Java(Fluent)Builderモードの継承

2975 ワード

Fluentスタイルのコードは非常に流行しており、Builderモードでもよく使われています.以下は簡単な例です.
public class FluentBuilder {
    private String param1;
    private String param2;
    
    public FluentBuilder setParam1(String param1){
        this.param1 = param1;
        return this;
    }
    
    public FluentBuilder setParam2(String param2){
        this.param2 = param2;
        return this;
    }
    
    public String build(){
        return param1 + param2;
    }
}


シンプルに使用できます.
        String result = new FluentBuilder()
            .setParam1("1")
            .setParam2("2")
            .build();

関連するオブジェクトを持つ構造では、builderコードを多重化する必要がある場合があります.この場合、いくつかの構文上の困難が発生します.
  • サブクラスBuilder:
  • public class SubFluentBuilder extends FluentBuilder {
        private String param3;
        
        public SubFluentBuilder setParam3(String param3){
            this.param3 = param3;
            return this;
        } 
    }
    
  • サブクラスメソッドを呼び出してから親メソッドを呼び出すと、問題はありません.
  •         String result = new SubFluentBuilder()
                    .setParam3("3")
                    .setParam1("1")
                    .setParam2("2")
                    .build();
    
  • 親メソッドが子より前の場合、子メソッドは表示されなくなります:
  •         String result = new SubFluentBuilder()
                    .setParam1("1")
                    .setParam2("2")
                    .setParam3("3")//    ,       
                    .build();
    
  • 原因はSubFluentBuilderにある.setParam 2()は、サブクラスメソッドを備えていないFluentBuilderを返します.

  • ここには2つのソリューションがあります
    1つ目は汎用型によってサブクラスタイプを取得し,thisを返して強制的にサブクラスに変換することである.この場合、サブクラス、親クラスにかかわらずサブクラスbuilderが返され、すべてのメソッドが使用できます.
    public class GenericBuilder> {
        private String param1;
        private String param2;
        
        public T setParam1(String param1){
            this.param1 = param1;
            return (T)this;
        }
        
        public T setParam2(String param2){
            this.param2 = param2;
            return (T)this;
        }
        
        public String build(){
            return param1 + param2;
        }
    }
    
    public class SubGenericBuilder extends GenericBuilder {
        private String param3;
        
        public SubGenericBuilder setParam3(String param3){
            this.param3 = param3;
            return this;
        } 
    }
    

    2つ目の方法は、すべての親メソッドを書き換えてサブクラスタイプを返すことです.JDKでStringBuilder/stringBufferはこのように実現されます.
    public class SubFluentBuilder2 extends FluentBuilder {
        private String param3;
        
        public SubFluentBuilder2 setParam1(String param1){
            super.setParam1(param1);
            return this;
        }
        
        public SubFluentBuilder2 setParam2(String param2){
            super.setParam2(param2);
            return this;
        }
        
        public SubFluentBuilder2 setParam3(String param3){
            this.param3 = param3;
            return this;
        }