我正在开发一个由于继承而存在一些缺陷的遗留应用程序,但是我正在努力正确地解决它.
目前,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.