设计模式——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 风格文本框

在这个示例中:

  • 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 风格文本框
    }
}

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 风格文本框
}

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 风格文本框

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

#include <iostream>

// 抽象产品:按钮
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;
}

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. 确保在客户端代码中可以轻松地切换不同的工厂以生产不同品牌的产品。

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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

guohuang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值