รูปแบบของตัวออกแบบการสร้างและรูปแบบการออกแบบจากโรงงานแตกต่างกันอย่างไร


663

รูปแบบการออกแบบของ Builder และรูปแบบการออกแบบของโรงงานแตกต่างกันอย่างไร

ข้อใดที่ได้เปรียบกว่าและทำไม

ฉันจะแสดงสิ่งที่ค้นพบของฉันเป็นกราฟได้อย่างไรหากฉันต้องการทดสอบและเปรียบเทียบ / เปรียบต่างรูปแบบเหล่านี้


13
เนื่องจากพวกเขาทำสิ่งต่าง ๆ คุณหมายถึงอะไรโดย "ได้เปรียบ"
S.Lott

5
สร้างเป็นรุ่นที่ซับซ้อนมากขึ้นของคอนสตรัค - ในขณะที่วิธีการโรงงานเป็นง่ายหนึ่ง
DávidHorváth

@ DávidHorváthฉันจะไม่อธิบายว่า Builder เป็น "ซับซ้อนมากขึ้น" เมื่อคุณจัดการกับคอนสตรัคเตอร์ที่มี 100 พารามิเตอร์และคุณสนใจเพียง 3 พารามิเตอร์เท่านั้นและคุณรู้ว่าจำนวนพารามิเตอร์อาจเปลี่ยนแปลงในอนาคตการใช้รูปแบบตัวสร้างจะทำให้ชีวิตของทุกคนง่ายขึ้นมาก
Aberrant

@Aberrant การใช้งานที่ซับซ้อนและความซับซ้อนของสถาปัตยกรรมเป็นสองสิ่งที่แตกต่างกัน ฉันมุ่งเน้นไปที่หลัง
เดวิดฮอร์วั ธ

คำตอบ:


466

ด้วยรูปแบบการออกแบบมักจะไม่มีทางออกที่ "ได้เปรียบกว่า" ที่ใช้ได้กับทุกกรณี ขึ้นอยู่กับสิ่งที่คุณต้องนำไปใช้

จาก 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


159
นี่คือสิ่งที่แตกต่าง ตัวสร้างจำเป็นเฉพาะเมื่อไม่สามารถสร้างวัตถุได้ในขั้นตอนเดียว หนึ่งในตัวอย่างที่ดีนี้จะอยู่ในกระบวนการการทำให้เป็นอนุกรมสำหรับวัตถุที่ซับซ้อน บ่อยครั้งที่พารามิเตอร์สำหรับวัตถุที่ซับซ้อนจะต้องดึงทีละคน
Bernard Igiri

1
สำหรับประโยคแรกฉันจะบอกว่ามักจะมีทางออกที่เป็นประโยชน์มากกว่าที่ใช้กันอย่างแพร่หลาย ... เราไม่เห็นสิ่งเหล่านี้เพราะพวกเขาจบลงด้วยการอบโดยตรงกับภาษาโปรแกรม
Joel Coehoorn

4
@Joel: ฉันยอมรับว่ารูปแบบบางอย่างเป็นเรื่องธรรมดามากกว่าที่คนอื่น ๆ (เช่น Factory ดูเหมือนจะเป็นเรื่องธรรมดามากกว่า Builder) แต่สิ่งที่ฉันหมายถึงคือไม่มีรูปแบบใดที่ดีกว่าแบบอื่นเสมอไม่ว่าสถานการณ์จะเป็นอย่างไร .
Adrian Grigore

@AdrianGrigore เกิดอะไรขึ้นถ้าผสมทั้งสองอย่างเข้าด้วยกัน? aso.net mvc มี ControllerBuilder ที่ได้ตั้งค่าและรับเมธอดสำหรับคลาส ControllerFactory
AminM

คำตอบของ Goood แม้ว่า 2 สิ่งที่ควรค่าแก่การเพิ่มคือ 1) ตัวสร้างส่วนใหญ่จะใช้ในการสร้าง POJO โดยใช้ Fluent API (เช่น Person.builder (). withName ("Sam"). withAge (38) .build (). 2) ใน Experene ของฉันตัวสร้างมีประโยชน์สำหรับการสร้าง POJO สำหรับวัตถุโดเมนในขณะที่โรงงานมีประโยชน์สำหรับการสร้างวัตถุบริการเช่นคลาส PdfGeneratorFactory วัตถุบริการอาจถูกแคชภายในโรงงานสำหรับการใช้งานมากกว่า 1 ครั้งในขณะที่ตัวสร้างจะสร้างวัตถุใหม่ด้วยการออกแบบเสมอ
saurabh.in

359

โรงงานเป็นเพียงฟังก์ชั่นคลุมรอบตัวสร้าง (อาจเป็นหนึ่งในคลาสที่แตกต่างกัน) ความแตกต่างที่สำคัญคือรูปแบบวิธีการจากโรงงานต้องการให้วัตถุทั้งหมดถูกสร้างขึ้นในการเรียกใช้วิธีการเดียวโดยมีพารามิเตอร์ทั้งหมดส่งผ่านในบรรทัดเดียว วัตถุสุดท้ายจะถูกส่งกลับ

ในทางกลับกันรูปแบบของตัวสร้างจะมีวัตถุห่อหุ้มอยู่รอบตัวพารามิเตอร์ทั้งหมดที่เป็นไปได้ที่คุณอาจต้องการส่งผ่านไปยังการเรียกใช้คอนสตรัคเตอร์ สิ่งนี้อนุญาตให้คุณใช้เมธอด 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


1
นั่นไม่ใช่การใช้งานที่ถูกต้องของ IMO ของรูปแบบตัวสร้างแม้ในลิงก์วิกิที่คุณใช้งานจะแตกต่างกัน FruitBuilder นี้เป็นการผสมผสานระหว่างองค์ประกอบ Director และ Builder ที่คุณเรียกใช้ build () ซึ่งควรเป็นของ Director และ setters ที่เป็นส่วนประกอบของ Builder ผู้อำนวยการควรมีตรรกะทางธุรกิจเกี่ยวกับวิธีการสร้างวัตถุโดยใช้วิธีการสร้าง apis ได้อย่างคล่องแคล่วไม่ได้เป็นรูปแบบการสร้างและ StringBuilder ยังไม่ได้เป็นรูปแบบการสร้าง
Kmaczek

282

รูปแบบของ Factory สามารถมองเห็นได้ในรูปแบบของ Builder รูปแบบที่เรียบง่าย

ในโรงงานรูปแบบโรงงานอยู่ในความดูแลของการสร้างชนิดย่อยต่างๆของวัตถุขึ้นอยู่กับความต้องการของ

ผู้ใช้วิธีการจากโรงงานไม่จำเป็นต้องรู้ชนิดย่อยที่แน่นอนของวัตถุนั้น ตัวอย่างของวิธีการจากโรงงานcreateCarอาจส่งคืนFordหรือHondaวัตถุที่พิมพ์

ในรูปแบบตัวสร้างชนิดย่อยที่แตกต่างกันจะถูกสร้างขึ้นโดยวิธีการสร้าง แต่องค์ประกอบของวัตถุอาจแตกต่างกันภายในคลาสย่อยเดียวกัน

เพื่อดำเนินการต่อตัวอย่างรถยนต์คุณอาจมีcreateCarวิธีการสร้างซึ่งสร้างHondaวัตถุ -typed ด้วย 4 cylinder engine หรือHondaวัตถุ -typed 6 cylinder รูปแบบการสร้างช่วยให้สำหรับความละเอียดปลีกย่อยนี้

ไดอะแกรมของทั้งรูปแบบตัวสร้างและรูปแบบวิธีการของโรงงานมีอยู่ใน Wikipedia


13
รูปแบบการสร้างเป็นเหมือนการซูมเพื่อสร้างวัตถุขนาดใหญ่ วัตถุขนาดใหญ่ประกอบด้วยวัตถุอื่น ๆ ซึ่งประกอบขึ้นด้วยเช่นการเรียกซ้ำ ในขณะที่โรงงานจะให้สิ่งที่คุณต้องการในการโทรเพียงครั้งเดียว ความเข้าใจนี้ถูกต้องหรือไม่
Fooo

63

รูปแบบการออกแบบตัวสร้างอธิบายถึงวัตถุที่รู้วิธีการสร้างวัตถุอื่นที่มีประเภทเฉพาะในหลายขั้นตอน มันถือสถานะที่จำเป็นสำหรับรายการเป้าหมายในแต่ละขั้นตอนกลาง คิดว่า StringBuilder ดำเนินการอย่างไรเพื่อสร้างสตริงสุดท้าย

รูปแบบการออกแบบจากโรงงานอธิบายถึงวัตถุที่รู้วิธีสร้างวัตถุที่แตกต่างกัน แต่มีความเกี่ยวข้องในขั้นตอนเดียวโดยเลือกประเภทเฉพาะตามพารามิเตอร์ที่กำหนด คิดว่าระบบการทำให้เป็นอันดับซึ่งคุณสร้าง serializer ของคุณและมันสร้างความต้องการในวัตถุทั้งหมดในการเรียกโหลดเดียว


7
เพียงคำใบ้: ตัวอย่างที่ดีสำหรับรูปแบบตัวสร้างคือ "ส่วนต่อประสานที่คล่องแคล่ว" และ ADO.NET เต็มไปด้วยการใช้งาน "factory" และ "abstract factory" (เช่น DbFactory)
boj

50
  • การสร้างวัตถุที่ซับซ้อนทีละขั้นตอน: รูปแบบการสร้าง

  • มีสร้างวัตถุอย่างง่ายโดยใช้วิธีการเดียว: รูปแบบวิธีการจากโรงงาน

  • การสร้างวัตถุโดยใช้วิธีการที่หลากหลายจากโรงงาน: รูปแบบโรงงานที่เป็นนามธรรม


21

รูปแบบของตัวสร้างและรูปแบบโรงงานดูเหมือนจะคล้ายกับตาเปล่าเพราะทั้งคู่สร้างวัตถุให้คุณ

แต่คุณต้องมองให้ใกล้

ตัวอย่างในชีวิตจริงนี้จะสร้างความแตกต่างระหว่างทั้งสองให้ชัดเจนยิ่งขึ้น

สมมติว่าคุณไปร้านอาหารฟาสต์ฟู้ดและสั่งอาหารอาหาร

1) อาหารอะไร

พิซซ่า

2) รสชาติอะไร

พริก, มะเขือเทศ, ไก่บาร์บีคิว, NO PINEAPPLE

ดังนั้นอาหารประเภทต่าง ๆ จึงทำขึ้นตามรูปแบบของโรงงาน แต่ความหลากหลาย (รสชาติ) ของอาหารแต่ละชนิดนั้นทำโดยรูปแบบบิลเดอร์

อาหารประเภทต่าง ๆ

พิซซ่าเบอร์เกอร์พาสต้า

หลากหลายรูปแบบของพิซซ่า

เฉพาะชีส, ชีส + มะเขือเทศ + พริก, ชีส + มะเขือเทศ ฯลฯ

ตัวอย่างโค้ด

คุณสามารถดูตัวอย่างรหัสการใช้งานของทั้งสองรูปแบบได้ที่นี่
Pattern Pattern
Factory Pattern


1
ขอขอบคุณที่แจ้งรหัสตัวอย่าง! ตัวอย่างของคุณแยกความแตกต่างทั้งสองรูปแบบได้เป็นอย่างดี
Rommel Paras

18

ทั้งสองเป็นรูปแบบ 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.

12

ก่อนอื่นให้ทำตามสิ่งที่ฉันถกเถียง:

ความท้าทายหลักในการออกแบบระบบซอฟต์แวร์ขนาดใหญ่คือต้องมีความยืดหยุ่นและไม่ซับซ้อนเพื่อเปลี่ยนแปลง ด้วยเหตุนี้จึงมีเมตริกบางอย่างเช่นการแต่งงานกันและการติดต่อกัน เพื่อให้บรรลุถึงระบบที่สามารถเปลี่ยนแปลงหรือขยายได้ง่ายในการทำงานโดยไม่จำเป็นต้องออกแบบระบบใหม่ทั้งหมดตั้งแต่ต้นคุณสามารถปฏิบัติตามหลักการออกแบบ (เช่น SOLID และอื่น ๆ ) หลังจากที่ในขณะที่นักพัฒนาบางคนรับรู้ว่าถ้าพวกเขาปฏิบัติตามหลักการเหล่านั้นมีวิธีการแก้ปัญหาที่คล้ายกันบางอย่างที่ทำงานได้ดีกับปัญหาที่คล้ายกัน โซลูชั่นมาตรฐานเหล่านั้นกลายเป็นรูปแบบการออกแบบ

ดังนั้นรูปแบบการออกแบบจะช่วยให้คุณทำตามหลักการออกแบบทั่วไปเพื่อให้ได้ระบบคู่ที่หลวม

ตอบคำถาม:

โดยการถามความแตกต่างระหว่างสองรูปแบบคุณต้องถามตัวเองว่ารูปแบบใดที่ทำให้ระบบของคุณมีความยืดหยุ่นมากขึ้น แต่ละรูปแบบมีจุดประสงค์ในการจัดระเบียบการพึ่งพาระหว่างคลาสในระบบของคุณ

รูปแบบนามธรรมของโรงงาน: GoF:“ ให้อินเทอร์เฟซสำหรับสร้างครอบครัวของวัตถุที่เกี่ยวข้องหรือขึ้นอยู่กับโดยไม่ต้องระบุคลาสคอนกรีตของพวกเขา”

หมายความว่าอะไร: ด้วยการให้อินเทอร์เฟซแบบนี้การเรียกไปยังตัวสร้างของผลิตภัณฑ์แต่ละตระกูลจะถูกห่อหุ้มในคลาสโรงงาน และเนื่องจากที่นี่เป็นที่เดียวในระบบทั้งหมดของคุณที่มีการเรียกตัวสร้างเหล่านั้นว่าคุณสามารถแก้ไขระบบของคุณได้โดยการใช้คลาสโรงงานใหม่ หากคุณแลกเปลี่ยนการเป็นตัวแทนของโรงงานผ่านทางอื่นคุณสามารถแลกเปลี่ยนสินค้าทั้งชุดได้โดยไม่ต้องแตะรหัสส่วนใหญ่

รูปแบบของตัวสร้าง: GoF:“ แยกการก่อสร้างวัตถุที่ซับซ้อนออกจากการเป็นตัวแทนเพื่อให้กระบวนการก่อสร้างเดียวกันสามารถสร้างการรับรองที่แตกต่างกันได้”

สิ่งนี้หมายความว่าอะไร: คุณแค็ปซูลกระบวนการก่อสร้างในอีกชั้นหนึ่งเรียกว่าผู้อำนวยการ (GoF) ผู้กำกับนี้มีอัลกอริทึมในการสร้างอินสแตนซ์ใหม่ของผลิตภัณฑ์ (เช่นเขียนผลิตภัณฑ์ที่ซับซ้อนจากส่วนอื่น ๆ ) เพื่อสร้างส่วนสำคัญของผลิตภัณฑ์ทั้งหมดผู้อำนวยการใช้ผู้สร้าง โดยการแลกเปลี่ยนผู้สร้างในผู้อำนวยการคุณสามารถใช้อัลกอริทึมเดียวกันเพื่อสร้างผลิตภัณฑ์ แต่เปลี่ยนการเป็นตัวแทนของส่วนเดียว (และเพื่อเป็นตัวแทนของผลิตภัณฑ์) เพื่อขยายหรือแก้ไขระบบของคุณในการเป็นตัวแทนของผลิตภัณฑ์สิ่งที่คุณต้องทำคือการใช้คลาสตัวสร้างใหม่

ดังนั้นโดยย่อ: วัตถุประสงค์ของ Abstract Factory Pattern คือการแลกเปลี่ยนชุดผลิตภัณฑ์ที่ใช้ร่วมกัน วัตถุประสงค์ของรูปแบบของตัวสร้างคือการแค็ปซูลอัลกอริทึมแบบนามธรรมของการสร้างผลิตภัณฑ์เพื่อนำกลับมาใช้ใหม่เพื่อการนำเสนอผลิตภัณฑ์ต่าง

ในความคิดของฉันคุณไม่สามารถพูดได้ว่ารูปแบบนามธรรมจากโรงงานเป็นพี่ใหญ่ของรูปแบบการสร้าง ใช่พวกเขามีทั้งลวดลายที่สร้างสรรค์ แต่ความตั้งใจหลักของรูปแบบนั้นแตกต่างกันอย่างสิ้นเชิง


คำตอบที่ดีอธิบายอย่างละเอียด
Towry

คุณช่วยอธิบายความหมายของ "แยกการก่อสร้างวัตถุที่ซับซ้อนออกจากการเป็นตัวแทนของมันได้
ไหม

@ Rajdeep คำอธิบายนั้นยาวสำหรับความคิดเห็นนั่นเป็นเหตุผลที่ฉันเขียนคำตอบอีก
Janis

@ Janis คำตอบหรือแหล่งข้อมูลนั้นอยู่ที่ไหนจากที่ฉันสามารถอ่านได้?
Rajdeep

@Rajdeep ฉันแนะนำให้คุณอ่านหนังสือ Patterns Design Patterns“ - amazon.de/Patterns-Elements-Reuse-Object-Oriented-Software/ …
Janis

7

หนึ่งความแตกต่างที่โดดเด่นระหว่างผู้สร้างและโรงงานที่ฉันสามารถทำได้คือต่อไปนี้

สมมติว่าเรามีรถ

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();

  }

ในกรณีที่สองแม้ว่าการดำเนินการหนึ่งล้มเหลวคุณจะยังได้รับรถยนต์

อาจเป็นเพราะรถคันนั้นใช้งานไม่ได้อย่างสมบูรณ์แบบในภายหลัง แต่คุณจะมีวัตถุ

เพราะวิธีการจากโรงงานให้รถของคุณในการโทรเพียงครั้งเดียวในขณะที่ผู้สร้างสร้างทีละคน

ถึงแม้ว่ามันขึ้นอยู่กับความต้องการของผู้ที่จะไป


2
แน่นอนว่ามันจะดีกว่าถ้าไม่มีรถยนต์ที่ไม่ใช่รถที่ไม่ถูกต้อง - จะเกิดอะไรขึ้นถ้าคุณพบปัญหาเมื่อมาใช้ตัวแบ่งเท่านั้น
เคน

@ เคน: ฉันไม่ได้ยืนยันว่ามันเป็นการออกแบบที่ดีจากที่คาดหวังจากโครงการเชิงพาณิชย์ ฯลฯ แต่ความตั้งใจในการอ้างอิงตัวอย่างนี้เพื่อเป็นตัวอย่างความแตกต่างระหว่างรูปแบบ แน่นอนคุณถูกต้องว่านี่เป็นสิ่งที่ไม่ดีจากประสบการณ์ของผู้ใช้ที่ได้รับรถยนต์ที่ไม่ดี แต่ให้พิจารณาว่ามีโรงงานที่ผลิตรถยนต์ & บางส่วนทำงานผิดปกติแล้วรถจะได้รับการผลิต เวลาของการทดสอบและการจัดส่งของรถคันนั้นให้กับลูกค้าจะหยุด
Fooo

2
ฉันต้องการชี้แจงว่าจริง ๆ แล้วฉันเป็นแฟนตัวยงของรูปแบบการสร้างอย่างไรก็ตามไม่ใช่สำหรับเหตุผลที่คุณให้ วัตถุที่ไม่ถูกต้องน่าจะล้มเหลวในการก่อสร้างยิ่งกระบวนการที่พบข้อผิดพลาดนั้นยิ่งมีราคาแพง ด้วยรูปแบบการสร้างมันจะเป็นเรื่องปกติสำหรับวิธีการสร้าง (ในตัวอย่างของคุณที่เรียกว่า getCar ()) เพื่อโยนข้อยกเว้นหากมีข้อมูลที่จำเป็นขาดหายไป
เคน

7
+-------------------------------------------------------------------+---------------------------------------------------+
|                              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                           |
+-------------------------------------------------------------------+---------------------------------------------------+  

รูปแบบตัวสร้าง Telescoping

การเปรียบเทียบ:

  • โรงงาน:พิจารณาร้านอาหาร การสร้าง "มื้ออาหารของวันนี้" เป็นรูปแบบของโรงงานเพราะคุณบอกห้องครัวว่า "รับอาหารของฉันวันนี้" และห้องครัว (โรงงาน) จะตัดสินว่าวัตถุใดที่จะสร้างตามเกณฑ์ที่ซ่อนอยู่
  • ผู้สร้าง:ผู้สร้างจะปรากฏขึ้นหากคุณสั่งพิซซ่าแบบกำหนดเอง ในกรณีนี้บริกรบอกพ่อครัว (ผู้สร้าง) "ฉันต้องการพิซซ่า; เพิ่มชีสหัวหอมและเบคอน!" ดังนั้นผู้สร้างจะเปิดเผยคุณสมบัติที่วัตถุที่สร้างขึ้นควรมี แต่ซ่อนวิธีการตั้งค่า

มารยาท


5

โรงงานผู้สร้างและบทคัดย่อมีความหมายสำหรับวัตถุประสงค์ที่แตกต่างกัน ขึ้นอยู่กับกรณีการใช้งานที่ถูกต้องคุณต้องเลือกรูปแบบการออกแบบที่เหมาะสม

คุณสมบัติเด่นของตัวสร้าง :

  1. รูปแบบตัวสร้างสร้างวัตถุที่ซับซ้อนโดยใช้วัตถุอย่างง่ายและใช้วิธีการทีละขั้นตอน
  2. ชั้น Builder สร้างขั้นตอนวัตถุสุดท้ายโดยขั้นตอน ผู้สร้างนี้มีความเป็นอิสระจากวัตถุอื่น ๆ
  3. แทนที่เป็นวิธีโรงงาน / บทคัดย่อโรงงานในสถานการณ์นี้: มีการโต้แย้งมากเกินไปที่จะผ่านจากโปรแกรมไคลเอนต์ไปยังคลาสโรงงานที่อาจเกิดข้อผิดพลาดได้ง่าย
  4. พารามิเตอร์บางตัวอาจเป็นทางเลือกไม่เหมือนใน Factory ซึ่งจะส่งพารามิเตอร์ทั้งหมด

คุณสมบัติเด่น ( โรงงานง่าย) จากโรงงาน:

  1. รูปแบบ Creational
  2. ขึ้นอยู่กับมรดก
  3. โรงงานส่งคืนวิธีการโรงงาน (อินเตอร์เฟส) ซึ่งจะส่งคืนวัตถุคอนกรีต
  4. คุณสามารถทดแทน Concrete Objects ใหม่สำหรับส่วนต่อประสานและไคลเอนต์ (ผู้โทร) ไม่ควรรับรู้ถึงการใช้งานที่เป็นรูปธรรมทั้งหมด
  5. ไคลเอ็นต์เข้าถึงอินเตอร์เฟสเท่านั้นเสมอและคุณสามารถซ่อนรายละเอียดการสร้างวัตถุในวิธีการของโรงงาน

บ่อยครั้งที่การออกแบบเริ่มต้นโดยใช้วิธีการของโรงงาน (ซับซ้อนน้อยลงปรับแต่งได้มากขึ้น subclasses เพิ่มจำนวนมากขึ้น) และพัฒนาไปสู่Abstract Factory , PrototypeหรือBuilder (ยืดหยุ่นมากขึ้นซับซ้อนขึ้น)

ดูที่โพสต์ที่เกี่ยวข้อง:

การรักษาผู้สร้างในคลาสที่แยกต่างหาก (ส่วนต่อประสานที่คล่องแคล่ว)

รูปแบบการออกแบบ: โรงงานกับวิธีการของโรงงานเทียบกับบทคัดย่อจากโรงงาน

คุณสามารถอ้างถึงบทความด้านล่างสำหรับรายละเอียดเพิ่มเติม:

sourcemaking

journaldev


5

Factory : ใช้สำหรับสร้างอินสแตนซ์ของวัตถุที่การขึ้นต่อกันของวัตถุนั้นถูกยึดโดยโรงงานทั้งหมด สำหรับรูปแบบโรงงานที่เป็นนามธรรมมักมีการนำไปใช้งานที่เป็นรูปธรรมจำนวนมากในโรงงานนามธรรมเดียวกัน การดำเนินการด้านขวาของโรงงานจะถูกฉีดผ่านการฉีดขึ้นรูป

ตัวสร้าง : ใช้เพื่อสร้างวัตถุที่ไม่เปลี่ยนรูปเมื่อการพึ่งพาของวัตถุที่จะสร้างอินสแตนซ์เป็นที่รู้จักกันส่วนหนึ่งล่วงหน้าและให้ลูกค้าของผู้สร้างบางส่วน


4

รูปแบบนามธรรมจากโรงงานและตัวสร้างมีทั้งรูปแบบการสร้างสรรค์ แต่มีจุดประสงค์ที่แตกต่างกัน

บทคัดย่อรูปแบบโรงงานเน้นการสร้างวัตถุสำหรับครอบครัวของวัตถุที่เกี่ยวข้องที่:

  • แต่ละตระกูลคือชุดของคลาสที่ได้มาจากคลาสพื้นฐาน / อินเตอร์เฟสทั่วไป
  • แต่ละวัตถุจะถูกส่งกลับทันทีเนื่องจากการโทรครั้งเดียว

รูปแบบของตัวสร้างจะเน้นไปที่การสร้างวัตถุที่ซับซ้อนทีละขั้นตอน มันแยกการแทนค่าจากกระบวนการสร้างวัตถุที่ซับซ้อนเพื่อให้กระบวนการก่อสร้างเดียวกันสามารถใช้สำหรับการรับรองที่แตกต่างกัน

  • วัตถุตัวสร้างห่อหุ้มการกำหนดค่าของวัตถุที่ซับซ้อน
  • ผู้อำนวยการวัตถุรู้โปรโตคอลของการใช้ตัวสร้างที่โปรโตคอลกำหนดขั้นตอนตรรกะทั้งหมดที่จำเป็นในการสร้างวัตถุที่ซับซ้อน

คุณช่วยอธิบายความหมายของ "decouples การเป็นตัวแทนจากกระบวนการสร้างวัตถุที่ซับซ้อน" ได้
ไหม

3

การก่อสร้างที่ซับซ้อนคือเมื่อวัตถุที่จะสร้างประกอบด้วยวัตถุอื่น ๆ ที่แตกต่างกันซึ่งแสดงโดย abstractions

พิจารณาเมนูใน McDonald's เมนูประกอบด้วยเครื่องดื่มหลักและด้านข้าง ขึ้นอยู่กับว่าทายาทของแต่ละ abstractions ประกอบด้วยกันเมนูที่สร้างขึ้นมีการแสดงอื่น

  1. ตัวอย่าง: Cola, Big Mac, French Fries
  2. ตัวอย่าง: สไปรต์นักเก็ตหยิกทอด

ที่นั่นเรามีสองอินสแตนซ์ของเมนูที่มีการนำเสนอที่แตกต่างกัน กระบวนการของการก่อสร้างในทางกลับกันยังคงเหมือนเดิม คุณสร้างเมนูด้วยเครื่องดื่มหลักและด้านข้าง

โดยใช้รูปแบบตัวสร้างคุณแยกอัลกอริทึมของการสร้างวัตถุที่ซับซ้อนจากส่วนประกอบต่าง ๆ ที่ใช้ในการสร้าง

ในแง่ของรูปแบบการสร้างอัลกอริทึมถูกห่อหุ้มในผู้อำนวยการในขณะที่ผู้สร้างจะใช้ในการสร้างส่วนที่สำคัญ การเปลี่ยนแปลงตัวสร้างที่ใช้ในอัลกอริทึมของผลการกำกับจะให้ผลลัพธ์ที่แตกต่างเนื่องจากชิ้นส่วนอื่น ๆ ประกอบไปด้วยเมนู วิธีการสร้างเมนูยังคงเหมือนเดิม


1
สิ่งนี้อธิบายถึง "การแยกการก่อสร้างวัตถุที่ซับซ้อนจากการเป็นตัวแทน"
Rajdeep

2

ความแตกต่างที่สำคัญระหว่างพวกเขาก็คือรูปแบบการสร้างหลักอธิบายถึงการสร้างวัตถุที่ซับซ้อนทีละขั้นตอน ในรูปแบบโรงงานบทคัดย่อเน้นอยู่ในครอบครัวของวัตถุผลิตภัณฑ์ สร้างผลตอบแทนที่ผลิตภัณฑ์ในขั้นตอนสุดท้าย ในขณะที่รูปแบบโรงงานบทคัดย่อผลิตภัณฑ์ที่เป็นใช้ได้ทันที

ตัวอย่าง: สมมติว่าเรากำลังสร้างเขาวงกต

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();
}

2

ฉันเชื่อว่าการใช้งานและความแตกต่างระหว่างรูปแบบของโรงงานและตัวสร้างสามารถเข้าใจ / ทำให้เข้าใจง่ายขึ้นในช่วงระยะเวลาหนึ่งขณะที่คุณทำงานบนฐานรหัสเดียวกันและข้อกำหนดที่เปลี่ยนแปลง

จากประสบการณ์ของฉันคุณมักจะเริ่มต้นด้วยรูปแบบของโรงงานรวมถึงวิธีการสร้างแบบสแตติกสองวิธีเพื่อซ่อนตรรกะการเริ่มต้นที่ค่อนข้างซับซ้อน เมื่อลำดับชั้นวัตถุของคุณซับซ้อนมากขึ้น (หรือเมื่อคุณเพิ่มประเภทพารามิเตอร์มากขึ้น) คุณอาจต้องใช้วิธีการของคุณที่มีพารามิเตอร์มากขึ้นและไม่ต้องพูดถึงว่าคุณจะต้องคอมไพล์โมดูลโรงงานของคุณอีกครั้ง สิ่งเหล่านั้นทั้งหมดเพิ่มความซับซ้อนของวิธีการสร้างลดความสามารถในการอ่านและทำให้โมดูลการสร้างมีความบอบบางมากขึ้น

จุดนี้อาจเป็นจุดเปลี่ยน / ขยาย โดยการทำเช่นนั้นคุณจะสร้างโมดูล wrapper รอบ ๆพารามิเตอร์การก่อสร้างจากนั้นคุณจะสามารถแสดงวัตถุใหม่ (ที่คล้ายกัน) โดยการเพิ่ม abstractions (อาจ) และการใช้งานเพิ่มเติมโดยไม่ต้องสัมผัสตรรกะการสร้างจริงของคุณ คุณมีตรรกะที่ซับซ้อน "น้อยลง"

"การมีวัตถุที่สร้างขึ้นในขั้นตอนเดียวหรือหลายขั้นตอนคือความแตกต่าง" เนื่องจากปัจจัยความหลากหลายเพียงอย่างเดียวนั้นไม่เพียงพอสำหรับฉันที่จะแยกแยะพวกเขาเนื่องจากฉันสามารถใช้ทั้งสองวิธีสำหรับเกือบทุกกรณีที่ฉันเผชิญ ตอนนี้โดยไม่ได้รับประโยชน์ใด ๆ ดังนั้นนี่คือสิ่งที่ฉันคิดในที่สุด


2

ข้อได้เปรียบหลักของรูปแบบตัวสร้างเหนือรูปแบบจากโรงงานคือในกรณีที่คุณต้องการสร้างวัตถุมาตรฐานที่มีการปรับแต่งที่เป็นไปได้มากมาย

ตัวอย่างเช่นหากคุณต้องการเขียนไคลเอ็นต์ 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 อื่น ๆ เหล่านั้นทั้งหมด


1

รูปแบบการสร้างเน้นความซับซ้อน ของการสร้างวัตถุ (แก้ไขโดย "ขั้นตอน")

รูปแบบนามธรรมเน้น "เพียงแค่" กับ "นามธรรม" ของวัตถุ (หลายรายการ แต่เกี่ยวข้อง)


1

ความแตกต่างชัดเจนในตัวสร้างรูปแบบตัวสร้างจะสร้างวัตถุชนิดเฉพาะสำหรับคุณ คุณต้องบอกผู้สร้างว่าต้องสร้างอะไร ในรูปแบบโรงงานโดยใช้คลาสนามธรรมคุณกำลังสร้างวัตถุเฉพาะโดยตรง

ที่นี่ตัวสร้างคลาสทำหน้าที่เป็นสื่อกลางระหว่างคลาสหลักและคลาสชนิดเฉพาะ สิ่งที่เป็นนามธรรมมากขึ้น


1

ทั้งคู่มีลักษณะคล้ายกันมาก แต่ถ้าคุณมีพารามิเตอร์จำนวนมากสำหรับการสร้างวัตถุโดยมีพารามิเตอร์บางตัวเลือกที่มีค่าเริ่มต้นให้ไปสำหรับรูปแบบตัวสร้าง


1

IMHO

ช่างก่อสร้างเป็นโรงงานที่ซับซ้อนกว่านี้

แต่ในตัวสร้างคุณสามารถยกตัวอย่างวัตถุด้วยการใช้โรงงานอื่นซึ่งจะต้องสร้างวัตถุขั้นสุดท้ายและถูกต้อง

ดังนั้นการพูดคุยเกี่ยวกับวิวัฒนาการ "รูปแบบ Creational" โดยความซับซ้อนที่คุณสามารถคิดเกี่ยวกับมันด้วยวิธีนี้:

Dependency Injection Container -> Service Locator -> Builder -> Factory

1

ทั้งสองรูปแบบมีความจำเป็นเช่นเดียวกัน: ซ่อนจากบางรหัสไคลเอนต์ตรรกะการก่อสร้างของวัตถุที่ซับซ้อน แต่อะไรทำให้ "ซับซ้อน" (หรือบางครั้งซับซ้อน) วัตถุ? ส่วนใหญ่เป็นเพราะการพึ่งพาหรือมากกว่าสถานะของวัตถุที่ประกอบด้วยรัฐบางส่วนมากขึ้น คุณสามารถฉีดการพึ่งพาโดยนวกรรมิกเพื่อตั้งค่าสถานะวัตถุเริ่มต้น แต่วัตถุอาจต้องการมากของพวกเขาบางคนจะอยู่ในสถานะเริ่มต้นเริ่มต้น (เพียงเพราะเราควรได้เรียนรู้ว่าการตั้งค่าเริ่มต้นเป็นโมฆะไม่ใช่วิธีที่สะอาดที่สุด ) และชุดอื่น ๆ ให้อยู่ในสภาพที่ได้รับการขับเคลื่อนโดยเงื่อนไขบางอย่าง นอกจากนี้ยังมีคุณสมบัติของวัตถุที่เป็น "การพึ่งพาที่หลงลืม" บางชนิด แต่พวกมันยังสามารถสมมติสถานะทางเลือกได้

มีสองวิธีที่รู้จักกันดีในการควบคุมความซับซ้อนนั้น:

  • การประพันธ์ / การรวม: สร้างวัตถุสร้างวัตถุที่ขึ้นต่อกันจากนั้นจึงโยงเข้าด้วยกัน ผู้สร้างสามารถสร้างกระบวนการที่โปร่งใสและยืดหยุ่นซึ่งกำหนดกฎที่นำไปสู่การสร้างส่วนประกอบ

  • ความแตกต่าง: กฎการก่อสร้างจะประกาศโดยตรงในคำจำกัดความของประเภทย่อยดังนั้นคุณจึงมีชุดของกฎสำหรับแต่ละประเภทย่อยและเงื่อนไขบางอย่างตัดสินใจว่าจะใช้กฎใดในกลุ่มชุดของกฎเหล่านี้เพื่อสร้างวัตถุ โรงงานเข้ากันได้อย่างสมบูรณ์แบบในสถานการณ์นี้

ไม่มีอะไรป้องกันไม่ให้ผสมสองแนวทางนี้ ตระกูลของผลิตภัณฑ์สามารถสร้างวัตถุนามธรรมที่สร้างขึ้นด้วยตัวสร้างผู้สร้างสามารถใช้โรงงานเพื่อกำหนดว่าวัตถุชิ้นส่วนยกตัวอย่าง


0

ในความคิดของฉันรูปแบบตัวสร้างจะใช้เมื่อคุณต้องการสร้างวัตถุจากเครือวัตถุอื่นและการสร้างชิ้นส่วนจำเป็นต้องเป็นอิสระจากวัตถุที่คุณต้องการสร้าง ช่วยในการซ่อนการสร้างชิ้นส่วนจากลูกค้าเพื่อให้ผู้สร้างและลูกค้าเป็นอิสระ มันถูกใช้สำหรับการสร้างวัตถุที่ซับซ้อน (วัตถุซึ่งอาจประกอบด้วยคุณสมบัติที่ซับซ้อน)

ในขณะที่รูปแบบจากโรงงานระบุว่าคุณต้องการสร้างวัตถุของครอบครัวทั่วไปและคุณต้องการให้มันถูกชุบทันที มันใช้สำหรับวัตถุที่ง่ายกว่า


0

โรงงานผู้สร้างและบทคัดย่อ

รูปแบบการออกแบบ Builder จะคล้ายกันมากกับรูปแบบ Abstract Factory ด้วยเหตุนี้จึงเป็นสิ่งสำคัญที่จะต้องสามารถสร้างความแตกต่างระหว่างสถานการณ์เมื่อมีการใช้อย่างใดอย่างหนึ่ง ในกรณีของ Abstract Factory ลูกค้าใช้วิธีการของโรงงานเพื่อสร้างวัตถุของตัวเอง ในกรณีของตัวสร้างคลาสตัวสร้างจะได้รับคำแนะนำเกี่ยวกับวิธีสร้างวัตถุและจากนั้นจะถูกถาม แต่วิธีการที่คลาสจะรวมกันนั้นขึ้นอยู่กับคลาสของตัวสร้างรายละเอียดนี้สร้างความแตกต่างระหว่างสองรูปแบบ

อินเตอร์เฟสทั่วไปสำหรับผลิตภัณฑ์

ในทางปฏิบัติผลิตภัณฑ์ที่สร้างโดยผู้สร้างคอนกรีตมีโครงสร้างที่แตกต่างกันอย่างมีนัยสำคัญดังนั้นหากไม่มีเหตุผลที่จะได้รับผลิตภัณฑ์ที่แตกต่างกันในระดับผู้ปกครองทั่วไป สิ่งนี้ยังแยกความแตกต่างของรูปแบบตัวสร้างจากรูปแบบนามธรรมจากโรงงานซึ่งสร้างวัตถุที่ได้มาจากประเภททั่วไป

จาก: http://www.oodesign.com/builder-pattern.html


-2

รูปแบบของโรงงานสร้างการใช้งานอย่างเป็นรูปธรรมของคลาสที่รันไทม์นั่นคือความตั้งใจหลักคือการใช้ความหลากหลายเพื่อให้คลาสย่อยตัดสินใจว่าคลาสใดจะสร้างอินสแตนซ์ ซึ่งหมายความว่าในเวลารวบรวมเราไม่ทราบคลาสที่แน่นอนที่จะถูกสร้างขึ้นในขณะที่รูปแบบการสร้างส่วนใหญ่เกี่ยวข้องกับการแก้ปัญหาของ antipattern ตัวสร้าง telescoping ซึ่งเกิดขึ้นเนื่องจากฟิลด์จำนวนมากของคลาส ในรูปแบบการสร้างไม่มีความคิดของความหลากหลายในขณะที่เรารู้ว่าสิ่งที่เรากำลังพยายามที่จะสร้างในเวลารวบรวม

ชุดรูปแบบทั่วไปเพียงอย่างเดียวของทั้งสองรูปแบบคือการซ่อนตัวสร้างและการสร้างวัตถุที่อยู่เบื้องหลังวิธีการของโรงงานและวิธีการสร้างเพื่อปรับปรุงการสร้างวัตถุ


-2

รูปแบบจากโรงงานช่วยให้คุณสามารถสร้างวัตถุได้ในคราวเดียวในขณะที่รูปแบบของตัวสร้างช่วยให้คุณสามารถทำลายกระบวนการสร้างของวัตถุ ด้วยวิธีนี้คุณสามารถเพิ่มฟังก์ชันการทำงานที่แตกต่างกันระหว่างการสร้างวัตถุ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.