ทำไมเราถึงต้องการรูปแบบการออกแบบโรงงานที่เป็นนามธรรม?


125

คำจำกัดความส่วนใหญ่กล่าวว่า:

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

การใช้ Abstract Factory Pattern คืออะไรในขณะที่เราสามารถบรรลุงานผ่านการสร้างวัตถุของคลาสคอนกรีตเอง เหตุใดเราจึงมีวิธีการโรงงานที่สร้างวัตถุของคลาสคอนกรีต?

โปรดให้ตัวอย่างชีวิตจริงที่ฉันต้องใช้รูปแบบ abstractFactory?

คำตอบ:


219

Abstract Factory เป็นรูปแบบการออกแบบที่เป็นศูนย์กลางสำหรับDependency Injection (DI) นี่คือรายการของคำถามกองมากเกินที่ใช้ของโรงงานบทคัดย่อได้รับการยอมรับว่าเป็นวิธีการแก้ปัญหา

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


6
ตัวอย่างทั้งหมดนี้อธิบายถึง Factory Method Pattern เนื่องจากทั้งหมดส่งคืนอินเทอร์เฟซผลิตภัณฑ์เดียว ไม่มีสิ่งเหล่านี้เป็นรูปแบบโรงงานนามธรรมเนื่องจากไม่มีส่วนต่อประสานผลิตภัณฑ์ที่เกี่ยวข้อง
jaco0646

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

1
@ jaco0646 IIRC รูปแบบ Factory Methodเป็นความเชี่ยวชาญเฉพาะของรูปแบบ Template Methodซึ่งอาศัยการสืบทอด แม้ว่าฉันอาจจะเข้าใจผิดในขณะที่ฉันกำลังเดินทางและไม่มีหนังสือ GoF อยู่กับฉัน คุณหมายถึงอะไรที่ "ไม่มีส่วนต่อประสานผลิตภัณฑ์ที่เกี่ยวข้อง"
Mark Seemann

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

1
นี่คือตัวอย่างoodesign.com/abstract-factory-pattern.html นี่คือสิ่งที่รูปแบบโรงงานนามธรรมถูกสร้างขึ้นสำหรับ
user2802557

23

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

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

DbProviderFactoryใน .NET Framework เป็นตัวอย่างของรูปแบบนี้


18
คำตอบนี้สามารถอธิบายรูปแบบ Factory Method หรือ Static Factory ได้อย่างถูกต้อง แต่ไม่ใช่รูปแบบ Abstract Factory
jaco0646

5

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


4

การใช้ Abstract Factory Pattern คืออะไรในขณะที่เราสามารถบรรลุงานผ่านการสร้างวัตถุของคลาสคอนกรีตเอง เหตุใดเราจึงมีวิธีการโรงงานที่สร้างวัตถุของคลาสคอนกรีต?

ในกรณีที่ไม่มีAbstract Factoryลูกค้าจำเป็นต้องทราบรายละเอียดของคลาสคอนกรีต นี้มีเพศสัมพันธ์แน่นได้ถูกลบออกกับโรงงานบทคัดย่อ

ตอนนี้Factory Methodมีสัญญาที่ลูกค้าต้องใช้ คุณสามารถเพิ่มผลิตภัณฑ์เพิ่มเติมในโรงงานของคุณได้โดยการเพิ่มผลิตภัณฑ์ใหม่ซึ่งใช้อินเทอร์เฟซที่เปิดเผยโดย Factory Method

อ้างถึงคำถาม SE ที่เกี่ยวข้องเหล่านี้เพื่อความเข้าใจที่ดีขึ้น:

อะไรคือความแตกต่างพื้นฐานระหว่าง Factory และ Abstract Factory Patterns?

เจตนา:

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

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

รายการตรวจสอบ:

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

2

Abstract Factory เหมาะอย่างยิ่งสำหรับการรองรับหลายแพลตฟอร์มในขณะที่ทำให้ฐานรหัสของคุณเป็นหนึ่งเดียวกัน สมมติว่าคุณมีโปรแกรม Qt หรือ GTK + หรือ. NET / Mono ขนาดใหญ่ที่คุณต้องการรันบน Windows, Linux และ OSX แต่คุณมีคุณลักษณะที่ใช้งานในลักษณะที่แตกต่างกันในแต่ละแพลตฟอร์ม (อาจใช้ผ่าน kernel32 API หรือคุณลักษณะ POSIX)

public abstract class Feature
{
    public abstract int PlatformSpecificValue { get; }

    public static Feature PlatformFeature
    {
        get
        {
            string platform;
            // do platform detection here
            if (platform == "Win32")
                return new Win32Feature();
            if (platform == "POSIX")
                return new POSIXFeature();
        }
    }

    // platform overrides omitted
}

ด้วย Abstract Factory นี้ UI ของคุณไม่จำเป็นต้องรู้อะไรเกี่ยวกับแพลตฟอร์มปัจจุบัน

Feature feature = Feature.PlatformFeature;
Console.WriteLine(feature.PlatformSpecificValue);

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

1

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


1

เป็นเรื่องง่ายการถ่ายภาพที่คุณมีรหัสที่ใช้ได้กับสิ่งที่เป็นนามธรรมคุณควรสร้างนามธรรมไม่ใช่คลาสที่เป็นรูปธรรม

คุณควรทำงานกับนามธรรมเสมอเพราะคุณสามารถแก้ไขโค้ดได้ดีขึ้น

นี่เป็นตัวอย่างที่ดี: http://en.wikipedia.org/wiki/Abstract_factory_pattern#C.23


1

ฉันพบว่ารูปแบบ Abstract Factory มีการประเมินราคาสูงเกินไป

ครั้งแรกของทั้งหมดมันไม่ได้เกิดขึ้นที่มักจะว่าคุณมีชุดของความสัมพันธ์ประเภทที่คุณต้องการอินสแตนซ์

ประการที่สองระดับของการบ่งชี้ (นามธรรม) ที่มาจากอินเทอร์เฟซโดยปกติจะเพียงพอเมื่อทำงานกับการฉีดแบบพึ่งพา

ตัวอย่างทั่วไปของ WindowsGui vs MacGui เทียบกับ ... ที่คุณมี WindowsButton, MacButton, WindowsScrollBar, MacScrollbar และอื่น ๆ มักจะใช้งานได้ง่ายกว่าโดยการกำหนดปุ่มคอนกรีตแถบเลื่อน ฯลฯ โดยใช้รูปแบบผู้เยี่ยมชมและ / หรือล่ามเพื่อให้ พฤติกรรมที่แท้จริง


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

2
ดี ... การใช้ตัวระบุตำแหน่งบริการกับ DI เป็นระบบป้องกันการเคลื่อนที่ Abstract Factory เป็นโซลูชันสากลเมื่อเราต้องการสร้าง DEPENDENCIES จากค่ารันไทม์
TheMentor

1

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

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

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

และบางทีพรุ่งนี้เราจะมีอีกตระกูลสมมติว่า type_B และ type_C เพื่อสร้างอินสแตนซ์ ดังนั้น UI จะมี "if else" เพื่อให้ทราบว่าผู้ใช้ต้องการ "type_A", "type_B" หรือ "type_C" หรือไม่ แต่คลาสโรงงานจะตัดสินใจอย่างชัดเจนว่าจะสร้างคลาสจากประเภทใด (จากตระกูล) และ วิธีการปรับแต่ง - ค่าที่กำหนดเป็นพารามิเตอร์หรือส่งให้ผู้รับเหมา ทั้งหมดนี้ - ตามพารามิเตอร์หลายอย่างที่ UI ไม่ทราบ ทั้งหมดนี้จะมากเกินไปสำหรับคลาสโรงงานเดียว


1

ตัวอย่างชีวิตจริงมีให้ในเนมสเปซ System.Data.Common ที่มีคลาสพื้นฐานนามธรรมซึ่งรวมถึง DbConnection, DbCommand และ DbDataAdapter และแชร์โดยผู้ให้บริการข้อมูล. NET Framework เช่น System.Data.SqlClient และ System.Data.OracleClient ซึ่ง ช่วยให้นักพัฒนาสามารถเขียนรหัสการเข้าถึงข้อมูลทั่วไปที่ไม่ขึ้นอยู่กับผู้ให้บริการข้อมูลเฉพาะ

คลาส DbProviderFactories จัดเตรียมเมธอดแบบคงที่สำหรับการสร้างอินสแตนซ์ DbProviderFactory จากนั้นอินสแตนซ์จะส่งคืนอ็อบเจ็กต์ที่พิมพ์อย่างถูกต้องตามข้อมูลผู้ให้บริการและสตริงการเชื่อมต่อที่ให้มาในขณะรัน

ตัวอย่าง:

 DataTable allProvidersTable = DbProviderFactories.GetFactoryClasses();

ใส่คำอธิบายภาพที่นี่

        /* Getting SqlClient family members */
        DbProviderFactory dbProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
        DbCommand dbCommand = dbProviderFactory.CreateCommand();
        DbConnection dbConnection = dbProviderFactory.CreateConnection();
        DbDataAdapter dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        SqlClientFactory sqlClientFactory = (SqlClientFactory)dbProviderFactory;
        SqlConnection sqlConnection = (SqlConnection)dbConnection;
        SqlCommand sqlCommand = (SqlCommand) dbCommand;
        SqlDataAdapter sqlDataAdapter = (SqlDataAdapter) dbDataAdapter;

        /* Getting OracleClient family members*/
        dbProviderFactory = DbProviderFactories.GetFactory("System.Data.OracleClient");
        dbCommand = dbProviderFactory.CreateCommand();
        dbConnection = dbProviderFactory.CreateConnection();
        dbDataAdapter = dbProviderFactory.CreateDataAdapter();

        OracleClientFactory oracleClientFactory = (OracleClientFactory)dbProviderFactory;
        OracleConnection oracleConnection = (OracleConnection)dbConnection;
        OracleCommand oracleCommand = (OracleCommand)dbCommand;
        OracleDataAdapter oracleDataAdapter = (OracleDataAdapter)dbDataAdapter;

ตัวอย่างที่ 2 ใส่คำอธิบายภาพที่นี่

สถาปัตยกรรม Code Solution ใส่คำอธิบายภาพที่นี่

อินสแตนซ์โรงงานคอนกรีตมีให้โดยใช้วิธี Static Factory ดังต่อไปนี้

public  class FurnitureProviderFactory
{
    public static IFurnitureFactory GetFactory(string furnitureType)
    {
        if (furnitureType == "Wood")
        {
            return new WoodenFurnitureFactory();
        }
        if (furnitureType == "Plastic")
        {
            return new PlasticFurnitureFactory();
        }
        throw new Exception("Undefined Furniture");
    }
}

0

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

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

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


0

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


0

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

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


0

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

การทำความเข้าใจและการปรับใช้รูปแบบโรงงานนามธรรมใน C #

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