2

OO にはかなり慣れていないので、単純化された例から与えられた実際の要件に移行しようとするまでは、概念を理解していると感じることがよくあります。この特定の問題について考える方法を理解する助けをいただければ幸いです。

コンテナとそれに入るアイテムを定義するパネルを持つ GUI があります。現在、コンテナには 3 つのタイプがあります。コンテナーにはいくつかのプロパティ (サイズなど) があり、1 ~ 3 種類のアイテムを含めることができます (2 つはオプション)。十分な情報が入力されたら、その情報を使用してグラフを作成します。

Observer パターンを実装しました。ユーザーが情報を入力すると、observable が更新され、変更されたことをグラフに通知します。

私は今のところ幸せです。今、しわ。私のコンテナにはサイズがありますが、明示的に入力されることもあれば、コンテナが保持しているものによって決定されることもあります。それはコンテナの種類によって決まります。明示的に入力されていない場合、サイズの決定方法は、オプションの項目の 1 つがコンテナー内にあるかどうかによって異なります。要件作成者が私を嫌っているだけなのか、それとも十分なオブジェクト指向の経験が不足しているのかはわかりませんが、それらのしわが私にフィットしています。現在、オブザーバブルには、さまざまな情報をすべて保持するための変数があり、特殊なケースを処理するために一連の switch ステートメントを使用しています。

ビルダーパターンを使用できると考えています。ディレクターは、グラフ化されたデータを作成します。コンテナーの種類ごとに具体的なビルダーを用意し、コンテナーのプロパティとその中の項目を使用してクラスをインスタンス化します。getContainerSize() など、グラフに必要な値をディレクタに返し、これらを組み合わせて実際のデータ ポイントを生成する抽象ビルダー クラスのメソッドを用意します。また、ユーザーがまだグラフを完成させるのに十分なデータを入力していない場合、director は null を返す可能性があります。

使用可能な OO 設計に近づいていますか? 特別なケーシングをもう少し深く埋めただけではないかどうかはわかりません.

シワがもう一つ。アイテム タイプの 1 つは、3 つのコンテナすべてに入っています。現在、私のオブザーバブルはコンテナーとアイテムを別々に追跡し、グラフを作成するメソッドが何を求めるかを決定します (ユーザーが値をいじると、グラフは大きく変化します)。複数のビルダー パターンがある場合、どのように機能しますか?

多分私はステップを逃していますか?オブザーバブルは現在のコンテナのビルダーを更新し、その座標を取得するためにディレクターを呼び出す必要があることをグラフに知らせますか? 次に、現在のコンテナが何であるかを尋ねる必要があるのはどれですか?

オブジェクト指向の設計や特にこの問題について理解するのに役立つすべてのコメントを歓迎します。実際の要件にはさらに特殊なケースがありますが、この基本的なテーマのバリエーションです。

返信ありがとうございます。私は、2 つの質問を混ぜ合わせて罪を犯していると思います。ここでは、Builder パターンに焦点を当てた最小限のコード例を提供しようとしています。IE8 に注意してください。FireFox 8 ではありません。IE8 でコードを読んでいる人には申し訳ありません。

interface MyContainerBuilder
{
     void   setContents( MyContents contents );

     Double myVolume();
     Double myDensity();   
}

class SmallContainerBuilder implements MyContainerBuilder
{
    Double     volume   = null;
    Double     density  = null;
    MyContents contents = null;

    public void   setVolume()
    {
        if (contents != null)
        {
            volume = contents.myDensity() / 3.0;
        }
    }

    public void   setContents( MyContents contents )
    {
        this.contents = contents;
    }

    public Double myVolume()
    {
        if (volume == null)
            setVolume();
        return volume;
    }

    public Double myDensity()   
    {
        return contents.myDensity();
    }
}

class BigContainerBuilder implements MyContainerBuilder
{
    Double     volume   = null;
    Double     density  = null;
    MyContents contents = null;

    public void   setVolume( Double volume )
    {
        this.volume = volume;
    }

    public void   setContents( MyContents contents )
    {
        this.contents = contents;
    }

    public Double myVolume()
    {
        return volume;
    }

    public Double myDensity()   
    {
        return contents.myDensity();
    }
}

class ContainerDirector
{
    Double myResult( MyContainerBuilder container )
    {
        return container.myVolume() * container.myDensity();
    }
}

class MyContents
{
    Double density;

    MyContents( Double density )
    {
        this.density = density;
    }

    public Double myDensity()
    {
        return density;
    }
}

class Test
{
    public static void main(String[] args)
    {
        SmallContainerBuilder smallContainer = new SmallContainerBuilder();
        BigContainerBuilder   bigContainer   = new BigContainerBuilder();
        ContainerDirector     director       = new ContainerDirector();
//
// Assume this comes from the GUI, where an ActionListener knows which Builder
// to use based on the user's action. I'd be having my observable store this.
       Double        density       = 15.0;
       MyContents    contents      = new MyContents( density );
       smallContainer.setContents( contents );
//
// Then I would need to tell my observer to do this.
        Double       results       = director.myResult( smallContainer );
        System.out.println( "Use this result: " + results );
    }
}

容量の計算に異なる方法を使用する 2 種類のコンテナーがあります。コンテナの種類を選択するためのラジオボタンがあり、各ラジオボタンの下に、選択したコンテナに入れることができる項目のコンボボックスがあるとします。コンボボックスの ActionListener は、アイテムを適切なコンテナーに配置し、それをオブザーバブルに保存します (実際に設定されるものは他にもたくさんあります)。オブザーバーにディレクターを使用して適切な値を取得し、オブザーバーが更新するように指示します。 GUI の一部のビュー コンポーネント。

4

1 に答える 1

2

私のコンテナにはサイズがありますが、明示的に入力されることもあれば、コンテナが保持しているものによって決定されることもあります。それはコンテナのタイプによって決まります。[...] 明示的に入力されていない場合は、オプションのアイテムの 1 つがコンテナー内にあるかどうかによって異なります。

抽象コンテナのさまざまなサブクラスがあり、それぞれgetContainerSize()が異なる方法で実装されているように思えます。1 つは明示的に入力する場合、1 つはオプション項目がある場合、もう 1 つはそれがない場合です。

...そして、特殊なケースを処理するために一連のswitchステートメントを使用します。

よく聞こえません。該当する場合は、 Conditional を Polymorphism に置き換えます。

ビルダーパターンを使用できると考えています...

null入力変数のセットに基づいて、オブジェクト (または ) の具体的なタイプを決定する必要があると仮定します。このパターンは、複雑なオブジェクトの型がわかっている場合に構築する方法を提供しますが、実際の問題は型を決定することです。したがって、どこかで条件付きコードが必要です。その場所はビルダーになることもできますが、単純な工場になることもあります。

現在、オブザーバブルはコンテナーとアイテムを別々に追跡します[...] オブザーバブルは現在のコンテナーのビルダーを更新します[...] 複数のビルダーパターンがある場合、それはどのように機能しますか?

その Observable が何を監視しているのか、どのような変更がどのような場合に何をトリガーしているのかを実際には理解していませんが、Observable がビルダー (または複数) を更新するのは奇妙に聞こえます。しかし、それはより直感的なものです:)

使用可能な OO 設計に近づいていますか?

それが機能する場合は、はい。しかし、あなたのテキストを何度か読んだ後でも、あなたの問題やデザインの詳細をまだ知らないので、あなたが良いデザインや使いやすいデザインを作成したかどうかは実際にはわかりません.

質問にもう 1 ページの情報を追加するのではなく、問題を小さな断片に分割し、コード スニペット、画像、グラフ、またはあらゆる種類の視覚化を使用して、人々が問題とそれらの断片間のすべてのつながりを理解できるようにします。大量のテキストだけではかなり恐ろしく、そのような巨大な OO 設計は全体として大きすぎ、SO にはローカライズされすぎています。


あなたのアプローチは問題ないようですが、その使用を正当化するには、IMO の非常に複雑なオブジェクトが必要です。

オブザーバーを介して GUI で MyContents インスタンスを作成します。次に、そのオブジェクトは MyContainerBuilder にラップされ、ContainerDirector に渡されて結果が生成されます。私の意見では、MyContents または結果が単純な場合、これは 1 歩多すぎます。

また、MyContents を MyContainerBuilder に設定する方法は、同じ具体的な MyContainerBuilder インスタンスをやみくもに再利用できないことを意味します。順番に使用するか、毎回新しいものを作成する必要があります。

つまり、これは機能しません

MyContents content1 = new MyContents( 5 );
MyContents content2 = new MyContents( 6 );
smallContainer.setContents( content1 );
smallContainer.setContents( content2 ); // overwriting old state
Double results1 = director.myResult( smallContainer ); // wrong result
Double results2 = director.myResult( smallContainer );

MyContents は、ユーザーがいくつかの手順でデータを入力する汎用データ保持オブジェクトであると想定しています。ユーザーが満足すると、結果に組み込まれるために送信されます。私が知る限り、あなたはその時点で結果がどうなるかを知っています.

以下は、戦略パターン(? - これらすべての名前と小さな違いが苦手です) を使用したアプローチです。これを MyContents に直接プラグインすることを選択したため、ファイナライズされた MyContents オブジェクトには、結果に変換する方法のすべての詳細が含まれます。 . そうすれば、1 つのステップが安全になり、追加のビルダー オブジェクトを作成/維持する必要がなくなります。MyContents は、ある意味ではすでに Builder です。

interface VolumeStrategy {
     Double calculateVolume(Double density);
}
class SmallVolumeStrategy implements VolumeStrategy {
    public Double calculateVolume(Double density) {
        return density / 3.0;
    }
}
class BigVolumeStrategy implements VolumeStrategy {
    public Double calculateVolume(Double density) {
        return density;
    }
}

class ContainerDirector {
    Double myResult( MyContents container ) {
        Double density = container.myDensity();
        VolumeStrategy strategy = container.myStrategy();
        return density * strategy.calculateVolume(density);
    }
}

class MyContents {
    // built via observer
    Double density;
    MyContents( Double density ) {
        this.density = density;
    }
    public Double myDensity() {
        return density;
    }

    // plugged in at the end.
    VolumeStrategy strategy;
    public void setStrategy(VolumeStrategy strategy) {
        this.strategy = strategy;
    }
    public VolumeStrategy myStrategy() {
        return strategy;
    }
}

public class Test {
    public static void main(String[] args) {
        // all those can be static 
        VolumeStrategy       smallStrategy  = new SmallVolumeStrategy();
        VolumeStrategy       bigStratetgy   = new BigVolumeStrategy();
        ContainerDirector    director       = new ContainerDirector();

       // from the GUI
       Double        density       = 15.0;
       MyContents    contents      = new MyContents( density );
       // building this contents ...
       // ... time to submit, we know what strategy to use
       contents.setStrategy(smallStrategy);

       // can turn contents into result without needing to know anything about it.
        Double       results       = director.myResult( contents );
        System.out.println( "Use this result: " + results );
    }
}

それは、あなたが抱えていると私が想像する問題に対してうまくいくと私が思う方法です。私はタフに間違っている可能性があります。

于 2012-11-20T01:21:00.450 に答える