อะไรคือความแตกต่างพื้นฐานระหว่างรูปแบบการออกแบบจากโรงงานและบทคัดย่อ? [ปิด]


483

อะไรคือความแตกต่างพื้นฐานระหว่างรูปแบบโรงงานและรูปแบบนามธรรม?


11
ในความคิดของฉันคุณภาพของคำตอบในความแตกต่างระหว่างรูปแบบนามธรรมจากโรงงานและวิธีการของโรงงานนั้นดีกว่าแบบที่นี่
KurzedMetal

1
ความแตกต่างที่สำคัญคือวิธีการของโรงงานใช้การสืบทอด (โดยอ้อมเป็นแนวตั้งเช่นcreateThing()) และบทคัดย่อจากโรงงานใช้การจัดองค์ประกอบ (โดยอ้อมเป็นแนวนอนเช่นgetFactory().createThing())
David James

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

คำตอบ:


412

ด้วยรูปแบบโรงงานคุณผลิตกรณีของการใช้งาน ( Apple, Banana, Cherryฯลฯ ) ของอินเตอร์เฟซที่โดยเฉพาะอย่างยิ่ง - IFruitพูด

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


5
@SPI ฉันคิดว่าคุณเข้าใจฉันผิด โรงงานตัวเองไม่จำเป็นต้องใช้IFruit- มัน instantiates IFruitสิ่งที่ดำเนินการ แน่นอนว่าไม่จำเป็นต้องสร้างอินสแตนซ์ของสิ่งต่าง ๆ ที่ใช้อินเทอร์เฟซเฉพาะ แต่อาจเป็นกลิ่นรหัสหากคุณมี Factory ที่สร้างสิ่งที่ไม่เกี่ยวข้องกันโดยสิ้นเชิง
John Feminella

75
โรงงานที่ผลิตโรงงาน เราต้องไปกันลึก ...
พอลแอนน์คอฟ

11
ไม่เคยได้ยินอะไรผิดพลาดไปกว่านี้ คุณจะเรียกโรงงานที่ผลิตอินเทอร์เฟซของโรงงานนามธรรม (IAbstractFactory) ว่าอะไร - อาฉันเห็นแล้วว่าจะเป็นบทคัดย่อ
โรงงานกวางโจว

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

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

142

แหล่งข้อมูลนี้นำมาจาก: http://java.dzone.com/news/intro-design-patterns-abstract

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

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

รูปแบบโรงงานนามธรรมประกอบด้วย AbstractFactory, ConcreteFactory, AbstractProduct, ConcreteProduct และลูกค้า

วิธีการใช้งาน

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

รูปแบบวิธีการจากโรงงานเป็นรูปแบบย่อของรูปแบบนามธรรมจากโรงงาน รูปแบบวิธีการของโรงงานมีหน้าที่รับผิดชอบในการสร้างผลิตภัณฑ์ที่เป็นของตระกูลเดียวกันในขณะที่รูปแบบนามธรรมจากโรงงานเกี่ยวข้องกับผลิตภัณฑ์หลายตระกูล

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

เมื่อใดจึงจะใช้รูปแบบวิธีการจากโรงงาน

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

เมื่อใดจึงจะใช้รูปแบบนามธรรมจากโรงงาน

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

ตัวอย่าง:

บทคัดย่อจากโรงงานตัวอย่าง 1

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

บทคัดย่อจากโรงงานตัวอย่างที่ 2:

อุปกรณ์ปั๊มที่สอดคล้องกับโรงงานนามธรรมเนื่องจากเป็นอินเตอร์เฟสสำหรับการดำเนินการที่สร้างวัตถุผลิตภัณฑ์นามธรรม แม่พิมพ์นั้นสอดคล้องกับโรงงานคอนกรีตในขณะที่พวกเขาสร้างผลิตภัณฑ์คอนกรีต หมวดชิ้นส่วนแต่ละชิ้น (ฮูด, ประตู ฯลฯ ) สอดคล้องกับผลิตภัณฑ์นามธรรม ชิ้นส่วนเฉพาะ (เช่นประตูด้านคนขับสำหรับ 99 คัมรี่) สอดคล้องกับผลิตภัณฑ์คอนกรีต

ตัวอย่างวิธีการจากโรงงาน:

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


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

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

โค้ดตัวอย่าง @ sourcemaking.com/design_patterns/abstract_factory
pramodc84

ตัวอย่างองค์ประกอบ: ไคลเอ็นต์ระดับสาธารณะ {ผลิตภัณฑ์ AbstractProduct; อุปกรณ์เสริม ไคลเอ็นต์สาธารณะ (โรงงาน AbstractFactory) {AbstractProduct ผลิตภัณฑ์ = factory.createProduct (); } public void run () {product.print (); อุปกรณ์เสริม = product.getAccessories (); }}
Asim Ghaffar

เป็นไปได้หรือไม่ที่จะตรวจจับในโค้ดซึ่งรูปแบบสองรูปแบบนี้ใช้
Warlock

98

รูปแบบของโรงงาน: โรงงานผลิต IProduct-implementations

บทคัดย่อรูปแบบโรงงาน: โรงงาน - โรงงานผลิต IFactories ซึ่งจะผลิต IProducts :)

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


4
ดี! ถูกต้องหรือไม่ที่จะบอกว่า Abstract Factory เป็นชุดของวิธีการของโรงงาน
Warlock

2
ฉันเดาว่ามันจะถูกต้อง แต่ก็อาจพลาดประเด็น :) ตัวอย่างที่ไม่คล้ายคลึงกันอาจเป็น FileFactory ซึ่งมีวิธีเช่น CreateBitmapFile () หรือ CreateTextFile () ตอนนี้คุณจะส่งการอ้างอิงไปยังโรงงานนั้นในบริการบางประเภท แต่จะเกิดอะไรขึ้นเมื่อคุณต้องการทดสอบบริการของคุณ คุณจะต้องสร้างอินเตอร์เฟส IFileFactory เพื่อจำลองการเข้าถึงระบบไฟล์ ตอนนี้ในโลกแห่งความเป็นจริงคุณอาจจะมีกรอบ DI / IoC ที่จะยกตัวอย่าง IFileFactories ขึ้นอยู่กับความต้องการของคุณ ในกรณีนี้กรอบ IoC จะทำหน้าที่เป็นโรงงานที่เป็นนามธรรม
cwap

5
หากฉันเข้าใจอย่างถูกต้องคำตอบนี้ดูเหมือนจะบอกเป็นนัยว่า Abstract Factory จะสร้าง IFactories เพิ่มเติมซึ่งสามารถนำไปใช้เพื่อสร้าง IProducts ได้ งานนำเสนอใน GoF ไม่ปรากฏขึ้นให้ฉันสนับสนุนสิ่งนี้และในความเป็นจริงขัดแย้งกับมัน: ตัวอย่างของ Abstract Factory สร้าง IProducts โดยตรง กล่าวอีกนัยหนึ่ง GoF Abstract Factory ไม่ได้ (หรือมากกว่านั้นไม่จำเป็นต้องเป็น ) "โรงงานโรงงาน"
SSJ_GZ

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

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

42

รูปแบบโรงงานนามธรรม

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

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

  • ที่จริงแล้ววัตถุที่ได้รับการแต่งตั้งมักใช้วิธีการจากโรงงานเพื่อทำอินสแตนซ์!

รูปแบบโรงงาน

  • รูปแบบของโรงงานเป็นตัวอย่างของรูปแบบการสร้างสรรค์

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

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

  • รูปแบบการสร้างวัตถุมุ่งเน้นไปที่การมอบหมายการสร้างอินสแตนซ์ไปยังวัตถุอื่นบทคัดย่อโรงงาน

อ้างอิง: Factory vs Abstract Factory


3
ลิงค์อ้างอิงนั้นตายแล้ว
mkobit

39

วิธีการจากโรงงาน:คุณมีโรงงานที่สร้างวัตถุที่ได้มาจากคลาสพื้นฐานเฉพาะ

บทคัดย่อจากโรงงาน:คุณมีโรงงานที่สร้างโรงงานอื่นและโรงงานเหล่านี้จะสร้างวัตถุที่ได้มาจากคลาสพื้นฐาน คุณทำเช่นนี้เพราะคุณมักจะไม่เพียงต้องการสร้างวัตถุเดียว (เช่นเดียวกับวิธีโรงงาน) แต่คุณต้องการสร้างคอลเลกชันของวัตถุที่เกี่ยวข้อง


6
นี่เป็นคำตอบที่ซ้ำกันและไม่ถูกต้องเท่ากัน
jaco0646

36

Abstract factory เป็นอินเตอร์เฟสสำหรับการสร้างวัตถุที่เกี่ยวข้อง แต่วิธีโรงงานเป็นวิธีการ บทคัดย่อโรงงานจะดำเนินการโดยวิธีโรงงาน

ป้อนคำอธิบายรูปภาพที่นี่


36

ความแตกต่างพื้นฐาน:

โรงงาน:สร้างวัตถุโดยไม่ต้องเปิดเผยตรรกะการสร้างอินสแตนซ์ให้กับลูกค้า

วิธีการโรงงาน : กำหนดอินเทอร์เฟซสำหรับการสร้างวัตถุ แต่ให้คลาสย่อยตัดสินใจว่าคลาสใดจะสร้างอินสแตนซ์ เมธอด Factory อนุญาตให้คลาสเลื่อนการอินสแตนซ์ไปที่คลาสย่อย

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

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

จาก บทความoodesign :

แผนภาพระดับโรงงาน :

ป้อนคำอธิบายรูปภาพที่นี่

ตัวอย่าง: StaticFactory

 public class ShapeFactory {

   //use getShape method to get object of type shape 
   public static Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }     
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();

      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();

      } else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }

      return null;
   }
}

โรงงานแบบคงที่การใช้งาน FactoryMethod ตัวอย่างมีให้ในโพสต์นี้:

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

ควรใช้เมื่อใด:ลูกค้าเพียงแค่ต้องการเรียนและไม่สนใจว่าการใช้งานที่เป็นรูปธรรมนั้นจะได้รับ

วิธีการระดับโรงงาน digaram:

ป้อนคำอธิบายรูปภาพที่นี่

ควรใช้เมื่อใด:ไคลเอนต์ไม่ทราบว่าจะต้องมีคลาสรูปธรรมใดในการสร้างที่รันไทม์ แต่ต้องการรับคลาสที่จะทำงาน

บทคัดย่อแผนภาพระดับโรงงานจาก dzone

ป้อนคำอธิบายรูปภาพที่นี่

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

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

คำถาม SE ที่เกี่ยวข้องพร้อมตัวอย่างรหัส:

รูปแบบโรงงาน จะใช้วิธีการจากโรงงานเมื่อใด

แตกต่าง:

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

บทความที่มีประโยชน์อื่น ๆ :

factory_methodจากการสร้างแหล่งที่มา

abstract_factoryจากแหล่งที่มาทำ

รูปแบบนามธรรมการออกแบบโรงงานจาก journaldev


21

ตัวอย่าง / สถานการณ์สำหรับ Abstract Factory

ฉันอาศัยอยู่ในสถานที่ที่ฝนตกในฤดูฝนหิมะในฤดูหนาวและมีแดดจัดในฤดูร้อน ฉันต้องการเสื้อผ้าประเภทต่าง ๆ เพื่อปกป้องตัวเองจากองค์ประกอบ เมื่อต้องการทำเช่นนั้นฉันไปที่ร้านใกล้บ้านของฉันและขอเสื้อผ้า / รายการเพื่อป้องกันตัวเอง ผู้ดูแลร้านให้ฉันรายการที่เหมาะสมตามสภาพแวดล้อมและความลึกของกระเป๋าของฉัน สินค้าที่เขาให้ฉันมีคุณภาพและระดับราคาเท่ากัน เนื่องจากเขาตระหนักถึงมาตรฐานของฉันมันง่ายสำหรับเขาที่จะทำ แต่เมื่อคนรวยจากฝั่งตรงข้ามมาด้วยข้อกำหนดเดียวกันเขาจะได้รับของมีราคาแพงและเป็นแบรนด์ สิ่งหนึ่งที่เห็นได้ชัดเจนคือสิ่งของทุกชิ้นที่เขามอบให้กับฉันเพื่อเสริมซึ่งกันและกันในด้านคุณภาพมาตรฐานและค่าใช้จ่าย หนึ่งสามารถพูดได้ว่าพวกเขาไปด้วยกัน เป็นกรณีเดียวกันกับรายการที่คนรวยคนนี้ได้รับ

ดังนั้นจากการดูสถานการณ์ข้างต้นตอนนี้ฉันขอขอบคุณประสิทธิภาพของผู้ดูแลร้าน ฉันสามารถแทนที่เจ้าของร้านนี้ด้วย Abstract Shop รายการที่เราได้รับด้วยรายการนามธรรมและฉันและอุดมไปด้วยลูกค้ามุมมอง ทั้งหมดที่เราต้องการคือผลิตภัณฑ์ / รายการที่เหมาะสมกับความต้องการของเรา

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

ถ้าฉันมีโอกาสสร้างบางอย่างเช่นเว็บไซต์นี้ฉันจะพิจารณารูปแบบนามธรรมจากโรงงานแน่นอน

ผลิตภัณฑ์ที่เป็นนามธรรม: บานหน้าต่างโฆษณา, เมนู, จิตรกร UI
บทคัดย่อจากโรงงาน: ประสบการณ์ผู้ใช้เว็บสโตร์
เชื่อมโยงโรงงาน: ประสบการณ์ผู้ใช้ระดับพรีเมียมประสบการณ์ผู้ใช้ทองคำประสบการณ์ผู้ใช้ทั่วไป


AbstractFactory เป็นสถานการณ์ที่ดี แต่คุณไม่ได้ตอบคำถามจริง ๆ โรงงานและโรงงานนามธรรมต่างกันอย่างไร
Adelin

20

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

เริ่มจากข้อเท็จจริงที่ว่าไม่มีรูปแบบที่เป็นรูปธรรมที่เรียกว่า "โรงงาน" มีรูปแบบที่เรียกว่า "Abstract Factory" และมีรูปแบบที่เรียกว่า "Factory Method"

ดังนั้น "โรงงาน" หมายความว่าอย่างไร ข้อใดข้อหนึ่งต่อไปนี้ (ทั้งหมดสามารถพิจารณาได้ว่าถูกต้องขึ้นอยู่กับขอบเขตของการอ้างอิง):

  • บางคนใช้เป็นนามแฝง (ทางลัด) สำหรับ " Abstract Factory "
  • บางคนใช้เป็นนามแฝง (ทางลัด) สำหรับ " วิธีการจากโรงงาน "
  • บางคนใช้เป็นชื่อทั่วไปสำหรับรูปแบบโรงงาน / สร้างสรรค์ เช่น "Abstract Factory" และ "Method Factory" เป็นโรงงาน

และน่าเสียดายที่หลายคนใช้ "โรงงาน" เพื่อแสดงว่าเป็นโรงงานประเภทอื่นที่สร้างโรงงานหรือโรงงาน (หรืออินเทอร์เฟซ) ตามทฤษฎีของพวกเขา:

ผลิตภัณฑ์ใช้ IProduct ซึ่งสร้างโดยโรงงานซึ่งใช้ IFactory ซึ่งสร้างโดย AbstractFactory

เพื่อให้เข้าใจว่าสิ่งนี้โง่แค่ไหนลองทำสมการของเราต่อไป:

AbstractFactory ดำเนินการ IAbstractFactory ซึ่งสร้างโดย ... AbstractAbstractFactory ???

ฉันหวังว่าคุณจะเห็นประเด็น อย่าสับสนและโปรดอย่าประดิษฐ์สิ่งที่ไม่มีเหตุผล

-

PS : โรงงานสำหรับผลิตภัณฑ์คือ AbstractFactory และโรงงานสำหรับโรงงานบทคัดย่อก็เป็นอีกตัวอย่างหนึ่งของ AbstractFactory เช่นกัน


ฉันจะแยกความแตกต่างระหว่าง AbstractFactory ซึ่งสร้าง AbstractFactories อื่นจาก AbstractFactory ซึ่งสร้างวัตถุเฉพาะได้อย่างไร GenericAbstractFactory? หรือ AbstractFactoryFactory?
Andrew

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

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

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

16
//Abstract factory - Provides interface to create factory of related products
interface PizzaIngredientsFactory{    
   public Dough createDough(); //Will return you family of Dough
   public Clam createClam();   //Will return you family of Clam
   public Sauce createSauce(); //Will return you family of Sauce
}

class NYPizzaIngredientsFactory implements PizzaIngredientsFactory{

   @Override
   public Dough createDough(){
      //create the concrete dough instance that NY uses
      return doughInstance;
   }

   //override other methods
} 

คำตอบอื่น ๆ มีคำจำกัดความของหนังสือตำราเรียนอยู่แล้ว ฉันคิดว่าฉันจะให้ตัวอย่างมันด้วย

ดังนั้นที่นี่PizzaIngredientsFactoryเป็นโรงงานนามธรรมเพราะมีวิธีการสร้างตระกูลของผลิตภัณฑ์ที่เกี่ยวข้อง

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

วิธีการโรงงาน

แสดงตัวอย่างการใช้งานที่เป็นรูปธรรม

ในตัวอย่าง:
- createDough()- ให้การใช้งานที่เป็นรูปธรรมสำหรับแป้ง นี่คือวิธีการของโรงงาน

โรงงานบทคัดย่อ

จัดเตรียมส่วนต่อประสานเพื่อสร้างตระกูลของวัตถุที่เกี่ยวข้อง

ในตัวอย่าง:
- PizzaIngredientsFactoryเป็นโรงงานที่เป็นนามธรรมที่มันช่วยให้การสร้างชุดที่เกี่ยวข้องของวัตถุที่ชอบDough, ,Clams Sauceสำหรับการสร้างวัตถุแต่ละตระกูลมันมีวิธีการจากโรงงาน

ตัวอย่างจากรูปแบบการออกแบบ Head First


5

ฉันมีบางจุดที่จะมีส่วนร่วมกับคำตอบของจอห์นดังนี้:

โรงงานนามธรรมเป็นโรงงานของโรงงาน!

กับ "โรงงานวิธี" (เพราะเพียงแค่ "โรงงาน" ไม่ชัดเจน), คุณผลิตการใช้งาน ( Lemon, Orangeฯลฯ ) ของอินเตอร์เฟซที่โดยเฉพาะอย่างยิ่ง - IFruitพูด CitricFruitFactoryโรงงานนี้อาจจะเรียกว่า

แต่ตอนนี้คุณต้องการสร้างผลไม้ชนิดอื่นที่ CitricFruitFactory ไม่สามารถสร้างได้ บางทีรหัสของCitricFruitFactoryจะไม่สมเหตุสมผลถ้าคุณสร้างStrawberryในนั้น (สตรอเบอร์รี่ไม่ได้เป็นผลไม้มะนาว!)

เพื่อให้คุณสามารถสร้างโรงงานใหม่ที่เรียกว่าRedFruitFactoryที่ผลิตStrawberry, Raspberryฯลฯ

เช่นเดียวกับ John Feminella กล่าวว่า: "ด้วยรูปแบบนามธรรมจากโรงงานคุณสามารถสร้างการใช้งานอินเทอร์เฟซของโรงงานเฉพาะ - เช่นIFruitFactoryแต่ละคนรู้วิธีสร้างผลไม้ชนิดต่าง ๆ "

การใช้งานของที่IFruitFactoryมีCitricFruitFactoryและRedFruitFactory!


4

แหล่งที่มาของฉัน: StackOverflow, tutorialspoint.com, และprogrammers.stackexchange.comCodeProject.com


Factory Method(เรียกอีกอย่างว่าFactory) มีไว้สำหรับลูกค้าที่แยกกลุ่มInterfaceการใช้งาน สำหรับตัวอย่างเรามีShapeอินเตอร์เฟสที่มีสองตัวCircleและSquareการใช้งาน เราได้กำหนดคลาสโรงงานด้วยวิธีโรงงานพร้อมพารามิเตอร์ดีเทอร์เนอร์เช่นTypeและการใช้Shapeอินเทอร์เฟซใหม่ที่เกี่ยวข้อง


Abstract Factoryมีวิธีการที่โรงงานหลายแห่งหรืออินเตอร์เฟซที่โรงงานโดยการใช้งานหลายโรงงาน สำหรับตัวอย่างข้างต้นถัดไปเรามีColorส่วนต่อประสานที่มีสองตัวRedและYellowการใช้งาน เรามีกำหนดShapeColorFactoryอินเตอร์เฟซกับสองและRedCircleFactory YellowSquareFactoryรหัสต่อไปนี้เพื่ออธิบายแนวคิดนี้:

interface ShapeColorFactory
{
    public Shape getShape();
    public Color getColor();
}

class RedCircleFactory implements ShapeColorFactory
{
    @Override
    public Shape getShape() {
        return new Circle();
    }

    @Override
    public Color getColor() {
        return new Red();
    }
}
class YellowSquareFactory implements ShapeColorFactory
{
    @Override
    public Shape getShape() {
        return new Square();
    }

    @Override
    public Color getColor() {
        return new Yellow();
    }
} 

ที่นี่แตกต่างระหว่างและFactoryMethod เพียงแค่ส่งคืนคลาสคอนกรีตของอินเทอร์เฟซ แต่คืนค่า กล่าวอีกนัยหนึ่งคือการรวมชุดของอินเตอร์เฟสที่ต่างกันAbstractFactoryFactory MethodAbstract Factoryfactory of factoryAbstract Factory


ฉันหวังว่าคำอธิบายของฉันจะเป็นประโยชน์


3

ความแตกต่างที่สำคัญในโรงงานเหล่านั้นคือเมื่อคุณต้องการทำอะไรกับโรงงานและเมื่อคุณต้องการใช้

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

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

ดังนั้นฉันคิดว่ามันยังเกี่ยวกับอายุการใช้งานและการสร้างวัตถุด้วย


3

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

Factory Methodคือการสืบทอดใน subclasses ในการสร้างวัตถุคอนกรีต (ผลิตภัณฑ์) ในขณะที่Abstract Factoryให้อินเตอร์เฟซสำหรับการสร้างครอบครัวของผลิตภัณฑ์ที่เกี่ยวข้องและ subclass ของอินเตอร์เฟซเหล่านี้กำหนดวิธีการที่จะสร้างผลิตภัณฑ์ที่เกี่ยวข้อง

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


3

คำตอบที่ขยายจาก John Feminella:

Apple, Banana, CherryการดำเนินการFruitFactoryและที่มีวิธีการที่เรียกว่าCreateซึ่งเป็นผู้รับผิดชอบ แต่เพียงผู้เดียวในการสร้างแอปเปิ้ลหรือกล้วยหรือเชอร์รี่ คุณทำเสร็จแล้วด้วยFactoryวิธีการของคุณ

ตอนนี้คุณต้องการCreateสลัดพิเศษจากผลไม้ของคุณและมีบทคัดย่อจากโรงงานของคุณ Abstract Factory รู้วิธีสร้างสลัดพิเศษของคุณจาก Apple, Banana และ Cherry

public class Apple implements Fruit, FruitFactory {
    public Fruit Create() {
        // Apple creation logic goes here
    }
}

public class Banana implements Fruit, FruitFactory {
    public Fruit Create() {
        // Banana creation logic goes here
    }
}

public class Cherry implements Fruit, FruitFactory {
    public Fruit Create() {
        // Cherry creation logic goes here
    }
}

public class SpecialSalad implements Salad, SaladFactory {
    public static Salad Create(FruitFactory[] fruits) {
        // loop through the factory and create the fruits.
        // then you're ready to cut and slice your fruits 
        // to create your special salad.
    }
}

2

ตามคำจำกัดความเราสามารถลากความแตกต่างของสอง:

Factory: อินเตอร์เฟสใช้สำหรับสร้างวัตถุ แต่คลาสย่อยตัดสินใจว่าคลาสใดที่จะยกตัวอย่าง การสร้างวัตถุเสร็จสิ้นเมื่อจำเป็น

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

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

รูปแบบโรงงาน:

public interface IFactory{
  void VehicleType(string n);
 }

 public class Scooter : IFactory{
  public void VehicleType(string n){
   Console.WriteLine("Vehicle type: " + n);
  }
 }

 public class Bike : IFactory{
  public void VehicleType(string n) {
  Console.WriteLine("Vehicle type: " + n);
  }
 }

 public interface IVehicleFactory{
  IFactory GetVehicleType(string Vehicle);
 }

 public class ConcreteVehicleFactory : IVehicleFactory{
 public IFactory GetVehicleType(string Vehicle){
   switch (Vehicle){
    case "Scooter":
     return new Scooter();
    case "Bike":
     return new Bike();
    default:
    return new Scooter();
  }
 }

 class Program{
  static void Main(string[] args){
   IVehicleFactory factory = new ConcreteVehicleFactory();
   IFactory scooter = factory.GetVehicleType("Scooter");
   scooter.VehicleType("Scooter");

   IFactory bike = factory.GetVehicleType("Bike");
   bike.VehicleType("Bike");

   Console.ReadKey();
 }
}

รูปแบบโรงงานนามธรรม:

interface IVehicleFactory{
 IBike GetBike();
 IScooter GetScooter();
}

class HondaFactory : IVehicleFactory{
     public IBike GetBike(){
            return new FZS();
     }
     public IScooter GetScooter(){
            return new FZscooter();
     }
 }
class HeroFactory: IVehicleFactory{
      public IBike GetBike(){
            return new Pulsur();
     }
      public IScooter GetScooter(){
            return new PulsurScooter();
     }
}

interface IBike
    {
        string Name();
    }
interface IScooter
    {
        string Name();
    }

class FZS:IBike{
   public string Name(){
     return "FZS";
   }
}
class Pulsur:IBike{
   public string Name(){
     return "Pulsur";
   }
}

class FZscooter:IScooter {
  public string Name(){
     return "FZscooter";
   }
}

class PulsurScooter:IScooter{
  public string Name(){
     return "PulsurScooter";
   }
}

enum MANUFACTURERS
{
    HONDA,
    HERO
}

class VehicleTypeCheck{
        IBike bike;
        IScooter scooter;
        IVehicleFactory factory;
        MANUFACTURERS manu;

        public VehicleTypeCheck(MANUFACTURERS m){
            manu = m;
        }

        public void CheckProducts()
        {
            switch (manu){
                case MANUFACTURERS.HONDA:
                    factory = new HondaFactory();
                    break;
                case MANUFACTURERS.HERO:
                    factory = new HeroFactory();
                    break;
            }

      Console.WriteLine("Bike: " + factory.GetBike().Name() + "\nScooter: " +      factory.GetScooter().Name());
        }
  }

class Program
    {
        static void Main(string[] args)
        {
            VehicleTypeCheck chk = new VehicleTypeCheck(MANUFACTURERS.HONDA);
            chk.CheckProducts();

            chk= new VehicleTypeCheck(MANUFACTURERS.HERO);
            chk.CheckProducts();

            Console.Read();
        }
    }

1

ตรวจสอบที่นี่: http://www.allapplabs.com/java_design_patterns/abstract_factory_pattern.htm ดูเหมือนว่าวิธี Factory ใช้คลาสเฉพาะ (ไม่ใช่นามธรรม) เป็นคลาสพื้นฐานในขณะที่ Abstract Factory ใช้คลาสนามธรรมสำหรับสิ่งนี้ นอกจากนี้หากใช้อินเทอร์เฟซแทนคลาสนามธรรมผลลัพธ์จะเป็นการใช้รูปแบบ Abstract Factory ที่แตกต่างกัน

: D


1

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


1

ฉันคิดว่าเราสามารถเข้าใจความแตกต่างระหว่างสองสิ่งนี้ด้วยการดูโค้ดตัวอย่าง Java8:

  interface Something{}

  interface OneWhoCanProvideSomething {
     Something getSomething();
  }

  interface OneWhoCanProvideCreatorsOfSomething{
     OneWhoCanProvideSomething getCreator();
  }


public class AbstractFactoryExample {

    public static void main(String[] args) {
        //I need something
        //Let's create one
        Something something = new Something() {};

        //Or ask someone (FACTORY pattern)
        OneWhoCanProvideSomething oneWhoCanProvideSomethingOfTypeA = () -> null;
        OneWhoCanProvideSomething oneWhoCanProvideSomethingOfTypeB = () -> null;

        //Or ask someone who knows soemone who can create something (ABSTRACT FACTORY pattern)
        OneWhoCanProvideCreatorsOfSomething oneWhoCanProvideCreatorsOfSomething = () -> null;

        //Same thing, but you don't need to write you own interfaces
        Supplier<Something> supplierOfSomething = () -> null;
        Supplier<Supplier<Something>> supplierOfSupplier = () -> null;
    }

}

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

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

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

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

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