ビルダーモードのいくつかの使用シーン


1.シーン1
複雑なオブジェクトのコンストラクションをその表現から分離する必要がある場合、同じコンストラクションプロセスで異なる表現の意図を作成できるようにするには、Builderモードとジェネレータモードを使用します.Builderモードを使用すると、ユーザーは構築するタイプを指定するだけでそれらを得ることができ、具体的な構築の過程と詳細は知る必要はありません.例えば今、私たちはこのような使用シーンがあります.スクリーンに小人を描く必要があります.人は頭と手足を持って、違う人を描く必要があります.太った小人、やせた小人、低い小人です.通常の書き方では、多くのテンプレートコードがあり、人の頭を描き、人の足を描き、うっかりすると、腕が欠けやすく、足が少なくなります.Builderモードの実装について説明します.
public class Person {
    //    get set      
    Head head;
    Body body;
    Arm leftArm;
    Arm rightArm;
    Leg leftLeg;
    Leg rightLeg;
    
    public void drawHead(int size){...}
    public void drawBody(int size){...}
    public void drawLeftArm(int size){...}
    public void drawRightArm(int size){...}
    public void drawLeftLeg(int size){...}
    public void drawRightLeg(int size){...}
}

abstract class BuilderPerson {
    protected Person person = new Person();
    public abstract void buildHead();
    public abstract void buildBody();
    public abstract void buildLeftArm();
    public abstract void buildRightArm();
    public abstract void buildLeftLeg();
    public abstract void buildRightLeg();
}

public class BuilderThinPerson extends BuilderPerson{
    
    @Override
    public void buildHead() {
        person.drawHead(10);
    }
    
    @Override
    public void buildBody() {
        person.drawBody(10);   //              ,
                               //         
    }
    
    @Override
    public void buildLeftArm() {
        person.drawLeftArm(5);
    }
    
    @Override
    public void buildRightArm() {
        person.drawRightArm(5);
    }
    
    @Override
    public void buildLeftLeg() {
        person.drawLeftLeg(7);
    }
    
    @Override
    public void buildRightLeg() {
        person.drawRightLeg(7);
    }
}
    Builder           ,   (Director),         ,               。
public class PersonDirector{
    private BuilderPerson pb;
    public PersonDirector(BuilderPerson pb){
        this.pb = pb;
    }
    //             ,         
    public void createPerson() {
        pb.buildHead();
        pb.buildBody();
        pb.buildLeftArm();
        pb.buildRightArm();
        pb.buildLeftLeg();
        pb.buildRightLeg();
    }
}
     
BuilderPerson bp = new BuilderThinPerson();
PersonDirector pd = new PersonDirector(bp);
pd.createPerson();


2.シーン2
複数のコンストラクタパラメータに遭遇した場合は、コンストラクタを使用することを考慮します.静的ファクトリとコンストラクタには共通の限界がある:それらはすべて大量のオプションパラメータにうまく拡張できない.包装食品の外に表示される栄養成分ラベルをクラスで表すシーンを考える.これらのラベルには、1部当たりの含有量、1缶当たりの含有量、および1部当たりのカロリー、さらに20以上のオプション領域が必要です.総脂肪量、飽和脂肪量、転化脂肪、コレステロール、ナトリウムなどです.プログラマは、オーバーラップコンストラクタモードを採用することに慣れています.このモードでは、必要なパラメータだけが最初のコンストラクタを提供します.2番目のコンストラクタにはオプションパラメータがあり、3番目には2つのオプションパラメータがあります.このように、最後のコンストラクタにはすべてのオプションパラメータが含まれています.オーバーラップコンストラクタモードは可能ですが、多くのパラメータがある場合、クライアントコードの作成が難しく、読み取りが困難です.長い列のタイプが同じパラメータは、微妙なエラーを引き起こします.クライアントが2つのパラメータの順序を誤って逆転した場合、コンパイラでもエラーは発生しませんが、プログラムが実行されるとエラーが発生します.次はBuilderモードのコードです.
public class NutritionFacts {
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;
    
    public static class Builder {
        //required parameters
        private final int servingSize;
        private final int servings;
        
        //Optional parameters - initialized to default values
        private int calories;
        private int fat;
        private int sodium;
        private int carbohydrate;
        
        public Builder(int servingSize, int servings){
            this.servingSize = servingSize;
            this.servings = servings
        }
        
        public Builder calories(int val){
            calories = val;
            return this;
        }
        
        public Builder fat(int val){
            fat = val;
            return this;
        }
        
        public Builder sodium(int val) {
            sodium = val;
            return this;
        }
        
        public Builder carbohydrate(int val){
            carbohydrate = val;
            return this;
        }
        
        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }
    
    private NutritionFacts(Builder builder){
        servingSize = builder.servingSize;
        servings = builder.servings;
        calories = builder.calories;
        fat = builder.fat;
        sodium = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }
}

NutritionFactsは可変ではありません.builderのsetterメソッドはbuilder自体を返し、呼び出しをリンクできるようにします.クライアントコードは次のとおりです.
NutritionFacts juice = new NutritionFacts.Builder(240, 8).
    calories(100).sodium(35).carbohydrate(27).build();

このようなクライアントコードは書きやすく、さらに重要なのは、読みやすいことです.
参考:1.『大話デザインモード』2.『Effective Java第2版』