เหตุใดฉันจึงควรใช้คลาสโรงงานแทนการสร้างวัตถุโดยตรง


162

ฉันได้เห็นประวัติของโครงการห้องสมุดคลาสС # และ Java หลายรายการบน GitHub และ CodePlex และฉันเห็นแนวโน้มของการเปลี่ยนไปใช้คลาสของโรงงานซึ่งต่างจากการอินสแตนซ์วัตถุโดยตรง

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

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

ฉันควรใช้ช่างก่อสร้างสาธารณะเมื่อใดและฉันควรใช้โรงงานเมื่อใด



1
ผ้า / วิธีการเรียนคืออะไร?
Doval

คำตอบ:


56

ชั้นเรียนของโรงงานมักถูกนำมาใช้เพราะอนุญาตให้โครงการทำตามหลักการของSOLIDอย่างใกล้ชิดยิ่งขึ้น โดยเฉพาะอย่างยิ่งหลักการแยกอินเทอร์เฟซและหลักการการพึ่งพาการพึ่งพา

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

  • ช่วยให้คุณสามารถแนะนำคอนเทนเนอร์Inversion of Control (IoC) ได้อย่างง่ายดาย
  • มันทำให้โค้ดของคุณสามารถทดสอบได้มากขึ้นในขณะที่คุณสามารถจำลองอินเตอร์เฟสได้
  • มันช่วยให้คุณมีความยืดหยุ่นมากขึ้นเมื่อถึงเวลาต้องเปลี่ยนแอปพลิเคชัน (เช่นคุณสามารถสร้างการใช้งานใหม่โดยไม่ต้องเปลี่ยนโค้ดที่ต้องพึ่งพา)

พิจารณาสถานการณ์นี้

การประกอบ A (-> หมายถึงการพึ่งพา):

Class A -> Class B
Class A -> Class C
Class B -> Class D

ฉันต้องการย้าย Class B ไปยัง Assembly B ซึ่งขึ้นอยู่กับแอสเซมบลี A ด้วยการอ้างอิงที่เป็นรูปธรรมเหล่านี้ฉันต้องย้ายลำดับชั้นของคลาสทั้งหมดของฉันไป ถ้าฉันใช้อินเตอร์เฟสฉันสามารถหลีกเลี่ยงความเจ็บปวดได้มาก

การประกอบ A:

Class A -> Interface IB
Class A -> Interface IC
Class B -> Interface IB
Class C -> Interface IC
Class B -> Interface ID
Class D -> Interface ID

ตอนนี้ฉันสามารถย้ายคลาส B ไปยังชุดประกอบ B โดยไม่เจ็บปวดใด ๆ มันยังคงขึ้นอยู่กับอินเตอร์เฟสในชุดประกอบ A

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

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


40
โรงงาน IMO มีความสำคัญน้อยที่สุดสำหรับ SOLID คุณสามารถทำ SOLID ได้โดยไม่ต้องมีโรงงาน
ร่าเริง

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

8
@ BЈовић - ยกเว้นว่าทุกครั้งที่คุณเพิ่มการใช้งานใหม่ตอนนี้คุณจะต้องเปิดโรงงานและปรับเปลี่ยนให้เป็นบัญชีสำหรับการใช้งานใหม่ - ละเมิด OCP อย่างชัดเจน
Telastyn

6
@Tastastyn ใช่ แต่รหัสโดยใช้วัตถุที่สร้างขึ้นจะไม่เปลี่ยนแปลง นั่นสำคัญกว่าการเปลี่ยนแปลงจากโรงงาน
BЈовић

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

126

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

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

หลายโรงงานถูกสร้างขึ้นเพราะ "บางทีวันหนึ่งฉันจะต้องสร้างชั้นเรียนเหล่านั้นแตกต่างกัน" ในใจ ซึ่งเป็นการละเมิดชัดเจนของYAGNI

และโรงงานล้าสมัยเมื่อคุณแนะนำ IoC framework เพราะ IoC เป็นเพียงโรงงานชนิดหนึ่ง และกรอบ IoC จำนวนมากสามารถสร้างการใช้งานของโรงงานเฉพาะ

นอกจากนี้ยังไม่มีรูปแบบการออกแบบที่บอกว่าจะสร้างคลาสสแตติกขนาดใหญ่ด้วยCreateXXXวิธีการที่เรียกเฉพาะคอนสตรัคเตอร์ และโดยเฉพาะอย่างยิ่งไม่เรียกว่าโรงงาน (หรือโรงงานนามธรรม)


6
ผมเห็นด้วยกับส่วนใหญ่ของคะแนนของคุณยกเว้น"IoC เป็นชนิดของโรงงาน" : ภาชนะ IoC มีโรงงานไม่ พวกเขาเป็นวิธีที่สะดวกในการบรรลุการฉีดพึ่งพา ใช่บางคนมีความสามารถในการสร้างโรงงานอัตโนมัติ แต่พวกเขาไม่ใช่โรงงานเองและไม่ควรได้รับการปฏิบัติเช่นนี้ ฉันยังยืนยันประเด็น YAGNI มันมีประโยชน์ที่จะสามารถแทนที่การทดสอบสองครั้งในการทดสอบหน่วยของคุณ Refactoring ทุกอย่างเพื่อให้นี้หลังจากที่ความจริงเป็นความเจ็บปวดในตูด วางแผนล่วงหน้าและอย่าพลาดข้ออ้าง "YAGNI"
AlexFoxGill

11
@AlexG - เอ๊ะ ... ในทางปฏิบัติคอนเทนเนอร์ IoC เกือบทั้งหมดทำงานเป็นโรงงานได้
Telastyn

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

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

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

79

รูปแบบของโรงงานเกิดจากความเชื่อที่ไม่เชื่อในหมู่นักเขียนในภาษา "C-style" (C / C ++, C #, Java) ที่ใช้คำหลัก "ใหม่" ไม่ดีและควรหลีกเลี่ยงค่าใช้จ่ายทั้งหมด (หรือที่ ส่วนกลางน้อยที่สุด) ในทางกลับกันสิ่งนี้มาจากการตีความอย่างเข้มงวดเป็นพิเศษของหลักการความรับผิดชอบเดี่ยว ("S" ของ SOLID) และหลักการผกผันของการพึ่งพา (D ") ระบุไว้ง่ายๆ SRP กล่าวว่าอุดมคติของรหัสวัตถุควรมี "เหตุผลในการเปลี่ยนแปลง" อย่างใดอย่างหนึ่ง ว่า "เหตุผลในการเปลี่ยนแปลง" เป็นจุดประสงค์หลักของวัตถุนั้น "ความรับผิดชอบ" ของมันใน codebase และสิ่งอื่น ๆ ที่ต้องมีการเปลี่ยนแปลงรหัสไม่ควรต้องเปิดไฟล์คลาสนั้น กรมทรัพย์สินทางปัญญาง่ายยิ่งขึ้น; รหัสวัตถุไม่ควรขึ้นอยู่กับวัตถุรูปธรรมอื่น

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

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

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

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


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

1
ปัญหาอีกประการหนึ่งของ constructors สาธารณะคือไม่มีวิธีที่ดีสำหรับคลาสที่Fooจะระบุ public constructor ที่ควรจะใช้สำหรับการสร้างFooอินสแตนซ์หรือการสร้างประเภทอื่น ๆภายในแพ็คเกจ / ชุดเดียวกัน แต่ไม่ควรใช้สำหรับการสร้าง ประเภทมาจากที่อื่น ฉันไม่รู้เหตุผลที่น่าสนใจโดยเฉพาะอย่างยิ่งภาษา / กรอบงานไม่สามารถกำหนดตัวสร้างแยกต่างหากเพื่อใช้ในnewการแสดงออกเทียบกับการเรียกใช้จากตัวสร้างชนิดย่อย แต่ฉันไม่รู้ภาษาใด ๆ ที่ทำให้เกิดความแตกต่างนั้น
supercat

1
คอนสตรัคเตอร์ที่ได้รับการป้องกันและ / หรือภายในจะเป็นสัญญาณดังกล่าว คอนสตรัคนี้จะใช้ได้เฉพาะกับรหัสการบริโภคไม่ว่าจะเป็นในคลาสย่อยหรือภายในแอสเซมบลีเดียวกัน C # ไม่มีชุดคำหลักสำหรับ "การป้องกันและภายใน" ความหมายเฉพาะชนิดย่อยภายในแอสเซมบลีเท่านั้นที่สามารถใช้งานได้ แต่ MSIL มีตัวระบุขอบเขตสำหรับการมองเห็นประเภทนั้นดังนั้นจึงเป็นไปได้ที่ C # spec สามารถขยายได้ . แต่นี่ไม่ได้เกี่ยวข้องกับการใช้โรงงานมากนัก (เว้นแต่คุณจะใช้ข้อ จำกัด ในการมองเห็นเพื่อบังคับใช้การใช้งานของโรงงาน)
KeithS

2
คำตอบที่สมบูรณ์แบบ ตรงประเด็นกับส่วน 'ทฤษฎีพบความจริง' แค่คิดว่ามีนักพัฒนาและเวลาของมนุษย์จำนวนมากที่ใช้เวลาไปกับการชื่นชมการยกระดับการใช้งานและการตกอยู่ในสถานการณ์เดียวกับที่คุณอธิบาย ติดตาม YAGNI, ฉันไม่เคยระบุความต้องการในการใช้โรงงาน
Breno Salgado

ฉันกำลังเขียนโปรแกรมบน codebase เนื่องจากการใช้งาน OOP ไม่อนุญาตให้มีการสร้างมากเกินไปการใช้ public constructor จึงถูกแบนอย่างมีประสิทธิภาพ นี่เป็นปัญหาเล็กน้อยในภาษาที่อนุญาต ชอบสร้างอุณหภูมิ ทั้งฟาเรนไฮต์และเซลเซียสเป็นลอย อย่างไรก็ตามคุณสามารถใส่กล่องเหล่านั้นแล้วแก้ไขปัญหาได้
jgmjgm

33

ตัวสร้างจะใช้ได้เมื่อพวกเขามีรหัสสั้น ๆ

เมื่อการกำหนดค่าเริ่มต้นเป็นมากกว่าการกำหนดตัวแปรให้กับเขตข้อมูลโรงงานจึงเหมาะสม นี่คือประโยชน์บางอย่าง:

  • รหัสที่ยาวและซับซ้อนทำให้มีความหมายมากขึ้นในคลาสเฉพาะ (โรงงาน) หากใส่รหัสเดียวกันในนวกรรมิกซึ่งเรียกใช้วิธีการคงที่จำนวนมากสิ่งนี้จะทำให้คลาสหลักสกปรก

  • ในบางภาษาและบางกรณีการโยนข้อยกเว้นในตัวสร้างเป็นความคิดที่แย่มากเพราะมันสามารถแนะนำบั๊กได้

  • เมื่อคุณเรียกใช้ Constructor คุณผู้เรียกจะต้องทราบประเภทที่แน่นอนของอินสแตนซ์ที่คุณต้องการสร้าง นี่ไม่ใช่กรณีเสมอไป (เช่นFeederฉันต้องสร้างมันขึ้นมาAnimalเพื่อป้อนมันฉันไม่สนว่ามันจะเป็นDogหรือCat)


2
ตัวเลือกไม่เพียงเป็น "โรงงาน" หรือ "ตัวสร้าง" A Feederอาจไม่ใช้และเรียกว่าKennelเป็นgetHungryAnimalวิธีการของวัตถุแทน
DougM

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

นี่เป็นคำตอบที่น่าพอใจเพียงข้อเดียวที่ฉันได้เห็นที่นี่ช่วยให้ฉันไม่ต้องเขียนเอง คำตอบอื่น ๆ มีการจัดการในแนวคิดนามธรรม
TheCatWhisperer

แต่อาร์กิวเมนต์นี้สามารถถูกต้องจริงสำหรับBuilder Patternเช่นกัน ไม่ใช่เหรอ
soufrk

กฎคอนสตรัคเตอร์
Breno Salgado

10

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

ตัวอย่างง่ายๆหนึ่งตัวอย่าง: คุณต้องการสื่อสารกับอุปกรณ์ แต่คุณไม่รู้ว่าจะเป็นผ่านอีเธอร์เน็ต, COM หรือ USB คุณกำหนดหนึ่งอินเทอร์เฟซและการใช้งาน 3 ที่รันไทม์คุณสามารถเลือกวิธีการที่คุณต้องการและโรงงานจะให้การใช้งานที่เหมาะสม

ใช้บ่อย ...


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

ตอนนี้คุณมีความยืดหยุ่นเพิ่มขึ้นและในทางทฤษฎีแล้วแอปพลิเคชันของคุณสามารถใช้ Ethernet, COM, USB และซีเรียลพร้อมสำหรับ fireloop หรืออะไรก็ตามในทางทฤษฎี ในความเป็นจริงแล้วแอปของคุณจะสื่อสารผ่านอีเทอร์เน็ตเท่านั้น ....
Pieter B

7

เป็นอาการของข้อ จำกัด ในระบบโมดูลของ Java / C #

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

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

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

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

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


2
ฉันหวังว่า Java และอนุพันธ์เช่น. NET มีไวยากรณ์พิเศษสำหรับคลาสที่สร้างอินสแตนซ์ของตัวเองและอย่างอื่นnewก็เป็นน้ำตาล syntactic สำหรับการเรียกวิธีคงที่ชื่อพิเศษ (ซึ่งจะถูกสร้างขึ้นโดยอัตโนมัติถ้าประเภทมี "คอนสตรัคสาธารณะ" "แต่ไม่ได้รวมวิธีการไว้อย่างชัดเจน) IMHO หากรหัสเพียงต้องการสิ่งเริ่มต้นที่น่าเบื่อที่ดำเนินการListก็ควรจะเป็นไปได้สำหรับอินเทอร์เฟซที่จะให้มันหนึ่งโดยไม่ต้องลูกค้าต้องรู้ของการใช้งานเฉพาะใด ๆ (เช่นArrayList)
supercat

2

ในความคิดของฉันพวกเขาเพียงใช้ Simple Factory ซึ่งไม่ใช่รูปแบบการออกแบบที่เหมาะสมและไม่ควรสับสนกับ Abstract Factory หรือวิธีการของโรงงาน

และเนื่องจากพวกเขาได้สร้าง "คลาสผ้าขนาดใหญ่ที่มีวิธีการคงที่ของ CreateXXX นับพัน" ซึ่งฟังดูเป็นรูปแบบการต่อต้าน

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

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


1
Simple Factory มีสถานที่ ลองนึกภาพนิติบุคคลที่จะใช้เวลาสองพารามิเตอร์ปลูกสร้างและint x IFooService fooServiceคุณไม่ต้องการที่จะเดินไปรอบ ๆfooServiceทุกที่ดังนั้นคุณจึงสร้างโรงงานด้วยวิธีการCreate(int x)และฉีดบริการภายในโรงงาน
AlexFoxGill

4
@AlexG และจากนั้นคุณจะต้องผ่านรอบทุกแทนIFactory IFooService
ร่าเริง

3
ฉันเห็นด้วยอย่างร่าเริง จากประสบการณ์ของฉันวัตถุที่ฉีดเข้าไปในกราฟจากด้านบนมักจะเป็นประเภทที่วัตถุระดับล่างทั้งหมดต้องการและการผ่าน IFooServices ไปรอบ ๆ นั้นไม่ใช่เรื่องใหญ่ การแทนที่สิ่งที่เป็นนามธรรมอย่างใดอย่างหนึ่งไม่สามารถทำได้สำเร็จ แต่เป็นการทำให้รหัสฐานเสื่อมเสียยิ่งขึ้น
KeithS

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

1
นั่นเป็นเพียงชื่อคำถามฉันคิดว่าคุณพลาดไปเลย ดูจุดเชื่อมโยงสุดท้ายที่มีให้;)
FranMowinckel

1

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

ในฐานะผู้สร้างห้องสมุดคุณจะใช้วิธีการจากโรงงานหากคุณต้องการใช้ความยืดหยุ่นนั้นด้วยตัวคุณเอง

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


ยังทราบ; หากผู้พัฒนาต้องการให้คลาสที่ได้รับนั้นมีฟังก์ชั่นพิเศษ (คุณสมบัติเพิ่มเติมการเริ่มต้น) ที่นักพัฒนาสามารถทำได้ (สมมติว่าวิธีการจากโรงงานนั้นสามารถ overridable ได้) ผู้เขียน API อาจมอบวิธีการแก้ปัญหาสำหรับความต้องการพิเศษของลูกค้า
Eric Schneider

-4

สิ่งนี้ดูเหมือนจะล้าสมัยในยุคของสกาล่าและการเขียนโปรแกรมเชิงหน้าที่ รากฐานที่มั่นคงของฟังก์ชั่นแทนที่คลาส gazillion

นอกจากนี้เพื่อให้ทราบว่า Java's double {{ไม่ทำงานอีกต่อไปเมื่อใช้งานจากโรงงาน

someFunction(new someObject() {{
    setSomeParam(...);
    etc..
}})

ซึ่งสามารถให้คุณสร้างคลาสที่ไม่ระบุชื่อและปรับแต่งได้

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


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