একটি জাভা নির্মাতা শ্রেণীর সাবক্লাসিং করা


133

দিন এই ড Dobbs নিবন্ধ এবং বিশেষ করে নির্মাতা প্যাটার্ন, কিভাবে আমরা একটি নির্মাতা subclassing ক্ষেত্রে হ্যান্ডেল করবেন? GMO লেবেলিং যুক্ত করতে আমরা সাবক্লাস করতে চাইলে উদাহরণটির একটি কাটা-ডাউন সংস্করণ গ্রহণ করা, একটি নিষ্পাপ বাস্তবায়ন হবে:

public class NutritionFacts {                                                                                                    

    private final int calories;                                                                                                  

    public static class Builder {                                                                                                
        private int calories = 0;                                                                                                

        public Builder() {}                                                                                                      

        public Builder calories(int val) { calories = val; return this; }                                                                                                                        

        public NutritionFacts build() { return new NutritionFacts(this); }                                                       
    }                                                                                                                            

    protected NutritionFacts(Builder builder) {                                                                                  
        calories = builder.calories;                                                                                             
    }                                                                                                                            
}

উপশ্রেণী:

public class GMOFacts extends NutritionFacts {                                                                                   

    private final boolean hasGMO;                                                                                                

    public static class Builder extends NutritionFacts.Builder {                                                                 

        private boolean hasGMO = false;                                                                                          

        public Builder() {}                                                                                                      

        public Builder GMO(boolean val) { hasGMO = val; return this; }                                                           

        public GMOFacts build() { return new GMOFacts(this); }                                                                   
    }                                                                                                                            

    protected GMOFacts(Builder builder) {                                                                                        
        super(builder);                                                                                                          
        hasGMO = builder.hasGMO;                                                                                                 
    }                                                                                                                            
}

এখন, আমরা এই জাতীয় কোড লিখতে পারি:

GMOFacts.Builder b = new GMOFacts.Builder();
b.GMO(true).calories(100);

তবে, আমরা যদি আদেশটি ভুলভাবে পেয়ে থাকি তবে এটি সমস্ত ব্যর্থ হয়:

GMOFacts.Builder b = new GMOFacts.Builder();
b.calories(100).GMO(true);

সমস্যাটি অবশ্যই NutritionFacts.Builderএকটি যা ফেরত দেয় , তাই NutritionFacts.Builderনা GMOFacts.Builder, তাই আমরা কীভাবে এই সমস্যাটি সমাধান করব, বা আরও ভাল প্যাটার্ন ব্যবহার করার আছে?

দ্রষ্টব্য: অনুরূপ প্রশ্নের এই উত্তরটি আমার উপরের ক্লাসগুলি সরবরাহ করে; আমার প্রশ্নটি বিল্ডার কলগুলি সঠিক ক্রমে রয়েছে তা নিশ্চিত করার সমস্যা সম্পর্কিত।


1
আমি মনে করি যে নীচের লিঙ্কটি একটি ভাল পদ্ধতির বর্ণনা দিয়েছে: egalluzzo.blogspot.co.at/2010/06/…
stuXnet

1
কিন্তু আপনি কিভাবে build()আউটপুট b.GMO(true).calories(100)?
শ্রীধর সারনোবাত

উত্তর:


170

আপনি জেনেরিকগুলি ব্যবহার করে এটি সমাধান করতে পারেন। আমি মনে করি একে "কৌতূহলীভাবে পুনরাবৃত্তি জেনেরিক নিদর্শন" বলা হয়

বেস শ্রেণীর বিল্ডার পদ্ধতিগুলির রিটার্নের ধরণেরটিকে জেনেরিক আর্গুমেন্ট করুন।

public class NutritionFacts {

    private final int calories;

    public static class Builder<T extends Builder<T>> {

        private int calories = 0;

        public Builder() {}

        public T calories(int val) {
            calories = val;
            return (T) this;
        }

        public NutritionFacts build() { return new NutritionFacts(this); }
    }

    protected NutritionFacts(Builder<?> builder) {
        calories = builder.calories;
    }
}

এখন জেনেরিক আর্গুমেন্ট হিসাবে উত্পন্ন শ্রেণি নির্মাতার সাথে বেস বিল্ডারকে ইনস্ট্যান্ট করুন।

public class GMOFacts extends NutritionFacts {

    private final boolean hasGMO;

    public static class Builder extends NutritionFacts.Builder<Builder> {

        private boolean hasGMO = false;

        public Builder() {}

        public Builder GMO(boolean val) {
            hasGMO = val;
            return this;
        }

        public GMOFacts build() { return new GMOFacts(this); }
    }

    protected GMOFacts(Builder builder) {
        super(builder);
        hasGMO = builder.hasGMO;
    }
}

2
হুম, আমি মনে করি আমাকে হয় (ক) একটি নতুন প্রশ্ন পোস্ট করতে হবে, (খ) এর implementsপরিবর্তে পুনরায় ডিজাইন করুন extends, বা (গ) সবকিছু ফেলে দিতে হবে। আমার এখন একটি অদ্ভুত সংকলন ত্রুটি আছে যেখানে leafBuilder.leaf().leaf()এবং leafBuilder.mid().leaf()ঠিক আছে, তবে leafBuilder.leaf().mid().leaf()ব্যর্থ ...
কেন ওয়াইএনএন

11
@gkamal return (T) this;একটি unchecked or unsafe operationsসতর্কতা ফলাফল । এড়ানো কি অসম্ভব, তাই না?
দিমিত্রি মিনকভস্কি

5
unchecked castসতর্কবার্তাটি সমাধান করার জন্য , সমাধানটি অন্য উত্তরের মধ্যে নমুনা
স্টেপান ভাভরা

8
দ্রষ্টব্য যে Builder<T extends Builder>আসলে একটি কাঁচা টাইপ - এটি হওয়া উচিত Builder<T extends Builder<T>>
বোরিস দ্য স্পাইডার

2
@ ব্যবহারকারী 2957378 এর Builderজন্য GMOFactsজেনেরিক হওয়াও প্রয়োজন Builder<B extends Builder<B>> extends NutritionFacts.Builder<Builder>- এবং এই ধরণটি প্রয়োজনীয় হিসাবে অনেকগুলি স্তরে অবিরত থাকতে পারে। আপনি যদি একটি জেনেরিক নির্মাতা ঘোষণা করেন তবে আপনি প্যাটার্নটি প্রসারিত করতে পারবেন না।
বোরিস স্পাইডার

44

শুধু রেকর্ডের জন্য, এ থেকে মুক্তি পেতে

unchecked or unsafe operations সাবধানবাণী

return (T) this;@dimadima এবং @ থমাস এন হিসাবে বক্তব্য রাখার জন্য নীচের সমাধানটি নির্দিষ্ট ক্ষেত্রে প্রযোজ্য।

abstractজেনেরিক প্রকার ( T extends Builderএই ক্ষেত্রে) ঘোষণা করে এমন নির্মাতা তৈরি করুন এবং protected abstract T getThis()বিমূর্ত পদ্ধতিটি নীচে ঘোষণা করুন :

public abstract static class Builder<T extends Builder<T>> {

    private int calories = 0;

    public Builder() {}

    /** The solution for the unchecked cast warning. */
    public abstract T getThis();

    public T calories(int val) {
        calories = val;

        // no cast needed
        return getThis();
    }

    public NutritionFacts build() { return new NutritionFacts(this); }
}

আরও তথ্যের জন্য http://www.angelikalanger.com / জেনারিক্স এফএকিউ / এফএকিউসেকশনস / প্রোগ্রামিং আইডিয়ামস html# FAQ205 দেখুন।


build()পদ্ধতিটি এখানে নিউট্রিশনফ্যাক্টগুলি ফিরিয়ে দিচ্ছে কেন ?
এমভিডি

@ এমভিডি কারণ এটি প্রশ্নের উত্তর? সাব টাইপগুলিতে আপনি এটিকে ওভাররাইড করবেন যেমনpublic GMOFacts build() { return new GMOFacts(this); }
স্টেপান ভাভরা

সমস্যাটি ঘটে যখন আমরা 2 য় শিশু যুক্ত করতে চাই BuilderC extends BuilderBএবং BuilderB extends BuilderAকখন BuilderBনাabstract
সসাইট

1
এটি প্রশ্নের উত্তর নয়, কারণ বেস ক্লাসটি বিমূর্ত নাও হতে পারে!
রোল্যান্ড

"বিমূর্তটি তৈরি করুন যা জেনেরিক ধরণের ঘোষণা করে" - আমি যদি সেই বিল্ডারকে সরাসরি ব্যবহার করতে চাইতাম তবে কী হবে?
ডেইজি

21

ব্লগ পোস্টের ভিত্তিতে , এই পদ্ধতির জন্য সমস্ত নন-পাতাগুলির ক্লাস বিমূর্ত হওয়া প্রয়োজন এবং সমস্ত পাতার শ্রেণি অবশ্যই চূড়ান্ত হতে হবে।

public abstract class TopLevel {
    protected int foo;
    protected TopLevel() {
    }
    protected static abstract class Builder
        <T extends TopLevel, B extends Builder<T, B>> {
        protected T object;
        protected B thisObject;
        protected abstract T createObject();
        protected abstract B thisObject();
        public Builder() {
            object = createObject();
            thisObject = thisObject();
        }
        public B foo(int foo) {
            object.foo = foo;
            return thisObject;
        }
        public T build() {
            return object;
        }
    }
}

তারপরে, আপনার কিছু মধ্যবর্তী শ্রেণি রয়েছে যা এই বর্গ এবং এর নির্মাতাকে প্রসারিত করে এবং আপনার আরও যতগুলি প্রয়োজন:

public abstract class SecondLevel extends TopLevel {
    protected int bar;
    protected static abstract class Builder
        <T extends SecondLevel, B extends Builder<T, B>> extends TopLevel.Builder<T, B> {
        public B bar(int bar) {
            object.bar = bar;
            return thisObject;
        }
    }
}

এবং, অবশেষে একটি কংক্রিট পাতার শ্রেণি যা তার যে কোনও পিতা-মাতার উপর বিল্ডার পদ্ধতিগুলিকে যে কোনও ক্রমে কল করতে পারে:

public final class LeafClass extends SecondLevel {
    private int baz;
    public static final class Builder extends SecondLevel.Builder<LeafClass,Builder> {
        protected LeafClass createObject() {
            return new LeafClass();
        }
        protected Builder thisObject() {
            return this;
        }
        public Builder baz(int baz) {
            object.baz = baz;
            return thisObject;
        }
    }
}

তারপরে, শ্রেণিবদ্ধের যে কোনও ক্লাস থেকে আপনি যে কোনও ক্রমে পদ্ধতিগুলি কল করতে পারেন:

public class Demo {
    LeafClass leaf = new LeafClass.Builder().baz(2).foo(1).bar(3).build();
}

আপনি কি জানেন কেন পাতার ক্লাসগুলি চূড়ান্ত হওয়া দরকার? আমি চাই আমার কংক্রিটের ক্লাসগুলি সাবক্লাসযোগ্য হতে পারে তবে সংকলকটির ধরণটি বোঝার কোনও উপায় খুঁজে পাইনি B, এটি সর্বদা বেস বর্গ হিসাবে দেখা যায়।
ডেভিড গ্যানস্টার

নোট করুন যে লিফক্লাসে বিল্ডার ক্লাস কীভাবে <T extends SomeClass, B extends SomeClass.Builder<T,B>> extends SomeClassParent.Builder<T,B>মধ্যস্থতাকারী দ্বিতীয় স্তরের শ্রেণীর মতো একই প্যাটার্নটি অনুসরণ করে না , পরিবর্তে এটি নির্দিষ্ট প্রকারের ঘোষণা করে। নির্দিষ্ট ধরণের ব্যবহার করে আপনি পাতায় না পৌঁছানো পর্যন্ত আপনি কোনও শ্রেণীর নির্দেশ দিতে পারবেন না, তবে একবার করার পরে আপনি এটিকে আর প্রসারিত করতে পারবেন না কারণ আপনি নির্দিষ্ট ধরণের ব্যবহার করছেন এবং কৌতূহলীভাবে পুনরাবৃত্তি টেম্পলেট প্যাটার্নটি পরিত্যাগ করেছেন। এই লিঙ্কটি সাহায্য করতে পারে: অ্যাঞ্জেলিক্যালঞ্জার
জেনারিক্স

7

আপনি সেই calories()পদ্ধতিটিও ওভাররাইড করতে পারেন এবং এটি প্রসারিত নির্মাতাকে ফেরত দিতে দিন। এটি সংকলিত হয়েছে কারণ জাভা কোভেরিয়েন্ট রিটার্নের ধরণগুলিকে সমর্থন করে ।

public class GMOFacts extends NutritionFacts {
    private final boolean hasGMO;
    public static class Builder extends NutritionFacts.Builder {
        private boolean hasGMO = false;
        public Builder() {
        }
        public Builder GMO(boolean val)
        { hasGMO = val; return this; }
        public Builder calories(int val)
        { super.calories(val); return this; }
        public GMOFacts build() {
            return new GMOFacts(this);
        }
    }
    [...]
}

আহ, আমি জানতাম না, যেহেতু আমি সি ++ ব্যাকগ্রাউন্ড থেকে এসেছি। এটি এই ছোট উদাহরণের জন্য একটি দরকারী পন্থা, তবে একটি সম্পূর্ণ বিকাশযুক্ত শ্রেণীর সমস্ত পদ্ধতি পুনরাবৃত্তি করা একটি ব্যথা হয়ে ওঠে এবং এতে ত্রুটি-প্রবণ ব্যথা হয়ে যায়। আমাকে নতুন কিছু শেখানোর জন্য +1!
কেন ওয়াইএন

আমার কাছে মনে হবে এটি কোনও কিছুই সমাধান করে না। পিতামাতাকে উপ-শ্রেণিবদ্ধ করার কারণ (আইএমও) হ'ল পিতা-মাতার পদ্ধতিগুলি ওভাররাইড না করে পুনরায় ব্যবহার করা। শ্রেণিগুলি যদি সাধারণ মূল্য নির্ধারণ ব্যতীত নির্মাতা পদ্ধতিগুলিতে সত্যিকারের যুক্তিবিহীন কোনও মূল্যমান অবজেক্ট হয় তবে ওভাররাইড পদ্ধতিতে পিতামাতার পদ্ধতিটি কল করার কোনও মূল্য নেই।
বিকাশকারী ডুড

উত্তরটি প্রশ্নের মধ্যে বর্ণিত সমস্যা সমাধান করে: বিল্ডার ব্যবহার করে কোড দুটি অর্ডার দিয়ে সংকলন করে। যেহেতু একটি উপায় সংকলন করে এবং অন্যটি না করে, আমি অনুমান করি যে সর্বোপরি কিছুটা মূল্য অবশ্যই হবে।
ফ্ল্যাভিও

3

Builderপ্যাটার্ন অনুসারে ক্লাস তৈরির আরও একটি উপায়ও রয়েছে, যা "উত্তরাধিকারের তুলনায় রচনা পছন্দ করে" forms

একটি ইন্টারফেস সংজ্ঞায়িত করুন, পিতামাত্ত শ্রেণীর Builderউত্তরাধিকারী হবে:

public interface FactsBuilder<T> {

    public T calories(int val);
}

বাস্তবায়ন NutritionFactsপ্রায় একই রকম ( Builder'ফ্যাক্টস বিল্ডার' ইন্টারফেস বাস্তবায়ন ব্যতীত ):

public class NutritionFacts {

    private final int calories;

    public static class Builder implements FactsBuilder<Builder> {
        private int calories = 0;

        public Builder() {
        }

        @Override
        public Builder calories(int val) {
            return this;
        }

        public NutritionFacts build() {
            return new NutritionFacts(this);
        }
    }

    protected NutritionFacts(Builder builder) {
        calories = builder.calories;
    }
}

Builderএকটি শিশু শ্রেণীর একই ইন্টারফেস (বিভিন্ন জেনেরিক বাস্তবায়ন ব্যতীত) প্রসারিত করা উচিত:

public static class Builder implements FactsBuilder<Builder> {
    NutritionFacts.Builder baseBuilder;

    private boolean hasGMO = false;

    public Builder() {
        baseBuilder = new NutritionFacts.Builder();
    }

    public Builder GMO(boolean val) {
        hasGMO = val;
        return this;
    }

    public GMOFacts build() {
        return new GMOFacts(this);
    }

    @Override
    public Builder calories(int val) {
        baseBuilder.calories(val);
        return this;
    }
}

লক্ষ্য করুন, এটি NutritionFacts.Builderভিতরে একটি ক্ষেত্র GMOFacts.Builder(বলা হয় baseBuilder)। FactsBuilderইন্টারফেস কলগুলির baseBuilderএকই নামের পদ্ধতি থেকে প্রয়োগ করা পদ্ধতি:

@Override
public Builder calories(int val) {
    baseBuilder.calories(val);
    return this;
}

এর কনস্ট্রাক্টরেও বড় পরিবর্তন রয়েছে GMOFacts(Builder builder)। কনস্ট্রাক্টরকে প্যারেন্ট ক্লাস কনস্ট্রাক্টরের প্রথম কলটি যথাযথভাবে পাস করা উচিত NutritionFacts.Builder:

protected GMOFacts(Builder builder) {
    super(builder.baseBuilder);
    hasGMO = builder.hasGMO;
}

GMOFactsশ্রেণীর সম্পূর্ণ বাস্তবায়ন :

public class GMOFacts extends NutritionFacts {

    private final boolean hasGMO;

    public static class Builder implements FactsBuilder<Builder> {
        NutritionFacts.Builder baseBuilder;

        private boolean hasGMO = false;

        public Builder() {
        }

        public Builder GMO(boolean val) {
            hasGMO = val;
            return this;
        }

        public GMOFacts build() {
            return new GMOFacts(this);
        }

        @Override
        public Builder calories(int val) {
            baseBuilder.calories(val);
            return this;
        }
    }

    protected GMOFacts(Builder builder) {
        super(builder.baseBuilder);
        hasGMO = builder.hasGMO;
    }
}

3

একাধিক বিল্ডারের উত্তরাধিকারের একটি সম্পূর্ণ 3 স্তরের উদাহরণটি দেখতে পাবেন :

(নির্মাতার জন্য একটি অনুলিপি নির্মাণকারী সহ সংস্করণের জন্য নীচের দ্বিতীয় উদাহরণটি দেখুন)

প্রথম স্তর - পিতামাতা (সম্ভাব্য বিমূর্ত)

import lombok.ToString;

@ToString
@SuppressWarnings("unchecked")
public abstract class Class1 {
    protected int f1;

    public static class Builder<C extends Class1, B extends Builder<C, B>> {
        C obj;

        protected Builder(C constructedObj) {
            this.obj = constructedObj;
        }

        B f1(int f1) {
            obj.f1 = f1;
            return (B)this;
        }

        C build() {
            return obj;
        }
    }
}

দ্বিতীয় স্তর

import lombok.ToString;

@ToString(callSuper=true)
@SuppressWarnings("unchecked")
public class Class2 extends Class1 {
    protected int f2;

    public static class Builder<C extends Class2, B extends Builder<C, B>> extends Class1.Builder<C, B> {
        public Builder() {
            this((C) new Class2());
        }

        protected Builder(C obj) {
            super(obj);
        }

        B f2(int f2) {
            obj.f2 = f2;
            return (B)this;
        }
    }
}

তৃতীয় স্তর

import lombok.ToString;

@ToString(callSuper=true)
@SuppressWarnings("unchecked")
public class Class3 extends Class2 {
    protected int f3;

    public static class Builder<C extends Class3, B extends Builder<C, B>> extends Class2.Builder<C, B> {
        public Builder() {
            this((C) new Class3());
        }

        protected Builder(C obj) {
            super(obj);
        }

        B f3(int f3) {
            obj.f3 = f3;
            return (B)this;
        }
    }
}

এবং ব্যবহারের একটি উদাহরণ

public class Test {
    public static void main(String[] args) {
        Class2 b1 = new Class2.Builder<>().f1(1).f2(2).build();
        System.out.println(b1);
        Class2 b2 = new Class2.Builder<>().f2(2).f1(1).build();
        System.out.println(b2);

        Class3 c1 = new Class3.Builder<>().f1(1).f2(2).f3(3).build();
        System.out.println(c1);
        Class3 c2 = new Class3.Builder<>().f3(3).f1(1).f2(2).build();
        System.out.println(c2);
        Class3 c3 = new Class3.Builder<>().f3(3).f2(2).f1(1).build();
        System.out.println(c3);
        Class3 c4 = new Class3.Builder<>().f2(2).f3(3).f1(1).build();
        System.out.println(c4);
    }
}


বিল্ডারের জন্য একটি অনুলিপি নির্মাণকারীর বৈশিষ্ট্যযুক্ত একটি দীর্ঘতর সংস্করণ:

প্রথম স্তর - পিতামাতা (সম্ভাব্য বিমূর্ত)

import lombok.ToString;

@ToString
@SuppressWarnings("unchecked")
public abstract class Class1 {
    protected int f1;

    public static class Builder<C extends Class1, B extends Builder<C, B>> {
        C obj;

        protected void setObj(C obj) {
            this.obj = obj;
        }

        protected void copy(C obj) {
            this.f1(obj.f1);
        }

        B f1(int f1) {
            obj.f1 = f1;
            return (B)this;
        }

        C build() {
            return obj;
        }
    }
}

দ্বিতীয় স্তর

import lombok.ToString;

@ToString(callSuper=true)
@SuppressWarnings("unchecked")
public class Class2 extends Class1 {
    protected int f2;

    public static class Builder<C extends Class2, B extends Builder<C, B>> extends Class1.Builder<C, B> {
        public Builder() {
            setObj((C) new Class2());
        }

        public Builder(C obj) {
            this();
            copy(obj);
        }

        @Override
        protected void copy(C obj) {
            super.copy(obj);
            this.f2(obj.f2);
        }

        B f2(int f2) {
            obj.f2 = f2;
            return (B)this;
        }
    }
}

তৃতীয় স্তর

import lombok.ToString;

@ToString(callSuper=true)
@SuppressWarnings("unchecked")
public class Class3 extends Class2 {
    protected int f3;

    public static class Builder<C extends Class3, B extends Builder<C, B>> extends Class2.Builder<C, B> {
        public Builder() {
            setObj((C) new Class3());
        }

        public Builder(C obj) {
            this();
            copy(obj);
        }

        @Override
        protected void copy(C obj) {
            super.copy(obj);
            this.f3(obj.f3);
        }

        B f3(int f3) {
            obj.f3 = f3;
            return (B)this;
        }
    }
}

এবং ব্যবহারের একটি উদাহরণ

public class Test {
    public static void main(String[] args) {
        Class3 c4 = new Class3.Builder<>().f2(2).f3(3).f1(1).build();
        System.out.println(c4);

        // Class3 builder copy
        Class3 c42 = new Class3.Builder<>(c4).f2(12).build();
        System.out.println(c42);
        Class3 c43 = new Class3.Builder<>(c42).f2(22).f1(11).build();
        System.out.println(c43);
        Class3 c44 = new Class3.Builder<>(c43).f3(13).f1(21).build();
        System.out.println(c44);
    }
}

2

আপনি যদি নিজের কৌনিক বন্ধনী বা তিনটির দিকে নজর দিতে চান না বা সম্ভবত নিজেকে অনুভব করেন না ... উম্মম ... মানে ... কাশি ... আপনার দলের বাকিরা দ্রুত কৌতূহল বোধ করবে পুনরাবৃত্তি জেনেরিক প্যাটার্ন, আপনি এটি করতে পারেন:

public class TestInheritanceBuilder {
  public static void main(String[] args) {
    SubType.Builder builder = new SubType.Builder();
    builder.withFoo("FOO").withBar("BAR").withBaz("BAZ");
    SubType st = builder.build();
    System.out.println(st.toString());
    builder.withFoo("BOOM!").withBar("not getting here").withBaz("or here");
  }
}

দ্বারা সমর্থিত

public class SubType extends ParentType {
  String baz;
  protected SubType() {}

  public static class Builder extends ParentType.Builder {
    private SubType object = new SubType();

    public Builder withBaz(String baz) {
      getObject().baz = baz;
      return this;
    }

    public Builder withBar(String bar) {
      super.withBar(bar);
      return this;
    }

    public Builder withFoo(String foo) {
      super.withFoo(foo);
      return this;
    }

    public SubType build() {
      // or clone or copy constructor if you want to stamp out multiple instances...
      SubType tmp = getObject();
      setObject(new SubType());
      return tmp;
    }

    protected SubType getObject() {
      return object;
    }

    private void setObject(SubType object) {
      this.object = object;
    }
  }

  public String toString() {
    return "SubType2{" +
        "baz='" + baz + '\'' +
        "} " + super.toString();
  }
}

এবং পিতামাতার ধরণ:

public class ParentType {
  String foo;
  String bar;

  protected ParentType() {}

  public static class Builder {
    private ParentType object = new ParentType();

    public ParentType object() {
      return getObject();
    }

    public Builder withFoo(String foo) {
      if (!"foo".equalsIgnoreCase(foo)) throw new IllegalArgumentException();
      getObject().foo = foo;
      return this;
    }

    public Builder withBar(String bar) {
      getObject().bar = bar;
      return this;
    }

    protected ParentType getObject() {
      return object;
    }

    private void setObject(ParentType object) {
      this.object = object;
    }

    public ParentType build() {
      // or clone or copy constructor if you want to stamp out multiple instances...
      ParentType tmp = getObject();
      setObject(new ParentType());
      return tmp;
    }
  }

  public String toString() {
    return "ParentType2{" +
        "foo='" + foo + '\'' +
        ", bar='" + bar + '\'' +
        '}';
  }
}

গুরুত্বপূর্ণ দিক:

  • বিল্ডারে অবজেক্টটি এমনভাবে সজ্জিত করে যাতে উত্তরাধিকার পিতামাতার ধরণের অবজেক্টে ক্ষেত্র স্থাপন করতে বাধা দেয়
  • সুপারটি নিশ্চিত করার জন্য কলগুলি সুপার টাইপ নির্মাতার পদ্ধতিগুলিতে যুক্তি (যদি থাকে তবে) উপ-প্রকারে বজায় থাকে।
  • ডাউন সাইড পিতামাত্ত শ্রেণিতে উত্সাহযুক্ত অবজেক্ট তৈরি (এস) ... তবে এটি পরিষ্কার করার জন্য নীচে দেখুন
  • উপরের দিকটি এক নজরে বোঝা আরও সহজ, এবং কোনও ভার্বোস নির্মাতা বৈশিষ্ট্য স্থানান্তর করে না।
  • যদি আপনার একাধিক থ্রেডগুলি আপনার বিল্ডার অবজেক্টগুলিতে অ্যাক্সেস করে থাকে ... আমার ধারণা আমি খুশী আমি আপনি নই :)।

সম্পাদনা করুন:

আমি উদাসীন বস্তু তৈরির চারপাশে একটি উপায় খুঁজে পেয়েছি। প্রথমে প্রতিটি বিল্ডারে এটি যুক্ত করুন:

private Class whoAmI() {
  return new Object(){}.getClass().getEnclosingMethod().getDeclaringClass();
}

তারপরে প্রতিটি নির্মাতার জন্য কনস্ট্রাক্টারে:

  if (whoAmI() == this.getClass()) {
    this.obj = new ObjectToBuild();
  }

new Object(){}বেনামি অভ্যন্তর শ্রেণীর জন্য ব্যয় একটি অতিরিক্ত শ্রেণীর ফাইল


1

আপনি যা করতে পারেন তা হ'ল আপনার প্রতিটি ক্লাসে একটি স্ট্যাটিক কারখানা পদ্ধতি তৈরি করা:

NutritionFacts.newBuilder()
GMOFacts.newBuilder()

এই স্থিতিশীল কারখানার পদ্ধতিটি যথাযথ নির্মাতাকে ফিরিয়ে দেবে। আপনার একটি GMOFacts.Builderএক্সটেন্ডিং এ থাকতে পারে NutritionFacts.Builder, এটি কোনও সমস্যা নয়। এখানে সমস্যাটি দৃশ্যমানতার সাথে মোকাবেলা করা ...


0

জাভাতে নিম্নলিখিত আইইইই অবদান রিফাইন্ড ফ্লুয়েন্ট বিল্ডার সমস্যার একটি ব্যাপক সমাধান দেয়।

এটি উত্তরাধিকারের ঘাটতি এবং পরিমাণের আগ্রাসনের দুটি উপ-সমস্যার মধ্যে মূল প্রশ্নটিকে বিচ্ছিন্ন করে এবং জাভাতে ধ্রুপদী নির্মাতা প্যাটার্নে কোডটি পুনরায় ব্যবহারের মাধ্যমে এই দুটি উপ-সমস্যার সমাধান কীভাবে উত্তরাধিকার সহায়তার জন্য খোলে তা দেখায়।


এই উত্তরটিতে সহায়ক হতে কোনও তথ্য নেই, লিঙ্কে দেওয়া উত্তরের কমপক্ষে একটি সংক্ষিপ্তসার নেই এবং লিংগের প্রয়োজন এমন একটি লিঙ্কে নিয়ে যায়।
সোনাটা

এই উত্তরটি একটি পিয়ার-পর্যালোচিত সম্মেলন প্রকাশনার সাথে একটি অফিসিয়াল প্রকাশনা কর্তৃপক্ষ এবং অফিসিয়াল প্রকাশনা এবং ভাগ করে নেওয়ার পদ্ধতির সাথে লিঙ্ক করে।
mc00x1

0

আমি একটি পিতামাতা, বিমূর্ত জেনেরিক বিল্ডার শ্রেণি তৈরি করেছি যা দুটি ফর্মাল টাইপের পরামিতি গ্রহণ করে। প্রথমটি বিল্ড () দ্বারা ফিরে আসা বস্তুর প্রকারের জন্য, দ্বিতীয়টি হ'ল প্রতিটি alচ্ছিক প্যারামিটার সেটার দ্বারা প্রত্যাবর্তিত প্রকার। উদাহরণস্বরূপ উদ্দেশ্যে নীচে পিতামাতার এবং শিশুদের ক্লাস রয়েছে:

// **Parent**
public abstract static class Builder<T, U extends Builder<T, U>> {
    // Required parameters
    private final String name;

    // Optional parameters
    private List<String> outputFields = null;


    public Builder(String pName) {
        name = pName;
    }

    public U outputFields(List<String> pOutFlds) {
        outputFields = new ArrayList<>(pOutFlds);
        return getThis();
    }


    /**
     * This helps avoid "unchecked warning", which would forces to cast to "T" in each of the optional
     * parameter setters..
     * @return
     */
    abstract U getThis();

    public abstract T build();



    /*
     * Getters
     */
    public String getName() {
        return name;
    }
}

 // **Child**
 public static class Builder extends AbstractRule.Builder<ContextAugmentingRule, ContextAugmentingRule.Builder> {
    // Required parameters
    private final Map<String, Object> nameValuePairsToAdd;

    // Optional parameters
    private String fooBar;


    Builder(String pName, Map<String, String> pNameValPairs) {
        super(pName);
        /**
         * Must do this, in case client code (I.e. JavaScript) is re-using
         * the passed in for multiple purposes. Doing {@link Collections#unmodifiableMap(Map)}
         * won't caught it, because the backing Map passed by client prior to wrapping in
         * unmodifiable Map can still be modified.
         */
        nameValuePairsToAdd = new HashMap<>(pNameValPairs);
    }

    public Builder fooBar(String pStr) {
        fooBar = pStr;
        return this;
    }


    @Override
    public ContextAugmentingRule build() {
        try {
            Rule r = new ContextAugmentingRule(this);
            storeInRuleByNameCache(r);
            return (ContextAugmentingRule) r;
        } catch (RuleException e) {
            throw new IllegalArgumentException(e);
        }
    }

    @Override
    Builder getThis() {
        return this;
    }
}

এই এক সন্তুষ্টি আমার চাহিদা পূরণ করেছেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.