2

Head First Design Patterns の本を読んでいて、第 4 章の「ファクトリ メソッドの宣言」セクションで、メソッドは保護されていると宣言されています。

public abstract class PizzaStore {

    public Pizza orderPizza(String type) {
        Pizza pizza;
        pizza = createPizza(type);
        pizza.prepare(); // other methods follow

        return pizza;
    }

    protected abstract Pizza createPizza(String type);

}

これは私を混乱させます。なぜなら、私は当初、ファクトリ (メソッド) を使用することでインスタンスを作成する単一の場所を持つことができると考えていたからです。 "。「行動する」とはpizza.cut()etc を意味し、「クエリを実行する」とは を意味しpizza.isSpicy()ます。

protectedキーワードは、クエリをサブクラスと同じパッケージ クラスのみに制限しませんか? サードパーティのクラスが注文前にピザが辛いことを知る必要があるとしたら?

ハイライトボックスにはそうあるべきだとは書かれていませんprotectedが、サンプルコードにはあります。

4

1 に答える 1

2

これは私を混乱させます。なぜなら、私は当初、ファクトリ (メソッド) を持つことでインスタンスを作成する単一の場所を持つことができると考えていたからです。 "

  • Pizzaが「作成」されるタイミングをクライアント (つまり、呼び出し元のコード) が制御できるようにする場合は、createPizzaメソッドを保護しません。これはパブリック メソッドであり、インスタンスへの参照を持つすべてのユーザーがPizzaStoreそれを呼び出すことができます。

  • そのクラスについて考えると、 のセマンティクスorderPizzaは明らかに異なりますcreatePizza。前者は呼び出し元がリソースを要求することを扱いますが、後者はそのリソースを取得することを扱います。これは、新しいリソースを作成するか、古いリソースを再利用するかです。

  • したがって、この場合、PizzaStoreクラスがピザが実際に「作成」されるタイミングを制御したいことは明らかであり、これがピザが保護されている理由です。(また、から継承するクラスもメソッドを実装できるため、それがプライベートである場合、それを実装するためにそれを見ることができませんでした。また、それは抽象的であるため、サブクラスPizzaStoreそれを実装する必要があることに注意してください)。そのため、作成プロセスは (Ananthu も言及したように)ストア内に安全にカプセル化されています。

a の実際の「作成」がPizza非常にコストのかかる操作であるとしましょう。それがいつ起こるかを誰にも決めてほしくありません。したがって、ファクトリ メソッドを保護しておくことで、PizzaStore(疑似コード、Java はわかりません) のような決定を下すことができます。

public abstract class PizzaStore {

    protected PizzaBin bin;

    //customer orders a pizza
    public Pizza orderPizza(String type) {
        //maybe we already have one...
        Pizza pizza = HeresOneWeMadeEarlier(type);
        if (pizza !=null) return pizza;
        //nope, we have none, so we have to make one.
        pizza = createPizza(type);
        pizza.prepare(); // other methods follow
        return pizza;
    }
    
    //customer returns a pizza
    public void ReturnPizza(Pizza pie) {
     if(!pie.HasAllSlices()){
       throw new CannotReturnPartiallyEatenPizzaException();
      }
     //hmm. maybe we can re-use this later on...
     bin.store(pie);        
    }
  
    //check if we have a pizza in the bin.
    protected Pizza HeresOneWeMadeEarlier(String type){
        if(bin.contains(type)){
          //we never said this was a *nice* pizza store!
            return bin.takeOutAndDustOff(type);
        }
        else{
          return null;
        }
    }

    protected abstract class Pizza createPizza(String type);

}

ピザを食べるにはあまり良い場所ではないかもしれませんが、私の言いたいことがわかるといいのですが:)

「操作する」とは、pizza.cut() などを意味し、「照会する」とは、pizza.isSpicy() を意味します。

これらは aPizzaではなく a のメソッドであるPizzaStoreため、ここでは実際には関与しないことに注意してください。呼び出し元に自分の が与えられると、 aが持つパブリック メソッド ( 、、など)Pizzaを呼び出すことができます。 ) そして、おそらくもう興味を持っていません。PizzaeatcutsharePizzaStore

それが役立つことを願っています。

アップデート

あなたが持っていた1つのポイントに対処するために:

サードパーティのクラスが注文前にピザが辛いことを知る必要があるとしたら?

その場合、PizzaStore材料またはオプションのリストと、それらが辛いかどうかを示すメソッドを設計します。

  • 次に、クライアントが (オプションのリストを指定して) ピザを注文すると、オプションのリストに基づいて、ピザが辛いかどうかが既にわかっています。
  • 別のクライアントは、注文番号を知っていれば、おそらく注文の詳細を調べることができます。これには、ピザがリクエストされたときに選択されたオプションが含まれており、ピザが辛いかどうかも判断できます。
于 2015-08-30T23:25:26.480 に答える