3

継承によるいくつかの欠陥があるレガシーアプリケーションに取り組んでいますが、適切に解決するのに苦労しています。

現在、WinForms の構造は次のようになっています。

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

BaseForm 内に sth like と呼ばれるメソッドがありprotected virtual 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私の最初の考えは、たとえばのような魔法のプロパティをオブジェクト (eg FormConfiguration) にカプセル化し、BaseForm.

たとえば、そのようなもの

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

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

    protected virtual void InitializeMyStuff(FormConfigObject config)
    {}
}

ここでの問題は、ListForm の FormConfig オブジェクトには、たとえば、他のプロパティが必要ですが、派生クラスの署名を..のisntead にGridBindingSource変更することはできません。ListFormConfigObjectFormConfigObject

このジレンマから抜け出すための解決策を提案できる人はいますか?

// 編集: 実際に何が起こるかコードを整理し、コンストラクタ違反の仮想呼び出しを取り除きました。

4

1 に答える 1

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;
}

そして、サブクラスが抽象オブジェクトを介して必要な情報を提供するようになったため、基本クラスはそのタスクを続行できます。

このように情報をさまざまなオブジェクトに分割することは、リファクタリングの良い出発点です。より小さなオブジェクトを作成すると、テストと管理が容易になり、遭遇した混乱の根底にある構造が明らかになります。また、単一責任原則の違反の数を減らすのにも役立ちます。

于 2013-10-01T10:51:54.113 に答える