সম্পাদনা: আমি উল্লেখ করতে চাই যে এই প্রশ্নটি একটি তাত্ত্বিক সমস্যা বর্ণনা করে এবং আমি সচেতন যে বাধ্যতামূলক পরামিতিগুলির জন্য আমি কনস্ট্রাক্টর আর্গুমেন্টগুলি ব্যবহার করতে পারি, বা যদি এপিআই ভুলভাবে ব্যবহার করা হয় তবে রানটাইম ব্যতিক্রম ছুঁড়ে ফেলতে পারি। যাইহোক, আমি এমন একটি সমাধান খুঁজছি যার জন্য নির্মাণকারীর পক্ষে যুক্তি বা রানটাইম চেকিংয়ের প্রয়োজন হবে না ।
আপনার Car
মত একটি ইন্টারফেস আছে কল্পনা করুন :
public interface Car {
public Engine getEngine(); // required
public Transmission getTransmission(); // required
public Stereo getStereo(); // optional
}
মতামতগুলি যেমন পরামর্শ দেবে, একটি Car
অবশ্যই একটি Engine
এবং Transmission
তবে একটি Stereo
বিকল্প al মানে একটি নির্মাতা করতে পারে যে build()
একটি Car
উদাহরণ হিসেবে বলা যায় শুধুমাত্র কখনও একটি থাকতে হবে build()
একটি যদি পদ্ধতি Engine
এবং Transmission
আছে উভয় ইতিমধ্যে রচয়িতা উদাহরণস্বরূপ দেওয়া হয়েছে। এইভাবে প্রকারের পরীক্ষক কোনও কোড সংকলন করতে অস্বীকার করবেন যা Car
একটি Engine
বা ছাড়াই উদাহরণ তৈরি করার চেষ্টা করে Transmission
।
এটি একটি পদক্ষেপ নির্মাতার জন্য কল । সাধারণত আপনি এরকম কিছু বাস্তবায়ন করতেন:
public interface Car {
public Engine getEngine(); // required
public Transmission getTransmission(); // required
public Stereo getStereo(); // optional
public class Builder {
public BuilderWithEngine engine(Engine engine) {
return new BuilderWithEngine(engine);
}
}
public class BuilderWithEngine {
private Engine engine;
private BuilderWithEngine(Engine engine) {
this.engine = engine;
}
public BuilderWithEngine engine(Engine engine) {
this.engine = engine;
return this;
}
public CompleteBuilder transmission(Transmission transmission) {
return new CompleteBuilder(engine, transmission);
}
}
public class CompleteBuilder {
private Engine engine;
private Transmission transmission;
private Stereo stereo = null;
private CompleteBuilder(Engine engine, Transmission transmission) {
this.engine = engine;
this.transmission = transmission;
}
public CompleteBuilder engine(Engine engine) {
this.engine = engine;
return this;
}
public CompleteBuilder transmission(Transmission transmission) {
this.transmission = transmission;
return this;
}
public CompleteBuilder stereo(Stereo stereo) {
this.stereo = stereo;
return this;
}
public Car build() {
return new Car() {
@Override
public Engine getEngine() {
return engine;
}
@Override
public Transmission getTransmission() {
return transmission;
}
@Override
public Stereo getStereo() {
return stereo;
}
};
}
}
}
(বিভিন্ন রচয়িতা ক্লাস একটি চেইন এর Builder
, BuilderWithEngine
, CompleteBuilder
), যে অ্যাড এক প্রয়োজনীয় একের পর সেটার পদ্ধতি, পাশাপাশি সব ঐচ্ছিক সেটার পদ্ধতি ধারণকারী গত বর্গ সঙ্গে।
এর অর্থ এই পদক্ষেপ নির্মাতার ব্যবহারকারীরা সেই আদেশে সীমাবদ্ধ যা লেখক বাধ্যতামূলক সেটটারগুলি উপলব্ধ করেছিলেন । এখানে সম্ভাব্য ব্যবহারের একটি উদাহরণ দেওয়া আছে (নোট করুন যে সেগুলি সমস্ত কঠোরভাবে অর্ডার করা হয়েছে: engine(e)
প্রথমে, তারপরে অনুসরণ করা হবে transmission(t)
এবং শেষ পর্যন্ত alচ্ছিক stereo(s)
)।
new Builder().engine(e).transmission(t).build();
new Builder().engine(e).transmission(t).stereo(s).build();
new Builder().engine(e).engine(e).transmission(t).stereo(s).build();
new Builder().engine(e).transmission(t).engine(e).stereo(s).build();
new Builder().engine(e).transmission(t).stereo(s).engine(e).build();
new Builder().engine(e).transmission(t).transmission(t).stereo(s).build();
new Builder().engine(e).transmission(t).stereo(s).transmission(t).build();
new Builder().engine(e).transmission(t).stereo(s).stereo(s).build();
যাইহোক, প্রচুর পরিস্থিতি রয়েছে যেখানে এটি নির্মাতার ব্যবহারকারীর পক্ষে আদর্শ নয়, বিশেষত যদি নির্মাতা কেবল সেটারগুলিই রাখেন না, তবে সংযোজনকারীও হন, বা যদি ব্যবহারকারী ক্রমটি নিয়ন্ত্রণ করতে না পারেন যেখানে বিল্ডারের জন্য নির্দিষ্ট বৈশিষ্ট্য উপলব্ধ হবে।
আমি এর জন্য কেবলমাত্র সমাধানটিই ভাবতে পারি এটি অত্যন্ত সংশ্লেষযুক্ত: বাধ্যতামূলক সম্পত্তিগুলির প্রতিটি সমন্বয়ের জন্য সেট করা হয়েছে বা এখনও সেট করা হয়নি, আমি একটি ডেডিকেটেড বিল্ডার শ্রেণি তৈরি করেছি যা জানে যে কোন সম্ভাব্য অন্যান্য বাধ্যতামূলক সেটটারগুলিতে পৌঁছানোর আগে ডাকা দরকার knows রাষ্ট্র যেখানে build()
পদ্ধতিটি উপলব্ধ উচিত, এবং যারা setters প্রতিটি রচয়িতা একটি সম্পূর্ণ টাইপ যা এক ধাপ একটি ধারণকারী কাছাকাছি ফেরৎ build()
পদ্ধতি।
আমি নীচের কোডটি যুক্ত করেছি, তবে আপনি বলতে পারেন যে আমি টাইপ সিস্টেমটি একটি এফএসএম তৈরি করতে ব্যবহার করছি Builder
যা আপনাকে একটি তৈরি করতে দেয় যা উভয়কে একটি BuilderWithEngine
বা একটিতে পরিণত করা যেতে পারে BuilderWithTransmission
, যা উভয়ই পরে পরিণত হতে পারে CompleteBuilder
যা কার্যকর করেbuild()
পদ্ধতি। Buildচ্ছিক সেটটারগুলির মধ্যে এইগুলির মধ্যে যে কোনও একটিতে অনুরোধ করা যেতে পারে।
public interface Car {
public Engine getEngine(); // required
public Transmission getTransmission(); // required
public Stereo getStereo(); // optional
public class Builder extends OptionalBuilder {
public BuilderWithEngine engine(Engine engine) {
return new BuilderWithEngine(engine, stereo);
}
public BuilderWithTransmission transmission(Transmission transmission) {
return new BuilderWithTransmission(transmission, stereo);
}
@Override
public Builder stereo(Stereo stereo) {
super.stereo(stereo);
return this;
}
}
public class OptionalBuilder {
protected Stereo stereo = null;
private OptionalBuilder() {}
public OptionalBuilder stereo(Stereo stereo) {
this.stereo = stereo;
return this;
}
}
public class BuilderWithEngine extends OptionalBuilder {
private Engine engine;
private BuilderWithEngine(Engine engine, Stereo stereo) {
this.engine = engine;
this.stereo = stereo;
}
public CompleteBuilder transmission(Transmission transmission) {
return new CompleteBuilder(engine, transmission, stereo);
}
public BuilderWithEngine engine(Engine engine) {
this.engine = engine;
return this;
}
@Override
public BuilderWithEngine stereo(Stereo stereo) {
super.stereo(stereo);
return this;
}
}
public class BuilderWithTransmission extends OptionalBuilder {
private Transmission transmission;
private BuilderWithTransmission(Transmission transmission, Stereo stereo) {
this.transmission = transmission;
this.stereo = stereo;
}
public CompleteBuilder engine(Engine engine) {
return new CompleteBuilder(engine, transmission, stereo);
}
public BuilderWithTransmission transmission(Transmission transmission) {
this.transmission = transmission;
return this;
}
@Override
public BuilderWithTransmission stereo(Stereo stereo) {
super.stereo(stereo);
return this;
}
}
public class CompleteBuilder extends OptionalBuilder {
private Engine engine;
private Transmission transmission;
private CompleteBuilder(Engine engine, Transmission transmission, Stereo stereo) {
this.engine = engine;
this.transmission = transmission;
this.stereo = stereo;
}
public CompleteBuilder engine(Engine engine) {
this.engine = engine;
return this;
}
public CompleteBuilder transmission(Transmission transmission) {
this.transmission = transmission;
return this;
}
@Override
public CompleteBuilder stereo(Stereo stereo) {
super.stereo(stereo);
return this;
}
public Car build() {
return new Car() {
@Override
public Engine getEngine() {
return engine;
}
@Override
public Transmission getTransmission() {
return transmission;
}
@Override
public Stereo getStereo() {
return stereo;
}
};
}
}
}
আপনি বলতে পারেন যে এটি ভাল স্কেল করে না, কারণ প্রয়োজনীয় বিভিন্ন বিল্ডার শ্রেণীর সংখ্যা হবে ও (2 ^ n) যেখানে এন বাধ্যতামূলক সেটারের সংখ্যা।
সুতরাং আমার প্রশ্ন: এটি আরও মার্জিতভাবে করা যেতে পারে?
(আমি জাভা নিয়ে কাজ করে এমন একটি উত্তর খুঁজছি, যদিও স্কালাটি গ্রহণযোগ্য হবে)
.engine(e)
একজন নির্মাতার কাছে দু'বার প্রার্থনা করার অর্থ কী ?
build()
না করে engine(e)
এবং transmission(t)
আগে না ডাকলে এইভাবে আপনি কল করতে পারবেন না ।
Engine
বাস্তবায়ন দিয়ে শুরু করতে এবং পরে আরও নির্দিষ্ট প্রয়োগের মাধ্যমে এটি ওভাররাইট করতে পারেন। তবে সম্ভবত এটি engine(e)
সেটার না হয়ে একটি সংযোজনকারী না হলে এটি আরও অর্থবোধ করবে addEngine(e)
। এটি এমন এক Car
নির্মাতার পক্ষে কার্যকর হবে যা একাধিক ইঞ্জিন / মোটর সহ হাইব্রিড গাড়ি উত্পাদন করতে পারে। যেহেতু এটি একটি স্বীকৃত উদাহরণ, আমি কেন ব্রিফিংয়ের জন্য আপনি এটি করতে চাইতে পারেন সে সম্পর্কে বিশদ বিবরণে যাইনি।
this
?