在C#winforms中消除继承“魔力”的最佳方法是什么?

时间:2013-10-01 10:41:25

标签: c# .net winforms design-patterns inheritance

我正在研究遗留应用程序,因为继承存在一些缺陷,但我正在努力解决它。

目前,WinForms的结构如下所示:

  • BaseForm
  • ListViewForm : BaseForm
  • ListViewFormReadOnly : ListViewForm
  • ListViewFormWithDetailForm : ListViewForm
  • DetailForm : BaseForm
  • ConcreteForm : ListViewFormWithDetailForm

BaseForm中有一个方法,就像protected virtual void InitializeMyStuff()一样,在继承的实例中被覆盖。

e.g。

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中将其设为私有。

e.g。类似的东西

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

    protected override void OnLoad()
    {
        InitializeMyStuff(_formConfig);
    }

    protected virtual void InitializeMyStuff(FormConfigObject config)
    {}
}

我遇到的问题是:ListForm的FormConfig对象必须具有其他属性,例如GridBindingSource,但我不能只将派生类中的签名更改为{{1} }而不是ListFormConfigObject ..

任何人都可以建议摆脱这种困境的可能解决方案吗?

//编辑:将代码直接输出到实际发生的情况并在构造函数违规中删除虚拟调用。

1 个答案:

答案 0 :(得分:3)

主要问题是: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的行为。