消除C#winforms中的继承“魔术”的最佳方法?

我正在开发一个由于继承而存在一些缺陷的遗留应用程序,但是我正在努力正确地解决它.

目前,WinForms的结构如下:

> BaseForm
> ListViewForm:BaseForm
> ListViewFormReadOnly:ListViewForm
> ListViewFormWithDetailForm:ListViewForm
> DetailForm:BaseForm
> ConcreteForm:ListViewFormWithDetailForm

BaseForm内部有一个方法,称为sth,就像受保护的虚拟void InitializeMyStuff()一样,该方法在继承的实例中将被覆盖.

例如

public class BaseForm {
    public BaseForm() {
       //.. do stuff

       //.. do other stuff like initialize DB connection or read app.config values and initialize properties..
}

public virtual void InitializeMyStuff() {
        throw new NotImplementedException();
    }
}

public class ListViewForm : BaseForm {
    protected BindingSource GridBindingSource { get; set; }

    public ListViewForm {
       //do special stuff like adding the grid and some buttons
    }
}
public class ConcreteForm : ListViewForm {
public override void InitializeMyStuff() {
        GridBindingSource = my_bindingSource;
        SomeOtherUsefulProperty = myValue;
        Foo = new Bar();
        // etc.
    }
}

//Usage:
var myForm = new ConcreteForm();
myForm.InitializeMyStuff();

可以想象,这会产生一些问题,例如:
-“此时必须设置什么才能使表单正常工作”
-“哪些东西可能尚未初始化?”
-“我可以使用哪些属性和方法调用”
以及有关该魔法黑匣子可能发生的事情的其他一些有趣的想法.

我如何重构它,以便更清楚地了解正在发生什么?请记住,这是一个具有约150或更多具体形式的项目.

我最初的想法是将诸如GridBindingSource之类的神奇属性封装到一个对象(例如FormConfiguration)中,并将其私有化为BaseForm.

例如这样的东西

public class BaseForm {
    private FormConfigObject _formConfig = new FormConfigObject();

    protected override void onl oad()
    {
        InitializeMyStuff(_formConfig);
    }

    protected virtual void InitializeMyStuff(FormConfigObject config)
    {}
}

我这里的问题是:ListForm的FormConfig对象必须具有其他属性,例如GridBindingSource,但我不能只是将派生类中的签名更改为FormConfigObject的ListFormConfigObject istead.

有人可以提出解决方案来摆脱这一困境吗?

//编辑:理顺代码以了解实际发生的情况,并摆脱构造函数冲突中的虚拟调用.

解决方法:

主要问题是这样的:BaseForm内是否存在任何对象:

>必须在BaseForm的构造函数中初始化
>取决于子类的具体实现

如果存在这样的对象,则可能应该使它们成为多态的,并从子类传递到BaseForm的构造函数中.

一个简单的示例,涉及许多可能的情况:

abstract class RandomPicture
{
    public RandomPicture()
    {
        shapes = new List<Shape>();
        InitializeRandomShapes();

        // do some initial drawing calculations
    }

    protected abstract void InitializeRandomShapes();

    protected List<Shape> shapes;
}

//... subclasses initialize the shapes

可以将其更改为:

abstract class RandomPicture
{
    public RandomPicture(AbstractShapeCollection shapeCollection)
    {
        shapes = shapeCollection;

        // do some initial drawing calculations
    }

    private AbstractShapeCollection shapes;
}

现在,子类通过抽象对象提供了所需的信息,因此基类可以继续执行其任务.

像这样将信息拆分为各种对象是一个很好的重构开始,因为您创建了更小的对象,这些对象更易于测试和管理以及揭示遇到的混乱的底层结构.它还有助于减少违规次数Single Responsibility Principle.

上一篇:C#-需要帮助修复Snake游戏中的错误


下一篇:c#-在运行时创建新设置,并在重新启动后读取