• 设计模式——3. 抽象工厂模式


    1. 说明

    抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种创建一组相关或依赖对象的方式,而无需指定它们的具体类。抽象工厂模式是工厂模式的扩展,它关注于创建一组相关的对象家族,而不仅仅是一个单一的对象。

    抽象工厂模式通常涉及以下几个角色:

    1. 抽象工厂(Abstract Factory):抽象工厂是一个接口或抽象类,它声明了一组工厂方法,每个工厂方法用于创建一个相关的对象家族,包括不同类型的产品。抽象工厂通常与具体工厂相对应。
    2. 具体工厂(Concrete Factory):具体工厂是抽象工厂的实际实现,它实现了工厂方法,负责创建一组相关的产品对象。每个具体工厂通常与特定的产品家族相对应。
    3. 抽象产品(Abstract Product):抽象产品是产品家族的抽象,它定义了产品的公共接口,包括不同类型产品的属性和方法。
    4. 具体产品(Concrete Product):具体产品是抽象产品的具体实现,它们实现了抽象产品定义的接口或继承了抽象产品的基类。

    抽象工厂模式的关键思想是将对象的创建与使用分离,同时确保创建的对象家族之间具有一致性。这使得系统更容易扩展,因为可以轻松添加新的产品家族,而不需要修改客户端代码。

    2. 使用的场景

    抽象工厂模式适用于以下场景:

    1. 需要创建一组相关的产品家族:当一个系统需要创建一组相关的产品对象,而这些产品对象之间有关联或依赖关系时,抽象工厂模式非常有用。例如,一个图形界面库需要创建按钮、文本框和标签等相关的组件。
    2. 需要跨不同产品家族进行配置:如果系统需要在不同的产品家族之间切换,抽象工厂模式是一个好的选择。例如,一个跨平台应用程序可能需要在不同的操作系统上使用不同的用户界面元素,而抽象工厂可以根据当前的操作系统选择合适的工厂来创建界面元素。
    3. 强调一致性:当希望确保创建的对象家族之间具有一致性时,可以使用抽象工厂模式。这有助于确保不同类型的产品对象之间的兼容性。
    4. 系统扩展性:抽象工厂模式支持系统的扩展,可以轻松地添加新的产品家族,而无需修改现有的客户端代码。这有助于保持系统的可维护性和可扩展性。
    5. 隐藏对象的创建细节:抽象工厂模式将对象的创建细节封装在工厂类中,客户端代码无需关心具体对象是如何创建的,从而降低了耦合性。

    总的来说,抽象工厂模式适用于需要创建一组相关产品对象,这些产品对象之间存在依赖关系或需要一致性,并且可能需要在不同产品家族之间进行切换或扩展的情况。

    3. 应用例子

    以下是一个使用Python实现抽象工厂模式的示例,我们将创建不同类型的按钮和文本框,并使用抽象工厂模式封装它们的创建逻辑。

    # 抽象工厂接口
    class GUIFactory:
        def create_button(self):
            pass
    
        def create_textbox(self):
            pass
    
    # 具体工厂1:创建Windows风格的按钮和文本框
    class WindowsFactory(GUIFactory):
        def create_button(self):
            return WindowsButton()
    
        def create_textbox(self):
            return WindowsTextbox()
    
    # 具体工厂2:创建Mac风格的按钮和文本框
    class MacFactory(GUIFactory):
        def create_button(self):
            return MacButton()
    
        def create_textbox(self):
            return MacTextbox()
    
    # 抽象产品:按钮
    class Button:
        def paint(self):
            pass
    
    # 具体产品1:Windows风格的按钮
    class WindowsButton(Button):
        def paint(self):
            return "Windows 风格按钮"
    
    # 具体产品2:Mac风格的按钮
    class MacButton(Button):
        def paint(self):
            return "Mac 风格按钮"
    
    # 抽象产品:文本框
    class Textbox:
        def display(self):
            pass
    
    # 具体产品1:Windows风格的文本框
    class WindowsTextbox(Textbox):
        def display(self):
            return "Windows 风格文本框"
    
    # 具体产品2:Mac风格的文本框
    class MacTextbox(Textbox):
        def display(self):
            return "Mac 风格文本框"
    
    # 客户端代码
    def create_gui(factory):
        button = factory.create_button()
        textbox = factory.create_textbox()
        return button, textbox
    
    # 使用Windows风格工厂
    windows_factory = WindowsFactory()
    windows_button, windows_textbox = create_gui(windows_factory)
    print(windows_button.paint())  # 输出:Windows 风格按钮
    print(windows_textbox.display())  # 输出:Windows 风格文本框
    
    # 使用Mac风格工厂
    mac_factory = MacFactory()
    mac_button, mac_textbox = create_gui(mac_factory)
    print(mac_button.paint())  # 输出:Mac 风格按钮
    print(mac_textbox.display())  # 输出:Mac 风格文本框
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    在这个示例中:

    • GUIFactory 是抽象工厂接口,定义了两个工厂方法:create_button() 和 create_textbox(),用于创建按钮和文本框。
    • WindowsFactory 和 MacFactory 分别是具体工厂,它们实现了 GUIFactory 接口,负责创建Windows风格和Mac风格的按钮和文本框。
    • Button 和 Textbox 是抽象产品,它们定义了按钮和文本框的公共接口。
    • WindowsButton、MacButton、WindowsTextbox 和 MacTextbox 是具体产品,它们实现了抽象产品的接口,分别表示Windows风格和Mac风格的按钮和文本框。
    • 在客户端代码中,我们可以选择使用不同的具体工厂来创建按钮和文本框,从而获得不同风格的用户界面元素。

    这个示例演示了如何使用抽象工厂模式来创建不同类型的相关产品对象,而无需直接关心它们的具体类。这种方式有助于实现一致性的用户界面风格,并支持在不同的工厂之间切换。

    4. 实现要素

    抽象工厂模式的实现要素包括以下几个关键部分:

    1. 抽象工厂(Abstract Factory):抽象工厂是一个接口或抽象类,它声明了一组抽象工厂方法,每个工厂方法用于创建一组相关的产品对象。抽象工厂的角色是定义产品家族的创建接口,通常与具体工厂相对应。
    2. 具体工厂(Concrete Factory):具体工厂是抽象工厂的实际实现,它实现了抽象工厂中声明的工厂方法,负责创建一组相关的具体产品对象。每个具体工厂通常对应于一个产品家族。
    3. 抽象产品(Abstract Product):抽象产品是产品家族的抽象,它定义了产品的公共接口,包括不同类型产品的属性和方法。抽象产品通常是一个接口或抽象类。
    4. 具体产品(Concrete Product):具体产品是抽象产品的具体实现,它们实现了抽象产品定义的接口或继承了抽象产品的基类。每个具体产品对应于一个具体工厂。

    抽象工厂模式的关键思想是将对象的创建与使用分离,通过抽象工厂和具体工厂来创建一组相关的产品对象。这有助于确保创建的产品对象之间具有一致性,并支持在不同的工厂之间切换,以满足不同需求。

    5. Java/golang/javascrip/C++ 等语言实现方式

    5.1 Java实现抽象工厂模式

    上述例子用Java实现示例如下:

    // 抽象产品:按钮
    interface Button {
        void paint();
    }
    
    // 具体产品1:Windows风格的按钮
    class WindowsButton implements Button {
        public void paint() {
            System.out.println("Windows 风格按钮");
        }
    }
    
    // 具体产品2:Mac风格的按钮
    class MacButton implements Button {
        public void paint() {
            System.out.println("Mac 风格按钮");
        }
    }
    
    // 抽象产品:文本框
    interface Textbox {
        void display();
    }
    
    // 具体产品1:Windows风格的文本框
    class WindowsTextbox implements Textbox {
        public void display() {
            System.out.println("Windows 风格文本框");
        }
    }
    
    // 具体产品2:Mac风格的文本框
    class MacTextbox implements Textbox {
        public void display() {
            System.out.println("Mac 风格文本框");
        }
    }
    
    // 客户端代码
    public class Client {
        public static void main(String[] args) {
            GUIFactory windowsFactory = new WindowsFactory();
            Button windowsButton = windowsFactory.createButton();
            Textbox windowsTextbox = windowsFactory.createTextbox();
    
            windowsButton.paint();      // 输出:Windows 风格按钮
            windowsTextbox.display();   // 输出:Windows 风格文本框
    
            GUIFactory macFactory = new MacFactory();
            Button macButton = macFactory.createButton();
            Textbox macTextbox = macFactory.createTextbox();
    
            macButton.paint();          // 输出:Mac 风格按钮
            macTextbox.display();       // 输出:Mac 风格文本框
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    5.2 Golang实现抽象工厂模式

    在Go中,由于语言的特性和面向对象编程模式的不同,抽象工厂模式的实现方式与传统的面向对象语言有所不同。Go语言没有类和继承,但我们可以使用接口和函数来实现抽象工厂模式。以下是一个使用Go实现上述例子的示例:

    package main
    
    import "fmt"
    
    // 抽象产品:按钮
    type Button interface {
            Paint()
    }
    
    // 具体产品1:Windows风格的按钮
    type WindowsButton struct{}
    
    func (b WindowsButton) Paint() {
            fmt.Println("Windows 风格按钮")
    }
    
    // 具体产品2:Mac风格的按钮
    type MacButton struct{}
    
    func (b MacButton) Paint() {
            fmt.Println("Mac 风格按钮")
    }
    
    // 抽象产品:文本框
    type Textbox interface {
            Display()
    }
    
    // 具体产品1:Windows风格的文本框
    type WindowsTextbox struct{}
    
    func (t WindowsTextbox) Display() {
            fmt.Println("Windows 风格文本框")
    }
    
    // 具体产品2:Mac风格的文本框
    type MacTextbox struct{}
    
    func (t MacTextbox) Display() {
            fmt.Println("Mac 风格文本框")
    }
    
    // 抽象工厂接口
    type GUIFactory interface {
            CreateButton() Button
            CreateTextbox() Textbox
    }
    
    // 具体工厂1:创建Windows风格的按钮和文本框
    type WindowsFactory struct{}
    
    func (f WindowsFactory) CreateButton() Button {
            return WindowsButton{}
    }
    
    func (f WindowsFactory) CreateTextbox() Textbox {
            return WindowsTextbox{}
    }
    
    // 具体工厂2:创建Mac风格的按钮和文本框
    type MacFactory struct{}
    
    func (f MacFactory) CreateButton() Button {
            return MacButton{}
    }
    
    func (f MacFactory) CreateTextbox() Textbox {
            return MacTextbox{}
    }
    
    // 客户端代码
    func main() {
            windowsFactory := WindowsFactory{}
            windowsButton := windowsFactory.CreateButton()
            windowsTextbox := windowsFactory.CreateTextbox()
    
            windowsButton.Paint()       // 输出:Windows 风格按钮
            windowsTextbox.Display()    // 输出:Windows 风格文本框
    
            macFactory := MacFactory{}
            macButton := macFactory.CreateButton()
            macTextbox := macFactory.CreateTextbox()
    
            macButton.Paint()           // 输出:Mac 风格按钮
            macTextbox.Display()        // 输出:Mac 风格文本框
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    5.3 Javascript实现抽象工厂模式

    在JavaScript中,抽象工厂模式的实现方式与其他面向对象编程语言不同,因为JavaScript是一门动态语言,没有类和接口的概念。但我们可以使用对象和函数来模拟抽象工厂模式。以下是一个使用JavaScript实现上述例子的示例:

    // 抽象产品:按钮
    function Button() {}
    
    Button.prototype.paint = function () {
        console.log("Button");
    };
    
    // 具体产品1:Windows风格的按钮
    function WindowsButton() {}
    
    WindowsButton.prototype = Object.create(Button.prototype);
    
    WindowsButton.prototype.paint = function () {
        console.log("Windows 风格按钮");
    };
    
    // 具体产品2:Mac风格的按钮
    function MacButton() {}
    
    MacButton.prototype = Object.create(Button.prototype);
    
    MacButton.prototype.paint = function () {
        console.log("Mac 风格按钮");
    };
    
    // 抽象产品:文本框
    function Textbox() {}
    
    Textbox.prototype.display = function () {
        console.log("Textbox");
    };
    
    // 具体产品1:Windows风格的文本框
    function WindowsTextbox() {}
    
    WindowsTextbox.prototype = Object.create(Textbox.prototype);
    
    WindowsTextbox.prototype.display = function () {
        console.log("Windows 风格文本框");
    };
    
    // 具体产品2:Mac风格的文本框
    function MacTextbox() {}
    
    MacTextbox.prototype = Object.create(Textbox.prototype);
    
    MacTextbox.prototype.display = function () {
        console.log("Mac 风格文本框");
    };
    
    // 抽象工厂
    function GUIFactory() {}
    
    GUIFactory.prototype.createButton = function () {
        throw new Error("Abstract method createButton() must be overridden.");
    };
    
    GUIFactory.prototype.createTextbox = function () {
        throw new Error("Abstract method createTextbox() must be overridden.");
    };
    
    // 具体工厂1:创建Windows风格的按钮和文本框
    function WindowsFactory() {}
    
    WindowsFactory.prototype = Object.create(GUIFactory.prototype);
    
    WindowsFactory.prototype.createButton = function () {
        return new WindowsButton();
    };
    
    WindowsFactory.prototype.createTextbox = function () {
        return new WindowsTextbox();
    };
    
    // 具体工厂2:创建Mac风格的按钮和文本框
    function MacFactory() {}
    
    MacFactory.prototype = Object.create(GUIFactory.prototype);
    
    MacFactory.prototype.createButton = function () {
        return new MacButton();
    };
    
    MacFactory.prototype.createTextbox = function () {
        return new MacTextbox();
    };
    
    // 客户端代码
    const windowsFactory = new WindowsFactory();
    const windowsButton = windowsFactory.createButton();
    const windowsTextbox = windowsFactory.createTextbox();
    
    windowsButton.paint();       // 输出:Windows 风格按钮
    windowsTextbox.display();   // 输出:Windows 风格文本框
    
    const macFactory = new MacFactory();
    const macButton = macFactory.createButton();
    const macTextbox = macFactory.createTextbox();
    
    macButton.paint();           // 输出:Mac 风格按钮
    macTextbox.display();        // 输出:Mac 风格文本框
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101

    5.4 C++实现抽象工厂模式

    #include 
    
    // 抽象产品:按钮
    class Button {
    public:
        virtual void paint() = 0;
    };
    
    // 具体产品1:Windows风格的按钮
    class WindowsButton : public Button {
    public:
        void paint() override {
            std::cout << "Windows 风格按钮" << std::endl;
        }
    };
    
    // 具体产品2:Mac风格的按钮
    class MacButton : public Button {
    public:
        void paint() override {
            std::cout << "Mac 风格按钮" << std::endl;
        }
    };
    
    // 抽象产品:文本框
    class Textbox {
    public:
        virtual void display() = 0;
    };
    
    // 具体产品1:Windows风格的文本框
    class WindowsTextbox : public Textbox {
    public:
        void display() override {
            std::cout << "Windows 风格文本框" << std::endl;
        }
    };
    
    // 具体产品2:Mac风格的文本框
    class MacTextbox : public Textbox {
    public:
        void display() override {
            std::cout << "Mac 风格文本框" << std::endl;
        }
    };
    
    // 抽象工厂接口
    class GUIFactory {
    public:
        virtual Button* createButton() = 0;
        virtual Textbox* createTextbox() = 0;
    };
    
    // 具体工厂1:创建Windows风格的按钮和文本框
    class WindowsFactory : public GUIFactory {
    public:
        Button* createButton() override {
            return new WindowsButton();
        }
    
        Textbox* createTextbox() override {
            return new WindowsTextbox();
        }
    };
    
    // 具体工厂2:创建Mac风格的按钮和文本框
    class MacFactory : public GUIFactory {
    public:
        Button* createButton() override {
            return new MacButton();
        }
    
        Textbox* createTextbox() override {
            return new MacTextbox();
        }
    };
    
    int main() {
        // 使用Windows风格工厂
        GUIFactory* windowsFactory = new WindowsFactory();
        Button* windowsButton = windowsFactory->createButton();
        Textbox* windowsTextbox = windowsFactory->createTextbox();
    
        windowsButton->paint();     // 输出:Windows 风格按钮
        windowsTextbox->display();  // 输出:Windows 风格文本框
    
        // 使用Mac风格工厂
        GUIFactory* macFactory = new MacFactory();
        Button* macButton = macFactory->createButton();
        Textbox* macTextbox = macFactory->createTextbox();
    
        macButton->paint();         // 输出:Mac 风格按钮
        macTextbox->display();      // 输出:Mac 风格文本框
    
        // 释放资源
        delete windowsButton;
        delete windowsTextbox;
        delete windowsFactory;
        delete macButton;
        delete macTextbox;
        delete macFactory;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104

    6. 练习题

    假设你正在设计一个电子产品制造工厂,该工厂可以生产不同品牌(例如,Apple和Samsung)的电子产品,包括手机和笔记本电脑。每个品牌都有自己的手机和笔记本电脑型号。使用抽象工厂模式来实现这个电子产品工厂。

    要求:

    1. 创建一个抽象工厂接口 ElectronicFactory,它包括两个抽象方法:createPhone 和 createLaptop,分别用于创建手机和笔记本电脑。
    2. 创建两个具体工厂类:AppleFactory 和 SamsungFactory,它们实现了 ElectronicFactory 接口,并分别负责生产Apple和Samsung品牌的电子产品。
    3. 创建抽象产品类 Phone 和 Laptop,它们包含抽象方法来描述不同品牌的手机和笔记本电脑特性。
    4. 创建具体产品类:ApplePhone、SamsungPhone、AppleLaptop 和 SamsungLaptop,它们分别继承自 Phone 和 Laptop,并实现具体品牌的特性。
    5. 在客户端代码中,使用抽象工厂模式来创建不同品牌的手机和笔记本电脑,并展示它们的特性。
    6. 确保在客户端代码中可以轻松地切换不同的工厂以生产不同品牌的产品。

    你可以在评论区里或者私信我回复您的答案,这样我或者大家都能帮你解答,期待着你的回复~

  • 相关阅读:
    全面解析IEC 60364三种接地系统的概念、特点及应用
    这是什么代码帮我看看
    arcgis导出某个属性的栅格
    微信小程序毕业设计-餐厅点餐系统项目开发实战(附源码+论文)
    mysql常用操作集合
    百战RHCE(第四十七战:运维工程师必会技-Ansible学习2-Ansible安装配置练习环境)
    Python集合类型详解(二)——集合处理方法与应用场景
    致敬最美抗击疫情的逆行者 DIV布局大学生抗疫感动专题网页设计作业模板 疫情感动人物静态HTML网页模板下载
    [VUE3] Element Plus 增删拆改页组件拆解
    Redis 的内存策略
  • 原文地址:https://blog.csdn.net/guohuang/article/details/133243198