设计模式之抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式定义

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式

  • 提供了一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们的具体类。
  • 抽象工厂允许客户端使用抽象的接口来创建一组相关的产品,而具体的创建工作由具体工厂类完成。

基本概念

  • 抽象工厂(Abstract Factory):声明了一组用于创建抽象产品的方法,每个方法对应一个产品。
  • 具体工厂(Concrete Factory):实现了抽象工厂接口,负责创建具体产品对象。
  • 抽象产品(Abstract Product):为一类产品声明接口。
  • 具体产品(Concrete Product):实现了抽象产品接口,由具体工厂创建,形成产品族。

抽象工厂模式的种类

抽象工厂模式的实现方式主要有两种:

  1. 普通实现:直接使用接口或抽象类定义抽象工厂和抽象产品,具体工厂和具体产品实现这些接口。
  2. 反射机制实现:利用反射和配置文件,使得客户端可以动态地选择具体工厂,实现更高的灵活性。

使用场景

  • 需要创建一系列相关或相互依赖的对象,且需要避免指定它们的具体类。
  • 系统的产品具有多种系列,且系统只消费其中某一系列的产品。
  • 产品族概念:在抽象工厂模式中,产品族是指位于不同产品等级结构中,功能相关联的产品组成的家族。

示例:UI 组件的跨平台实现

假设我们正在开发一个跨平台的 GUI 应用程序,需要在不同的操作系统(如 Windows、Mac)上显示不同风格的按钮和文本框。使用抽象工厂模式可以很好地解决这个问题。

1. 定义抽象产品

// 抽象产品:按钮
public interface Button {
    void click();
}

// 抽象产品:文本框
public interface TextField {
    void setText(String text);
    String getText();
}

2. 定义具体产品

// Windows 风格的按钮
public class WindowsButton implements Button {
    @Override
    public void click() {
        System.out.println("Windows 风格的按钮被点击。");
    }
}

// Windows 风格的文本框
public class WindowsTextField implements TextField {
    private String text;

    @Override
    public void setText(String text) {
        this.text = text;
        System.out.println("Windows 风格的文本框设置文本:" + text);
    }

    @Override
    public String getText() {
        return text;
    }
}

// Mac 风格的按钮
public class MacButton implements Button {
    @Override
    public void click() {
        System.out.println("Mac 风格的按钮被点击。");
    }
}

// Mac 风格的文本框
public class MacTextField implements TextField {
    private String text;

    @Override
    public void setText(String text) {
        this.text = text;
        System.out.println("Mac 风格的文本框设置文本:" + text);
    }

    @Override
    public String getText() {
        return text;
    }
}

3. 定义抽象工厂

// 抽象工厂
public interface GUIFactory {
    Button createButton();
    TextField createTextField();
}

4. 定义具体工厂

// Windows 工厂
public class WindowsFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new WindowsButton();
    }

    @Override
    public TextField createTextField() {
        return new WindowsTextField();
    }
}

// Mac 工厂
public class MacFactory implements GUIFactory {
    @Override
    public Button createButton() {
        return new MacButton();
    }

    @Override
    public TextField createTextField() {
        return new MacTextField();
    }
}

5. 客户端代码

public class Client {
    public static void main(String[] args) {
        GUIFactory factory;
        Button button;
        TextField textField;

        // 根据操作系统选择具体工厂
        String osType = "Windows"; // 这可以从配置文件或系统参数获取

        if (osType.equalsIgnoreCase("Windows")) {
            factory = new WindowsFactory();
        } else if (osType.equalsIgnoreCase("Mac")) {
            factory = new MacFactory();
        } else {
            throw new IllegalArgumentException("未知的操作系统类型");
        }

        // 通过工厂创建产品
        button = factory.createButton();
        textField = factory.createTextField();

        // 使用产品
        button.click();
        textField.setText("Hello, World!");
    }
}

输出结果(在 Windows 平台)

Windows 风格的按钮被点击。
Windows 风格的文本框设置文本:Hello, World!

6. 新增产品族或产品等级结构

如果需要支持新的操作系统(如 Linux),只需添加对应的具体工厂和具体产品类,而不需要修改现有代码。

抽象工厂模式的优势

  1. 分离接口和实现:客户端使用抽象工厂来创建产品,避免了对具体产品类的依赖。
  2. 产品族一致性:确保同一工厂创建的产品属于同一产品族,避免了产品间的不兼容问题。
  3. 符合开闭原则:增加新的产品族时,只需添加新的具体工厂和产品类,无需修改现有代码。

抽象工厂模式的意义

  • 提高系统的可扩展性:通过引入新的工厂和产品,系统可以支持新的产品族,满足不断变化的需求。
  • 降低系统的耦合度:客户端通过抽象接口与工厂和产品交互,具体实现细节对客户端透明。
  • 便于产品族的切换:只需更改具体工厂,客户端即可使用不同的产品族,实现灵活的系统配置。

抽象工厂模式与工厂方法模式的区别

虽然抽象工厂模式工厂方法模式都属于创建型设计模式,都涉及到工厂和产品的概念,但它们在目的、结构和使用场景上有明显的区别。

1. 目的不同

  • 工厂方法模式:关注创建单一产品,定义一个创建对象的接口,让子类决定实例化哪一个类。其目的是将对象的创建与使用解耦。

  • 抽象工厂模式:关注创建一系列相关的产品,提供一个接口,用于创建相关或依赖的对象的家族,而无需明确指定具体类。其目的是为一组相关或相互依赖的对象提供一个一致的创建方式。

2. 结构不同

  • 工厂方法模式

    • 角色:抽象产品、具体产品、抽象工厂、具体工厂。
    • 特点:每个具体工厂只生产一种具体产品。
  • 抽象工厂模式

    • 角色:抽象工厂、具体工厂、抽象产品族、具体产品族。
    • 特点:每个具体工厂生产多个具体产品,产品组成一个产品族。

3. 使用场景不同

  • 工厂方法模式:适用于创建单个产品,客户端不需要知道具体产品的类名,只需要知道工厂接口。

  • 抽象工厂模式:适用于创建一组相关的产品,客户端需要使用这些产品,但是不需要知道具体的产品类名,只需要知道产品的接口和工厂。

4. 扩展性不同

  • 工厂方法模式:增加新的产品,需要新增具体产品类和对应的具体工厂类。

  • 抽象工厂模式

    • 增加产品等级结构(新产品类型):需要修改抽象工厂,增加新的产品创建方法,以及所有的具体工厂类,违背了开闭原则。
    • 增加产品族(新产品系列):只需新增具体工厂类和具体产品类,符合开闭原则。

5. 示例区别

  • 工厂方法模式:比如,在日志系统中,通过工厂方法模式创建不同类型的日志记录器(文件日志、数据库日志),每个工厂只创建一种日志记录器。

  • 抽象工厂模式:在跨平台的 GUI 应用中,通过抽象工厂模式创建一组相关的 UI 组件(按钮、文本框),每个工厂创建一组风格一致的组件(如 Windows 风格、Mac 风格)。

结语

抽象工厂模式提供了一种解决方案,使得客户端可以使用抽象的接口来创建一系列相关或相互依赖的对象,而无需指定它们的具体类。这在需要创建产品族的场景中非常有用,可以确保产品族的一致性。

通过区分抽象工厂模式和工厂方法模式,我们可以更好地理解设计模式的应用场景和适用条件,选择最适合的模式来解决实际问题。

启发

抽象工厂模式通过对产品族的封装,实现了对变化的隔离,体现了面向对象设计的开闭原则依赖倒置原则。这启示我们,在软件设计中,应当尽可能地面向抽象编程,减少对具体实现的依赖。

抽象 是一个架构师最重要的能力亦或者是最基础的

©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,290评论 6 491
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,107评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,872评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,415评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,453评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,784评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,927评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,691评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,137评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,472评论 2 326
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,622评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,289评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,887评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,741评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,977评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,316评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,490评论 2 348

推荐阅读更多精彩内容