รูปแบบของโรงงานละเมิดหลักการเปิด / ปิดหรือไม่?


14

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

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

การออกแบบ ShapeFactory


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


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

@ArmonSafai: คุณกำลังโพสต์บล็อกนี้มาก แต่คุณไม่ได้อธิบายว่าทำไม เราทุกคนต่างก็ไม่รู้รูปแบบหรือไม่? เรามี Google เหมือนกันกับคุณ
Robert Harvey

1
@RobertHarvey ฉันกำลังเชื่อมโยงโพสต์บล็อกนี้เพื่อแสดงว่ารูปแบบโรงงานในหน้านั้นใช้เงื่อนไขอย่างไร
Armon Safai

คำตอบ:


20

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

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

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


2
เป็นไปได้อย่างสมบูรณ์แบบในการสร้างรูปแบบโรงงานโดยไม่ต้องifs จำนวนมาก ดูคำตอบของ@BЈовићสำหรับตัวอย่างง่ายๆของการบรรลุสิ่งนี้ downvoted
David Arno


11
@DavidArno โดยธรรมชาติมีหลายวิธีในการเลือกชั้นเรียนคอนกรีต ตัวระบุบริการเป็นหนึ่งคอนเทนเนอร์ IoC ที่กำหนดค่าได้เป็นอีกหนึ่ง เหล่านี้เป็นเพียงรายละเอียดการใช้งาน พวกเขาไม่ได้เบี่ยงเบนความสนใจจากข้อความหลักของ Killian ซึ่งเป็นที่ Factory ช่วยบรรเทาผู้โทรไม่ให้ตัดสินใจว่าจะยกระดับคลาสใดขึ้นมา อย่าติดหล่มในรายละเอียด
Robert Harvey

1
คำสั่งที่ยอดเยี่ยมที่ไม่ตอบคำถาม
Martin Maat

1
@ R.Schmitz ฉันคิดว่าคุณคิดผิด ฉันคิดว่าหลายคนพลาดคำถามนี้จาก OP: "ไม่ต้องเปลี่ยน ShapeFactory ถ้าเราต้องการเพิ่มคลาสอื่น ๆ ในอนาคต" อย่างชัดเจน OP สับสนว่ารูปแบบนี้ละเมิด OCP เนื่องจากการเพิ่มฟังก์ชั่นใหม่คุณต้องแก้ไขโค้ดที่มีอยู่ คำตอบที่ถูกต้องสำหรับคำถามนี้อยู่ในคำตอบของฉัน คำตอบสั้น ๆ : คุณปล่อยให้รหัสนั้นอยู่คนเดียวและคุณใช้รูปแบบนามธรรมจากโรงงานเพื่อขยาย (ไม่แก้ไข) ฟังก์ชั่นที่มีอยู่ของคุณ เนื่องจากคำตอบของ Kilian นี้ไม่ได้ตอบคำถาม
hfontanez

5

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

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

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


คุณช่วยอธิบายวิธีการทำงานของ map / configuration / registry ได้อย่างไร?
Armon Safai

@ArmonSafai: นี่คือตัวอย่าง: jkfill.com/2010/12/29/self-registering-factories-in-c-sharp
JacquesB

AFAIK นั้นเป็นไปไม่ได้ใน C ++ ภายในไลบรารีแบบสแตติกเนื่องจากไม่ได้ใช้ตัวแปรระดับโลกที่ไม่ได้ใช้ (เช่นที่ใช้งานแบบ odr) ถูกทิ้งโดยเครื่องมือ
void.pointer

@ArmonSafai อ่านสิ่งนี้เพื่อความเข้าใจเพิ่มเติมgoo.gl/RYuNSM
AZ_

2

รูปแบบนั้นไม่ได้ละเมิดหลักการ Open / Closed (OCP) อย่างไรก็ตามเราละเมิด OCP เมื่อเราใช้รูปแบบที่ไม่ถูกต้อง

คำตอบง่ายๆสำหรับคำถามนี้มีดังนี้:

  1. สร้างการทำงานพื้นฐานของคุณโดยใช้รูปแบบวิธีการจากโรงงาน
  2. ขยายการทำงานของคุณโดยใช้รูปแบบนามธรรมจากโรงงาน

ในตัวอย่างที่ให้มาฟังก์ชันการทำงานพื้นฐานของคุณรองรับสามรูปร่าง: วงกลมสี่เหลี่ยมผืนผ้าและสี่เหลี่ยม สมมติว่าคุณต้องการรองรับ Triangle, Pentagon และ Hexagon ในอนาคต ในการทำเช่นนี้โดยไม่ละเมิด OCP คุณต้องสร้างโรงงานเพิ่มเติมเพื่อสนับสนุนรูปร่างใหม่ของคุณ (เรียกว่าAdvancedShapeFactory) จากนั้นใช้AbstractFactoryเพื่อตัดสินใจโรงงานที่คุณต้องการสร้างเพื่อสร้างรูปร่างใด ๆ ที่คุณต้องการ


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

1

หากคุณกำลังพูดถึงรูปแบบนามธรรมจากโรงงานการตัดสินใจมักจะไม่ได้อยู่ในตัวโรงงาน แต่อยู่ในรหัสแอปพลิเคชัน เป็นรหัสที่เลือกโรงงานคอนกรีตเพื่อยกตัวอย่างและส่งต่อไปยังรหัสลูกค้าที่จะใช้วัตถุที่ผลิตโดยโรงงาน ดูจุดสิ้นสุดของตัวอย่าง Java ที่นี่: https://en.wikipedia.org/wiki/Abstract_factory_pattern

การตัดสินใจไม่จำเป็นต้องหมายถึงifงบ มันสามารถอ่านประเภทโรงงานคอนกรีตจากไฟล์กำหนดค่าสืบทอดมาจากโครงสร้างแผนที่ ฯลฯ



ถ้าฉันผู้โทรกำลังตัดสินใจว่าคลาสที่เป็นรูปธรรมสำหรับอินสแตนซ์แล้วทำไมฉันจึงต้องรำคาญกับ Abstract Factory?
Robert Harvey

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

0

หากคุณคิดว่า Open-Close ที่ระดับคลาสกับโรงงานนี้คุณกำลังสร้างคลาสอื่นในระบบ Open-Close ของคุณตัวอย่างเช่นถ้าคุณมีคลาสอื่นที่มีรูปร่างเดียวและคำนวณพื้นที่ (ตัวอย่างทั่วไป) คลาสนี้เป็น OpenClose เพราะ มันสามารถคำนวณพื้นที่สำหรับรูปร่างชนิดใหม่โดยไม่ต้องดัดแปลง จากนั้นคุณมีคลาสอื่นที่ดึงรูปร่างอีกคลาสที่ใช้รูปร่าง N และส่งคืนคลาสที่ใหญ่กว่าและคุณสามารถคิดโดยทั่วไปว่าคลาสอื่น ๆ ในระบบของคุณที่จัดการกับรูปร่างนั้นเป็น Open-Close (อย่างน้อยเกี่ยวกับรูปร่าง) เมื่อมองที่การออกแบบโรงงานจะทำให้ระบบที่เหลือเป็นแบบเปิด - ปิดและแน่นอนว่าตัวโรงงานเองไม่เปิด - ปิด

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


0

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


-2

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

อย่างไรก็ตามหากคุณไม่ชอบรูปแบบของโรงงานคุณสามารถใช้การฉีดแบบพึ่งพาได้เสมอ


6
สวิตช์ / กล่องดีกว่าเงื่อนไขอย่างไร การใช้ map / dict / table เพื่อแสดงรหัสเป็นข้อมูลนั้นดีถ้าคุณต้องการรีจิสตรีของการใช้งานที่แตกต่างกัน - เช่นในการใช้ DI container แต่การเรียกกลับที่มีประเภทเดียวกันต่างกันนั้นไม่จำเป็นสำหรับโรงงานส่วนใหญ่! ฉันไม่เข้าใจว่าทำไมคุณถึงแนะนำเช่นนั้น นอกจากนี้คอนเทนเนอร์ DI จำนวนมากถูกนำมาใช้ในแง่ของวัตถุในโรงงานดังนั้นแนะนำให้ใช้ DI แทนโรงงานดูเหมือนจะเป็นวงกลม
amon

1
@ ฉันหมายถึงการใช้ DI ประเภทอื่น - ไม่ใช่โรงงาน
BЈовић


1
โรงงานของคุณจะตัดสินใจอย่างไรว่าจะใช้ตัวชี้ใด ในที่สุดคุณต้องตัดสินใจ
whatsisname

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