C# 面向对象设计之谜

C# 面向对象设计之谜,c#,oop,object-oriented-analysis,C#,Oop,Object Oriented Analysis,假设您有一个从其他类X继承的抽象基类A 类重写方法foo1 其他的A1、A2、A3类混凝土类很少 所有具体类都继承方法foo1 方法foo1几乎类似于一般算法,应该适用于所有具体类。 这几乎是因为算法中有一个异常,即存在一个if条件,一些类(比如说只有A1、A3)需要在foo的开始处打乱一些其他方法foo2 对于A2,我们不需要启动foo2 问题是,如果我在类A中实现foo2,那么它的所有子级也将继承此函数,这不是很好的设计吗 我曾想过将foo2排除在一个接口之外,该接口将由具体类->实现,但这

假设您有一个从其他类X继承的抽象基类A

类重写方法foo1

其他的A1、A2、A3类混凝土类很少

所有具体类都继承方法foo1

方法foo1几乎类似于一般算法,应该适用于所有具体类。 这几乎是因为算法中有一个异常,即存在一个if条件,一些类(比如说只有A1、A3)需要在foo的开始处打乱一些其他方法foo2

对于A2,我们不需要启动foo2

问题是,如果我在类A中实现foo2,那么它的所有子级也将继承此函数,这不是很好的设计吗

我曾想过将foo2排除在一个接口之外,该接口将由具体类->实现,但这并不好,因为调用foo2的foo1位于基类上

有没有办法用一种合适的方式解决这个问题


谢谢

在基类中创建一个属性,子类可以在需要调用foo2时设置该属性:

public class BaseClass {
    protected bool RunFoo2 { get; set; }

    public BaseClass() {
        // Not really needed, since booleans default to false
        RunFoo2 = false;
    }

    public virtual void foo1() {
        if (RunFoo2)
            foo2();
        // Default code here
    }

    public virtual void foo2() {
        // Whatever
    }
}

public class A : BaseClass {
    public A() : base() {
        RunFoo2 = true;
    }
}

在基类中创建一个属性,子类可以在需要调用foo2时设置该属性:

public class BaseClass {
    protected bool RunFoo2 { get; set; }

    public BaseClass() {
        // Not really needed, since booleans default to false
        RunFoo2 = false;
    }

    public virtual void foo1() {
        if (RunFoo2)
            foo2();
        // Default code here
    }

    public virtual void foo2() {
        // Whatever
    }
}

public class A : BaseClass {
    public A() : base() {
        RunFoo2 = true;
    }
}

您可以在子类中重写某种内部Foo1初始值设定项

public abstract class A {
    internal virtual void Foo1Init() {
        Console.WriteLine("Foo1Init");
    }

    public void Foo1() {
        Foo1Init();
        Console.WriteLine("Foo1");
    }
}

public class A1 : A {
    internal override void Foo1Init() {
        Console.WriteLine("A1 Foo1Init Override");
    }
}

public class A2 : A {

}

public class A3 : A {
    internal override void Foo1Init() {
        Console.WriteLine("A3 Foo1Init Override");
    }
}

class Program {
    static void Main(string[] args) {
        var a1 = new A1();
        a1.Foo1();

        var a2 = new A2();
        a2.Foo1();

        var a3 = new A3();
        a3.Foo1();

        Console.ReadKey();
    }
}
输出:


您可以在子类中重写某种内部Foo1初始值设定项

public abstract class A {
    internal virtual void Foo1Init() {
        Console.WriteLine("Foo1Init");
    }

    public void Foo1() {
        Foo1Init();
        Console.WriteLine("Foo1");
    }
}

public class A1 : A {
    internal override void Foo1Init() {
        Console.WriteLine("A1 Foo1Init Override");
    }
}

public class A2 : A {

}

public class A3 : A {
    internal override void Foo1Init() {
        Console.WriteLine("A3 Foo1Init Override");
    }
}

class Program {
    static void Main(string[] args) {
        var a1 = new A1();
        a1.Foo1();

        var a2 = new A2();
        a2.Foo1();

        var a3 = new A3();
        a3.Foo1();

        Console.ReadKey();
    }
}
输出:


在这种情况下,我将使用的解决方案是生成另一层抽象类,而需要特殊Foo2的类则从中派生

abstract class A : X
{
    public virtual void Foo()
    {
        //Foo logic
    }
}

abstract class B : A
{
    protected virtual void Foo2()
    {
        //Foo2
    }

    override void Foo()
    {
        Foo2();
        base.Foo();
    }
}

public A1 : B
{
}

public A2 : A
{
}

public A3 : B
{
}

在这种情况下,我将使用的解决方案是生成另一层抽象类,而需要特殊Foo2的类则从中派生

abstract class A : X
{
    public virtual void Foo()
    {
        //Foo logic
    }
}

abstract class B : A
{
    protected virtual void Foo2()
    {
        //Foo2
    }

    override void Foo()
    {
        Foo2();
        base.Foo();
    }
}

public A1 : B
{
}

public A2 : A
{
}

public A3 : B
{
}

您可以在中将foo2设置为私有,并添加一个受保护的虚拟属性,子类可以覆盖该虚拟属性,并且A使用该虚拟属性来确定子类是否要在foo1的开头调用foo2。我想我理解并看到了一个解决方案,但我认为,如果您在问题中添加一些过于简单的代码,比如抽象类MyShape,那就更好了{….我不确定我是否遵循了,但这将有助于您在中使foo2私有化,并改为添加一个受保护的虚拟属性,子类可以覆盖该虚拟属性,并且A使用该虚拟属性来确定子类是否要在foo1的开头调用foo2。我想我理解并看到了一个解决方案,但我认为如果您添加一些simp会更好问题的列表代码ala抽象类MyShape{…..我不确定我是否遵循,但这将有助于您根据具体需要将foo2设置为私有、非虚拟或两者兼而有之。根据具体需要,您也可以将foo2设置为私有、非虚拟或两者兼而有之。此实现的唯一缺点是它添加了另一个具有特殊性的基类n从类名上看,这可能不明显。@lukegravitt在现实世界中,我希望有更多的描述性名称,如X=Shape、A=Polygon、B=Quadralateral、A1=parallelgoma、A2=Triangle和A3=梯形。此实现的唯一缺点是它添加了另一个基类,与其他基类的区别可能不明显类名。@lukegravitt在现实世界中,我希望有更多的描述性名称,如X=形状、A=多边形、B=四边形、A1=平行四边形、A2=三角形和A3=梯形