รูปแบบการออกแบบของ Builder และรูปแบบการออกแบบของโรงงานแตกต่างกันอย่างไร
ข้อใดที่ได้เปรียบกว่าและทำไม
ฉันจะแสดงสิ่งที่ค้นพบของฉันเป็นกราฟได้อย่างไรหากฉันต้องการทดสอบและเปรียบเทียบ / เปรียบต่างรูปแบบเหล่านี้
รูปแบบการออกแบบของ Builder และรูปแบบการออกแบบของโรงงานแตกต่างกันอย่างไร
ข้อใดที่ได้เปรียบกว่าและทำไม
ฉันจะแสดงสิ่งที่ค้นพบของฉันเป็นกราฟได้อย่างไรหากฉันต้องการทดสอบและเปรียบเทียบ / เปรียบต่างรูปแบบเหล่านี้
คำตอบ:
ด้วยรูปแบบการออกแบบมักจะไม่มีทางออกที่ "ได้เปรียบกว่า" ที่ใช้ได้กับทุกกรณี ขึ้นอยู่กับสิ่งที่คุณต้องนำไปใช้
จาก Wikipedia:
- ตัวสร้างเน้นการสร้างวัตถุที่มีความซับซ้อนทีละขั้นตอน บทคัดย่อโรงงานเน้นกลุ่มผลิตภัณฑ์วัตถุ (อย่างง่ายหรือซับซ้อน) บิลเดอร์ส่งคืนผลิตภัณฑ์เป็นขั้นตอนสุดท้าย แต่เท่าที่เกี่ยวข้องกับ Abstract Factory ผลิตภัณฑ์จะถูกส่งคืนทันที
- ตัวสร้างมักจะสร้างคอมโพสิต
- บ่อยครั้งที่การออกแบบเริ่มต้นโดยใช้วิธีการของโรงงาน (ซับซ้อนน้อยลงปรับแต่งได้มากขึ้น subclasses เพิ่มขึ้น) และพัฒนาไปสู่ Abstract Factory, Prototype หรือ Builder (ยืดหยุ่นมากขึ้นซับซ้อนมากขึ้น) ตามที่นักออกแบบพบว่าต้องการความยืดหยุ่นมากขึ้น
- บางครั้งรูปแบบการสร้างจะเสริม: ตัวสร้างสามารถใช้หนึ่งในรูปแบบอื่น ๆ เพื่อใช้ส่วนประกอบที่สร้าง Abstract Factory, Builder และ Prototype สามารถใช้ Singleton ในการนำไปใช้งานได้
รายการ Wikipedia สำหรับรูปแบบการออกแบบจากโรงงาน: http://en.wikipedia.org/wiki/Factory_method_pattern
รายการ Wikipedia สำหรับรูปแบบการออกแบบตัวสร้าง: http://en.wikipedia.org/wiki/Builder_pattern
โรงงานเป็นเพียงฟังก์ชั่นคลุมรอบตัวสร้าง (อาจเป็นหนึ่งในคลาสที่แตกต่างกัน) ความแตกต่างที่สำคัญคือรูปแบบวิธีการจากโรงงานต้องการให้วัตถุทั้งหมดถูกสร้างขึ้นในการเรียกใช้วิธีการเดียวโดยมีพารามิเตอร์ทั้งหมดส่งผ่านในบรรทัดเดียว วัตถุสุดท้ายจะถูกส่งกลับ
ในทางกลับกันรูปแบบของตัวสร้างจะมีวัตถุห่อหุ้มอยู่รอบตัวพารามิเตอร์ทั้งหมดที่เป็นไปได้ที่คุณอาจต้องการส่งผ่านไปยังการเรียกใช้คอนสตรัคเตอร์ สิ่งนี้อนุญาตให้คุณใช้เมธอด setter เพื่อสร้างรายการพารามิเตอร์ของคุณอย่างช้าๆ วิธีการเพิ่มเติมหนึ่งอย่างในคลาส builder คือเมธอด build () ซึ่งเพียงแค่ส่งอ็อบเจ็กต์ builder ไปยังตัวสร้างที่ต้องการและส่งคืนผลลัพธ์
ในภาษาแบบคงที่เช่น Java สิ่งนี้จะมีความสำคัญมากขึ้นเมื่อคุณมีมากกว่าหนึ่งพารามิเตอร์ (อาจเป็นทางเลือก) เนื่องจากหลีกเลี่ยงข้อกำหนดที่จะมีตัวสร้างแบบ telescopic สำหรับพารามิเตอร์ที่เป็นไปได้ทั้งหมด ตัวสร้างยังช่วยให้คุณใช้เมธอด setter เพื่อกำหนดฟิลด์แบบอ่านอย่างเดียวหรือส่วนบุคคลที่ไม่สามารถแก้ไขได้โดยตรงหลังจากตัวสร้างถูกเรียก
ตัวอย่างโรงงานพื้นฐาน
// Factory
static class FruitFactory {
static Fruit create(name, color, firmness) {
// Additional logic
return new Fruit(name, color, firmness);
}
}
// Usage
Fruit fruit = FruitFactory.create("apple", "red", "crunchy");
ตัวอย่างเครื่องมือสร้างพื้นฐาน
// Builder
class FruitBuilder {
String name, color, firmness;
FruitBuilder setName(name) { this.name = name; return this; }
FruitBuilder setColor(color) { this.color = color; return this; }
FruitBuilder setFirmness(firmness) { this.firmness = firmness; return this; }
Fruit build() {
return new Fruit(this); // Pass in the builder
}
}
// Usage
Fruit fruit = new FruitBuilder()
.setName("apple")
.setColor("red")
.setFirmness("crunchy")
.build();
มันอาจจะคุ้มค่าที่จะเปรียบเทียบตัวอย่างโค้ดจากหน้าวิกิพีเดียสองหน้านี้:
http://en.wikipedia.org/wiki/Factory_method_pattern
http://en.wikipedia.org/wiki/Builder_pattern
รูปแบบของ Factory สามารถมองเห็นได้ในรูปแบบของ Builder รูปแบบที่เรียบง่าย
ในโรงงานรูปแบบโรงงานอยู่ในความดูแลของการสร้างชนิดย่อยต่างๆของวัตถุขึ้นอยู่กับความต้องการของ
ผู้ใช้วิธีการจากโรงงานไม่จำเป็นต้องรู้ชนิดย่อยที่แน่นอนของวัตถุนั้น ตัวอย่างของวิธีการจากโรงงานcreateCar
อาจส่งคืนFord
หรือHonda
วัตถุที่พิมพ์
ในรูปแบบตัวสร้างชนิดย่อยที่แตกต่างกันจะถูกสร้างขึ้นโดยวิธีการสร้าง แต่องค์ประกอบของวัตถุอาจแตกต่างกันภายในคลาสย่อยเดียวกัน
เพื่อดำเนินการต่อตัวอย่างรถยนต์คุณอาจมีcreateCar
วิธีการสร้างซึ่งสร้างHonda
วัตถุ -typed ด้วย 4 cylinder engine หรือHonda
วัตถุ -typed 6 cylinder รูปแบบการสร้างช่วยให้สำหรับความละเอียดปลีกย่อยนี้
ไดอะแกรมของทั้งรูปแบบตัวสร้างและรูปแบบวิธีการของโรงงานมีอยู่ใน Wikipedia
รูปแบบการออกแบบตัวสร้างอธิบายถึงวัตถุที่รู้วิธีการสร้างวัตถุอื่นที่มีประเภทเฉพาะในหลายขั้นตอน มันถือสถานะที่จำเป็นสำหรับรายการเป้าหมายในแต่ละขั้นตอนกลาง คิดว่า StringBuilder ดำเนินการอย่างไรเพื่อสร้างสตริงสุดท้าย
รูปแบบการออกแบบจากโรงงานอธิบายถึงวัตถุที่รู้วิธีสร้างวัตถุที่แตกต่างกัน แต่มีความเกี่ยวข้องในขั้นตอนเดียวโดยเลือกประเภทเฉพาะตามพารามิเตอร์ที่กำหนด คิดว่าระบบการทำให้เป็นอันดับซึ่งคุณสร้าง serializer ของคุณและมันสร้างความต้องการในวัตถุทั้งหมดในการเรียกโหลดเดียว
การสร้างวัตถุที่ซับซ้อนทีละขั้นตอน: รูปแบบการสร้าง
มีสร้างวัตถุอย่างง่ายโดยใช้วิธีการเดียว: รูปแบบวิธีการจากโรงงาน
การสร้างวัตถุโดยใช้วิธีการที่หลากหลายจากโรงงาน: รูปแบบโรงงานที่เป็นนามธรรม
รูปแบบของตัวสร้างและรูปแบบโรงงานดูเหมือนจะคล้ายกับตาเปล่าเพราะทั้งคู่สร้างวัตถุให้คุณ
ตัวอย่างในชีวิตจริงนี้จะสร้างความแตกต่างระหว่างทั้งสองให้ชัดเจนยิ่งขึ้น
สมมติว่าคุณไปร้านอาหารฟาสต์ฟู้ดและสั่งอาหารอาหาร
พิซซ่า
พริก, มะเขือเทศ, ไก่บาร์บีคิว, NO PINEAPPLE
ดังนั้นอาหารประเภทต่าง ๆ จึงทำขึ้นตามรูปแบบของโรงงาน แต่ความหลากหลาย (รสชาติ) ของอาหารแต่ละชนิดนั้นทำโดยรูปแบบบิลเดอร์
อาหารประเภทต่าง ๆ
พิซซ่าเบอร์เกอร์พาสต้า
หลากหลายรูปแบบของพิซซ่า
เฉพาะชีส, ชีส + มะเขือเทศ + พริก, ชีส + มะเขือเทศ ฯลฯ
คุณสามารถดูตัวอย่างรหัสการใช้งานของทั้งสองรูปแบบได้ที่นี่
Pattern Pattern
Factory Pattern
ทั้งสองเป็นรูปแบบ Creational เพื่อสร้างวัตถุ
1) รูปแบบจากโรงงาน - สมมติว่าคุณมีหนึ่งคลาสซูเปอร์คลาสและจำนวนคลาสย่อย N วัตถุถูกสร้างขึ้นอยู่กับพารามิเตอร์ / ค่าที่ส่งผ่าน
2) รูปแบบของตัวสร้าง - เพื่อสร้างวัตถุที่ซับซ้อน
Ex: Make a Loan Object. Loan could be house loan, car loan ,
education loan ..etc. Each loan will have different interest rate, amount ,
duration ...etc. Finally a complex object created through step by step process.
ก่อนอื่นให้ทำตามสิ่งที่ฉันถกเถียง:
ความท้าทายหลักในการออกแบบระบบซอฟต์แวร์ขนาดใหญ่คือต้องมีความยืดหยุ่นและไม่ซับซ้อนเพื่อเปลี่ยนแปลง ด้วยเหตุนี้จึงมีเมตริกบางอย่างเช่นการแต่งงานกันและการติดต่อกัน เพื่อให้บรรลุถึงระบบที่สามารถเปลี่ยนแปลงหรือขยายได้ง่ายในการทำงานโดยไม่จำเป็นต้องออกแบบระบบใหม่ทั้งหมดตั้งแต่ต้นคุณสามารถปฏิบัติตามหลักการออกแบบ (เช่น SOLID และอื่น ๆ ) หลังจากที่ในขณะที่นักพัฒนาบางคนรับรู้ว่าถ้าพวกเขาปฏิบัติตามหลักการเหล่านั้นมีวิธีการแก้ปัญหาที่คล้ายกันบางอย่างที่ทำงานได้ดีกับปัญหาที่คล้ายกัน โซลูชั่นมาตรฐานเหล่านั้นกลายเป็นรูปแบบการออกแบบ
ดังนั้นรูปแบบการออกแบบจะช่วยให้คุณทำตามหลักการออกแบบทั่วไปเพื่อให้ได้ระบบคู่ที่หลวม
ตอบคำถาม:
โดยการถามความแตกต่างระหว่างสองรูปแบบคุณต้องถามตัวเองว่ารูปแบบใดที่ทำให้ระบบของคุณมีความยืดหยุ่นมากขึ้น แต่ละรูปแบบมีจุดประสงค์ในการจัดระเบียบการพึ่งพาระหว่างคลาสในระบบของคุณ
รูปแบบนามธรรมของโรงงาน: GoF:“ ให้อินเทอร์เฟซสำหรับสร้างครอบครัวของวัตถุที่เกี่ยวข้องหรือขึ้นอยู่กับโดยไม่ต้องระบุคลาสคอนกรีตของพวกเขา”
หมายความว่าอะไร: ด้วยการให้อินเทอร์เฟซแบบนี้การเรียกไปยังตัวสร้างของผลิตภัณฑ์แต่ละตระกูลจะถูกห่อหุ้มในคลาสโรงงาน และเนื่องจากที่นี่เป็นที่เดียวในระบบทั้งหมดของคุณที่มีการเรียกตัวสร้างเหล่านั้นว่าคุณสามารถแก้ไขระบบของคุณได้โดยการใช้คลาสโรงงานใหม่ หากคุณแลกเปลี่ยนการเป็นตัวแทนของโรงงานผ่านทางอื่นคุณสามารถแลกเปลี่ยนสินค้าทั้งชุดได้โดยไม่ต้องแตะรหัสส่วนใหญ่
รูปแบบของตัวสร้าง: GoF:“ แยกการก่อสร้างวัตถุที่ซับซ้อนออกจากการเป็นตัวแทนเพื่อให้กระบวนการก่อสร้างเดียวกันสามารถสร้างการรับรองที่แตกต่างกันได้”
สิ่งนี้หมายความว่าอะไร: คุณแค็ปซูลกระบวนการก่อสร้างในอีกชั้นหนึ่งเรียกว่าผู้อำนวยการ (GoF) ผู้กำกับนี้มีอัลกอริทึมในการสร้างอินสแตนซ์ใหม่ของผลิตภัณฑ์ (เช่นเขียนผลิตภัณฑ์ที่ซับซ้อนจากส่วนอื่น ๆ ) เพื่อสร้างส่วนสำคัญของผลิตภัณฑ์ทั้งหมดผู้อำนวยการใช้ผู้สร้าง โดยการแลกเปลี่ยนผู้สร้างในผู้อำนวยการคุณสามารถใช้อัลกอริทึมเดียวกันเพื่อสร้างผลิตภัณฑ์ แต่เปลี่ยนการเป็นตัวแทนของส่วนเดียว (และเพื่อเป็นตัวแทนของผลิตภัณฑ์) เพื่อขยายหรือแก้ไขระบบของคุณในการเป็นตัวแทนของผลิตภัณฑ์สิ่งที่คุณต้องทำคือการใช้คลาสตัวสร้างใหม่
ดังนั้นโดยย่อ: วัตถุประสงค์ของ Abstract Factory Pattern คือการแลกเปลี่ยนชุดผลิตภัณฑ์ที่ใช้ร่วมกัน วัตถุประสงค์ของรูปแบบของตัวสร้างคือการแค็ปซูลอัลกอริทึมแบบนามธรรมของการสร้างผลิตภัณฑ์เพื่อนำกลับมาใช้ใหม่เพื่อการนำเสนอผลิตภัณฑ์ต่าง
ในความคิดของฉันคุณไม่สามารถพูดได้ว่ารูปแบบนามธรรมจากโรงงานเป็นพี่ใหญ่ของรูปแบบการสร้าง ใช่พวกเขามีทั้งลวดลายที่สร้างสรรค์ แต่ความตั้งใจหลักของรูปแบบนั้นแตกต่างกันอย่างสิ้นเชิง
หนึ่งความแตกต่างที่โดดเด่นระหว่างผู้สร้างและโรงงานที่ฉันสามารถทำได้คือต่อไปนี้
สมมติว่าเรามีรถ
class Car
{
bool HasGPS;
bool IsCityCar;
bool IsSportsCar;
int Cylenders;
int Seats;
public:
void Car(bool hasGPs=false,bool IsCityCar=false,bool IsSportsCar=false, int Cylender=2, int Seats=4);
};
ในอินเทอร์เฟซข้างต้นเราสามารถรับรถยนต์ด้วยวิธีต่อไปนี้:
int main()
{
BadCar = new Car(false,false,true,4,4);
}
แต่ถ้าเป็นเช่นนั้นจะมีข้อยกเว้นเกิดขึ้นระหว่างการสร้างที่นั่ง คุณจะไม่ได้รับวัตถุทั้งหมด // แต่
สมมติว่าคุณมีการใช้งานดังต่อไปนี้
class Car
{
bool mHasGPS;
bool mIsCityCar;
bool mIsSportsCar;
int mCylenders;
int mSeats;
public:
void Car() : mHasGPs(false), mIsCityCar(false), mIsSportsCar(false), mCylender(2), mSeats(4) {}
void SetGPS(bool hasGPs=false) {mHasGPs = hasGPs;}
void SetCity(bool CityCar) {mIsCityCar = CityCar;}
void SetSports(bool SportsCar) {mIsSportsCar = SportsCar;}
void SetCylender(int Cylender) {mCylenders = Cylender;}
void SetSeats(int seat) {mSeats = seat;}
};
class CarBuilder
{
Car* mCar;
public:
CarBuilder():mCar(NULL) { mCar* = new Car(); }
~CarBuilder() { if(mCar) { delete mCar; }
Car* GetCar() { return mCar; mCar=new Car(); }
CarBuilder* SetSeats(int n) { mCar->SetSeats(n); return this; }
CarBuilder* SetCylender(int n) { mCar->SetCylender(n); return this; }
CarBuilder* SetSports(bool val) { mCar->SetSports(val); return this; }
CarBuilder* SetCity(bool val) { mCar->SetCity(val); return this; }
CarBuilder* SetGPS(bool val) { mCar->SetGPS(val); return this; }
}
ตอนนี้คุณสามารถสร้างเช่นนี้
int main()
{
CarBuilder* bp =new CarBuilder;
Car* NewCar = bp->SetSeats(4)->SetSports(4)->SetCity(ture)->SetGPS(false)->SetSports(true)->GetCar();
bp->SetSeats(2);
bp->SetSports(4);
bp->SetCity(ture);
bp->SetSports(true)
Car* Car_II= bp->GetCar();
}
ในกรณีที่สองแม้ว่าการดำเนินการหนึ่งล้มเหลวคุณจะยังได้รับรถยนต์
อาจเป็นเพราะรถคันนั้นใช้งานไม่ได้อย่างสมบูรณ์แบบในภายหลัง แต่คุณจะมีวัตถุ
เพราะวิธีการจากโรงงานให้รถของคุณในการโทรเพียงครั้งเดียวในขณะที่ผู้สร้างสร้างทีละคน
ถึงแม้ว่ามันขึ้นอยู่กับความต้องการของผู้ที่จะไป
+-------------------------------------------------------------------+---------------------------------------------------+
| Builder | Factory |
+-------------------------------------------------------------------+---------------------------------------------------+
| Return only single instance to handle complex object construction | Retrun various instances on multiple constructors |
| No interface required | Interface driven |
| Inner classes is involved (to avoid telescopic constructors) | Subclasses are involved |
+-------------------------------------------------------------------+---------------------------------------------------+
การเปรียบเทียบ:
โรงงานผู้สร้างและบทคัดย่อมีความหมายสำหรับวัตถุประสงค์ที่แตกต่างกัน ขึ้นอยู่กับกรณีการใช้งานที่ถูกต้องคุณต้องเลือกรูปแบบการออกแบบที่เหมาะสม
คุณสมบัติเด่นของตัวสร้าง :
คุณสมบัติเด่น ( โรงงานง่าย) จากโรงงาน:
บ่อยครั้งที่การออกแบบเริ่มต้นโดยใช้วิธีการของโรงงาน (ซับซ้อนน้อยลงปรับแต่งได้มากขึ้น subclasses เพิ่มจำนวนมากขึ้น) และพัฒนาไปสู่Abstract Factory , PrototypeหรือBuilder (ยืดหยุ่นมากขึ้นซับซ้อนขึ้น)
ดูที่โพสต์ที่เกี่ยวข้อง:
การรักษาผู้สร้างในคลาสที่แยกต่างหาก (ส่วนต่อประสานที่คล่องแคล่ว)
รูปแบบการออกแบบ: โรงงานกับวิธีการของโรงงานเทียบกับบทคัดย่อจากโรงงาน
คุณสามารถอ้างถึงบทความด้านล่างสำหรับรายละเอียดเพิ่มเติม:
Factory : ใช้สำหรับสร้างอินสแตนซ์ของวัตถุที่การขึ้นต่อกันของวัตถุนั้นถูกยึดโดยโรงงานทั้งหมด สำหรับรูปแบบโรงงานที่เป็นนามธรรมมักมีการนำไปใช้งานที่เป็นรูปธรรมจำนวนมากในโรงงานนามธรรมเดียวกัน การดำเนินการด้านขวาของโรงงานจะถูกฉีดผ่านการฉีดขึ้นรูป
ตัวสร้าง : ใช้เพื่อสร้างวัตถุที่ไม่เปลี่ยนรูปเมื่อการพึ่งพาของวัตถุที่จะสร้างอินสแตนซ์เป็นที่รู้จักกันส่วนหนึ่งล่วงหน้าและให้ลูกค้าของผู้สร้างบางส่วน
รูปแบบนามธรรมจากโรงงานและตัวสร้างมีทั้งรูปแบบการสร้างสรรค์ แต่มีจุดประสงค์ที่แตกต่างกัน
บทคัดย่อรูปแบบโรงงานเน้นการสร้างวัตถุสำหรับครอบครัวของวัตถุที่เกี่ยวข้องที่:
รูปแบบของตัวสร้างจะเน้นไปที่การสร้างวัตถุที่ซับซ้อนทีละขั้นตอน มันแยกการแทนค่าจากกระบวนการสร้างวัตถุที่ซับซ้อนเพื่อให้กระบวนการก่อสร้างเดียวกันสามารถใช้สำหรับการรับรองที่แตกต่างกัน
การก่อสร้างที่ซับซ้อนคือเมื่อวัตถุที่จะสร้างประกอบด้วยวัตถุอื่น ๆ ที่แตกต่างกันซึ่งแสดงโดย abstractions
พิจารณาเมนูใน McDonald's เมนูประกอบด้วยเครื่องดื่มหลักและด้านข้าง ขึ้นอยู่กับว่าทายาทของแต่ละ abstractions ประกอบด้วยกันเมนูที่สร้างขึ้นมีการแสดงอื่น
ที่นั่นเรามีสองอินสแตนซ์ของเมนูที่มีการนำเสนอที่แตกต่างกัน กระบวนการของการก่อสร้างในทางกลับกันยังคงเหมือนเดิม คุณสร้างเมนูด้วยเครื่องดื่มหลักและด้านข้าง
โดยใช้รูปแบบตัวสร้างคุณแยกอัลกอริทึมของการสร้างวัตถุที่ซับซ้อนจากส่วนประกอบต่าง ๆ ที่ใช้ในการสร้าง
ในแง่ของรูปแบบการสร้างอัลกอริทึมถูกห่อหุ้มในผู้อำนวยการในขณะที่ผู้สร้างจะใช้ในการสร้างส่วนที่สำคัญ การเปลี่ยนแปลงตัวสร้างที่ใช้ในอัลกอริทึมของผลการกำกับจะให้ผลลัพธ์ที่แตกต่างเนื่องจากชิ้นส่วนอื่น ๆ ประกอบไปด้วยเมนู วิธีการสร้างเมนูยังคงเหมือนเดิม
ความแตกต่างที่สำคัญระหว่างพวกเขาก็คือรูปแบบการสร้างหลักอธิบายถึงการสร้างวัตถุที่ซับซ้อนทีละขั้นตอน ในรูปแบบโรงงานบทคัดย่อเน้นอยู่ในครอบครัวของวัตถุผลิตภัณฑ์ สร้างผลตอบแทนที่ผลิตภัณฑ์ในขั้นตอนสุดท้าย ในขณะที่รูปแบบโรงงานบทคัดย่อผลิตภัณฑ์ที่เป็นใช้ได้ทันที
ตัวอย่าง: สมมติว่าเรากำลังสร้างเขาวงกต
1. โรงงานบทคัดย่อ:
Maze* MazeGame::CreateMaze (MazeFactory& factory) {
Maze* maze = factory.MakeMaze(); /// product is available at start!!
/* Call some methods on maze */
return maze;
}
2. ผู้สร้าง:
Maze* MazeGame::CreateMaze (MazeBuilder& builder) {
builder.buildMaze(); /// We don't have access to maze
/* Call some methods on builder */
return builder.GetMaze();
}
ฉันเชื่อว่าการใช้งานและความแตกต่างระหว่างรูปแบบของโรงงานและตัวสร้างสามารถเข้าใจ / ทำให้เข้าใจง่ายขึ้นในช่วงระยะเวลาหนึ่งขณะที่คุณทำงานบนฐานรหัสเดียวกันและข้อกำหนดที่เปลี่ยนแปลง
จากประสบการณ์ของฉันคุณมักจะเริ่มต้นด้วยรูปแบบของโรงงานรวมถึงวิธีการสร้างแบบสแตติกสองวิธีเพื่อซ่อนตรรกะการเริ่มต้นที่ค่อนข้างซับซ้อน เมื่อลำดับชั้นวัตถุของคุณซับซ้อนมากขึ้น (หรือเมื่อคุณเพิ่มประเภทพารามิเตอร์มากขึ้น) คุณอาจต้องใช้วิธีการของคุณที่มีพารามิเตอร์มากขึ้นและไม่ต้องพูดถึงว่าคุณจะต้องคอมไพล์โมดูลโรงงานของคุณอีกครั้ง สิ่งเหล่านั้นทั้งหมดเพิ่มความซับซ้อนของวิธีการสร้างลดความสามารถในการอ่านและทำให้โมดูลการสร้างมีความบอบบางมากขึ้น
จุดนี้อาจเป็นจุดเปลี่ยน / ขยาย โดยการทำเช่นนั้นคุณจะสร้างโมดูล wrapper รอบ ๆพารามิเตอร์การก่อสร้างจากนั้นคุณจะสามารถแสดงวัตถุใหม่ (ที่คล้ายกัน) โดยการเพิ่ม abstractions (อาจ) และการใช้งานเพิ่มเติมโดยไม่ต้องสัมผัสตรรกะการสร้างจริงของคุณ คุณมีตรรกะที่ซับซ้อน "น้อยลง"
"การมีวัตถุที่สร้างขึ้นในขั้นตอนเดียวหรือหลายขั้นตอนคือความแตกต่าง" เนื่องจากปัจจัยความหลากหลายเพียงอย่างเดียวนั้นไม่เพียงพอสำหรับฉันที่จะแยกแยะพวกเขาเนื่องจากฉันสามารถใช้ทั้งสองวิธีสำหรับเกือบทุกกรณีที่ฉันเผชิญ ตอนนี้โดยไม่ได้รับประโยชน์ใด ๆ ดังนั้นนี่คือสิ่งที่ฉันคิดในที่สุด
ข้อได้เปรียบหลักของรูปแบบตัวสร้างเหนือรูปแบบจากโรงงานคือในกรณีที่คุณต้องการสร้างวัตถุมาตรฐานที่มีการปรับแต่งที่เป็นไปได้มากมาย
ตัวอย่างเช่นหากคุณต้องการเขียนไคลเอ็นต์ HTTP - คุณจะตั้งค่าพารามิเตอร์เริ่มต้นเช่นการหมดเวลาการเขียน / อ่านค่าเริ่มต้นโปรโตคอลแคช DNS ตัวดัก ฯลฯ
ผู้ใช้ส่วนใหญ่ของลูกค้าของคุณจะใช้พารามิเตอร์เริ่มต้นเหล่านั้นในขณะที่ผู้ใช้รายอื่นอาจต้องการปรับแต่งพารามิเตอร์อื่น ๆ ในบางกรณีคุณเพียงต้องการเปลี่ยนการหมดเวลาและใช้ส่วนที่เหลือตามที่เป็นอยู่ในขณะที่ในกรณีอื่นคุณอาจต้องกำหนดค่าเองเช่นแคช
นี่เป็นวิธีที่เป็นไปได้ในการสร้างอินสแตนซ์ไคลเอ็นต์ของคุณ (นำมาจาก OkHttpClient):
//just give me the default stuff
HttpClient.Builder().build()
//I want to use custom cache
HttpClient.Builder().cache(MyCache()).build()
//I want custom connection timeout
HttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).build()
//I am more interested in read/write timeout
HttpClient.Builder()
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS).build()
หากคุณใช้รูปแบบจากโรงงานสำหรับสิ่งนี้คุณจะต้องเขียนวิธีการมากมายพร้อมกับค่าพารามิเตอร์ที่สร้างขึ้นทั้งหมด ด้วยตัวสร้างคุณเพียงระบุคนที่คุณใส่ใจและให้ผู้สร้างสร้างมันขึ้นมาเพื่อคุณดูแล params อื่น ๆ เหล่านั้นทั้งหมด
รูปแบบการสร้างเน้นความซับซ้อน ของการสร้างวัตถุ (แก้ไขโดย "ขั้นตอน")
รูปแบบนามธรรมเน้น "เพียงแค่" กับ "นามธรรม" ของวัตถุ (หลายรายการ แต่เกี่ยวข้อง)
ความแตกต่างชัดเจนในตัวสร้างรูปแบบตัวสร้างจะสร้างวัตถุชนิดเฉพาะสำหรับคุณ คุณต้องบอกผู้สร้างว่าต้องสร้างอะไร ในรูปแบบโรงงานโดยใช้คลาสนามธรรมคุณกำลังสร้างวัตถุเฉพาะโดยตรง
ที่นี่ตัวสร้างคลาสทำหน้าที่เป็นสื่อกลางระหว่างคลาสหลักและคลาสชนิดเฉพาะ สิ่งที่เป็นนามธรรมมากขึ้น
ทั้งคู่มีลักษณะคล้ายกันมาก แต่ถ้าคุณมีพารามิเตอร์จำนวนมากสำหรับการสร้างวัตถุโดยมีพารามิเตอร์บางตัวเลือกที่มีค่าเริ่มต้นให้ไปสำหรับรูปแบบตัวสร้าง
IMHO
ช่างก่อสร้างเป็นโรงงานที่ซับซ้อนกว่านี้
แต่ในตัวสร้างคุณสามารถยกตัวอย่างวัตถุด้วยการใช้โรงงานอื่นซึ่งจะต้องสร้างวัตถุขั้นสุดท้ายและถูกต้อง
ดังนั้นการพูดคุยเกี่ยวกับวิวัฒนาการ "รูปแบบ Creational" โดยความซับซ้อนที่คุณสามารถคิดเกี่ยวกับมันด้วยวิธีนี้:
Dependency Injection Container -> Service Locator -> Builder -> Factory
ทั้งสองรูปแบบมีความจำเป็นเช่นเดียวกัน: ซ่อนจากบางรหัสไคลเอนต์ตรรกะการก่อสร้างของวัตถุที่ซับซ้อน แต่อะไรทำให้ "ซับซ้อน" (หรือบางครั้งซับซ้อน) วัตถุ? ส่วนใหญ่เป็นเพราะการพึ่งพาหรือมากกว่าสถานะของวัตถุที่ประกอบด้วยรัฐบางส่วนมากขึ้น คุณสามารถฉีดการพึ่งพาโดยนวกรรมิกเพื่อตั้งค่าสถานะวัตถุเริ่มต้น แต่วัตถุอาจต้องการมากของพวกเขาบางคนจะอยู่ในสถานะเริ่มต้นเริ่มต้น (เพียงเพราะเราควรได้เรียนรู้ว่าการตั้งค่าเริ่มต้นเป็นโมฆะไม่ใช่วิธีที่สะอาดที่สุด ) และชุดอื่น ๆ ให้อยู่ในสภาพที่ได้รับการขับเคลื่อนโดยเงื่อนไขบางอย่าง นอกจากนี้ยังมีคุณสมบัติของวัตถุที่เป็น "การพึ่งพาที่หลงลืม" บางชนิด แต่พวกมันยังสามารถสมมติสถานะทางเลือกได้
มีสองวิธีที่รู้จักกันดีในการควบคุมความซับซ้อนนั้น:
การประพันธ์ / การรวม: สร้างวัตถุสร้างวัตถุที่ขึ้นต่อกันจากนั้นจึงโยงเข้าด้วยกัน ผู้สร้างสามารถสร้างกระบวนการที่โปร่งใสและยืดหยุ่นซึ่งกำหนดกฎที่นำไปสู่การสร้างส่วนประกอบ
ความแตกต่าง: กฎการก่อสร้างจะประกาศโดยตรงในคำจำกัดความของประเภทย่อยดังนั้นคุณจึงมีชุดของกฎสำหรับแต่ละประเภทย่อยและเงื่อนไขบางอย่างตัดสินใจว่าจะใช้กฎใดในกลุ่มชุดของกฎเหล่านี้เพื่อสร้างวัตถุ โรงงานเข้ากันได้อย่างสมบูรณ์แบบในสถานการณ์นี้
ไม่มีอะไรป้องกันไม่ให้ผสมสองแนวทางนี้ ตระกูลของผลิตภัณฑ์สามารถสร้างวัตถุนามธรรมที่สร้างขึ้นด้วยตัวสร้างผู้สร้างสามารถใช้โรงงานเพื่อกำหนดว่าวัตถุชิ้นส่วนยกตัวอย่าง
ในความคิดของฉันรูปแบบตัวสร้างจะใช้เมื่อคุณต้องการสร้างวัตถุจากเครือวัตถุอื่นและการสร้างชิ้นส่วนจำเป็นต้องเป็นอิสระจากวัตถุที่คุณต้องการสร้าง ช่วยในการซ่อนการสร้างชิ้นส่วนจากลูกค้าเพื่อให้ผู้สร้างและลูกค้าเป็นอิสระ มันถูกใช้สำหรับการสร้างวัตถุที่ซับซ้อน (วัตถุซึ่งอาจประกอบด้วยคุณสมบัติที่ซับซ้อน)
ในขณะที่รูปแบบจากโรงงานระบุว่าคุณต้องการสร้างวัตถุของครอบครัวทั่วไปและคุณต้องการให้มันถูกชุบทันที มันใช้สำหรับวัตถุที่ง่ายกว่า
โรงงานผู้สร้างและบทคัดย่อ
รูปแบบการออกแบบ Builder จะคล้ายกันมากกับรูปแบบ Abstract Factory ด้วยเหตุนี้จึงเป็นสิ่งสำคัญที่จะต้องสามารถสร้างความแตกต่างระหว่างสถานการณ์เมื่อมีการใช้อย่างใดอย่างหนึ่ง ในกรณีของ Abstract Factory ลูกค้าใช้วิธีการของโรงงานเพื่อสร้างวัตถุของตัวเอง ในกรณีของตัวสร้างคลาสตัวสร้างจะได้รับคำแนะนำเกี่ยวกับวิธีสร้างวัตถุและจากนั้นจะถูกถาม แต่วิธีการที่คลาสจะรวมกันนั้นขึ้นอยู่กับคลาสของตัวสร้างรายละเอียดนี้สร้างความแตกต่างระหว่างสองรูปแบบ
อินเตอร์เฟสทั่วไปสำหรับผลิตภัณฑ์
ในทางปฏิบัติผลิตภัณฑ์ที่สร้างโดยผู้สร้างคอนกรีตมีโครงสร้างที่แตกต่างกันอย่างมีนัยสำคัญดังนั้นหากไม่มีเหตุผลที่จะได้รับผลิตภัณฑ์ที่แตกต่างกันในระดับผู้ปกครองทั่วไป สิ่งนี้ยังแยกความแตกต่างของรูปแบบตัวสร้างจากรูปแบบนามธรรมจากโรงงานซึ่งสร้างวัตถุที่ได้มาจากประเภททั่วไป
รูปแบบของโรงงานสร้างการใช้งานอย่างเป็นรูปธรรมของคลาสที่รันไทม์นั่นคือความตั้งใจหลักคือการใช้ความหลากหลายเพื่อให้คลาสย่อยตัดสินใจว่าคลาสใดจะสร้างอินสแตนซ์ ซึ่งหมายความว่าในเวลารวบรวมเราไม่ทราบคลาสที่แน่นอนที่จะถูกสร้างขึ้นในขณะที่รูปแบบการสร้างส่วนใหญ่เกี่ยวข้องกับการแก้ปัญหาของ antipattern ตัวสร้าง telescoping ซึ่งเกิดขึ้นเนื่องจากฟิลด์จำนวนมากของคลาส ในรูปแบบการสร้างไม่มีความคิดของความหลากหลายในขณะที่เรารู้ว่าสิ่งที่เรากำลังพยายามที่จะสร้างในเวลารวบรวม
ชุดรูปแบบทั่วไปเพียงอย่างเดียวของทั้งสองรูปแบบคือการซ่อนตัวสร้างและการสร้างวัตถุที่อยู่เบื้องหลังวิธีการของโรงงานและวิธีการสร้างเพื่อปรับปรุงการสร้างวัตถุ
รูปแบบจากโรงงานช่วยให้คุณสามารถสร้างวัตถุได้ในคราวเดียวในขณะที่รูปแบบของตัวสร้างช่วยให้คุณสามารถทำลายกระบวนการสร้างของวัตถุ ด้วยวิธีนี้คุณสามารถเพิ่มฟังก์ชันการทำงานที่แตกต่างกันระหว่างการสร้างวัตถุ