7

ユーザーから提供されたマウスデータに基づいて幾何学的図形を描画する簡単なプログラムがあります。マウスの追跡を処理する 1 つのクラス (マウスの移動履歴を含むリストを取得します) と、Shape という抽象クラスが 1 つあります。このクラスから、Circle、Rectangle などの追加の Shape をいくつか派生させます。それらのすべてが抽象 Draw() 関数をオーバーライドします。

それはすべてうまく機能しますが、ユーザーが目的の形状を手動で切り替えられるようにしたい場合に問題が発生します。私はマウスデータを取得し、どのような形状を描くべきかを知っています. 問題は、どのオブジェクトを作成し、適切なパラメーターをコンストラクターに渡す必要があるかをコードに認識させる方法です。また、この時点で新しい Shape 派生物を追加することもできません。これは明らかに間違っています。

私は明らかに次のようなコードを出したくありません:

List<Shape> Shapes = new List<Shape>();
// somwhere later 

if(CurrentShape == "polyline"){
    Shapes.Add(new Polyline(Points)); 
}
else if (CurrentShape == "rectangle"){
    Shapes.Add(new Rectangle(BeginPoint, EndPoint));
}
// and so on.

上記のコードは、オープンクローズ原則に明らかに違反しています。問題は、それを乗り越える方法がよくわからないことです。主な問題は、さまざまな Shape にさまざまなパラメーターを持つコンストラクターがあり、これがさらに面倒なことです。

これはよくある問題だと確信していますが、それを乗り越える方法がわかりません。アイデアはありますか?

4

2 に答える 2

6

すべてが単一のクラスから派生するか、同じインターフェースを実装するオブジェクトを作成する必要がある場合、1 つの一般的なアプローチはfactoryを使用することです。ただし、ファクトリ自体は拡張可能である必要があるため、単純なファクトリでは不十分な場合があります。

それを実装する1つの方法は次のとおりです。

interface IShapeMaker {
    IShape Make(IList<Point> points);
}
class RectMaker : IShapeMaker {
    public Make(IList<Point> points) {
        // Check if the points are good to make a rectangle
        ...
        if (pointsAreGoodForRectangle) {
            return new Rectangle(...);
        }
        return null; // Cannot make a rectangle
    }
}
class PolylineMaker : IShapeMaker {
    public Make(IList<Point> points) {
        // Check if the points are good to make a polyline
        ...
        if (pointsAreGoodForPolyline) {
            return new Polyline(...);
        }
        return null; // Cannot make a polyline
    }
}

これらのMakerクラスが手元にあると、マーカーのレジストリ (単純なList<IShapeMaker>) を作成して、マーカーにポイントを渡し、null 以外の形状に戻ったときに停止することができます。

NewShapeとのペアを追加NewShapeMakerして、既存のフレームワークに「プラグイン」できるため、このシステムは引き続き拡張可能ですNewShapeMaker。レジストリに登録されると、システムの残りの部分はすぐに を認識して使用できるようになりますNewShape

于 2013-04-14T10:45:48.110 に答える