热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

抽象工厂模式[wiki]

抽象工厂[编辑]维基百科,自由的百科全书跳转至:导航、搜索以统一塑模语言中的类型图来表示抽象工厂抽象工厂模式(英语:Abst

 

抽象工厂[编辑]
维基百科,自由的百科全书
跳转至: 导航、 搜索
以统一塑模语言中的类型图来表示抽象工厂

抽象工厂模式(英语:Abstract factory pattern)是一种软件开发设计模式。抽象工厂模式提供了一种方式,可以将一组具有同一主题的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。客户端程序不需要知道(或关心)它从这些内部的工厂方法中获得对象的具体类型,因为客户端程序仅使用这些对象的通用接口。抽象工厂模式将一组对象的实现细节与他们的一般使用分离开来。

举个例子来说,比如一个抽象工厂类叫做DocumentCreator(文档创建器),此类提供创建若干种产品的接口,包括createLetter()(创建信件)和createResume()(创建简历)。其中,createLetter()返回一个Letter(信件),createResume()返回一个Resume(简历)。系统中还有一些DocumentCreator的具体实现类,包括FancyDocumentCreatorModernDocumentCreator。这两个类对DocumentCreator的两个方法分别有不同的实现,用来创建不同的“信件”和“简历”(用FancyDocumentCreator的实例可以创建FancyLetterFancyResume,用ModernDocumentCreator的实例可以创建ModernLetterModernResume)。这些具体的“信件”和“简历”类均继承自抽象类,即LetterResume类。客户端需要创建“信件”或“简历”时,先要得到一个合适的DocumentCreator实例,然后调用它的方法。一个工厂中创建的每个对象都是同一个主题的(“fancy”或者“modern”)。客户端程序只需要知道得到的对象是“信件”或者“简历”,而不需要知道具体的主题,因此客户端程序从抽象工厂DocumentCreator中得到了LetterResume类的引用,而不是具体类的对象引用。

“工厂”是创建产品(对象)的地方,其目的是将产品的创建与产品的使用分离。抽象工厂模式的目的,是将若干抽象产品的接口与不同主题产品的具体实现分离开。这样就能在增加新的具体工厂的时候,不用修改引用抽象工厂的客户端代码。

使用抽象工厂模式,能够在具体工厂变化的时候,不用修改使用工厂的客户端代码,甚至是在运行时。然而,使用这种模式或者相似的设计模式,可能给编写代码带来不必要的复杂性和额外的工作。正确使用设计模式能够抵消这样的“额外工作”。

目录

 [隐藏] 
  • 1 定义
  • 2 使用
  • 3 结构
    • 3.1 LePUS3图
    • 3.2 类图
  • 4 代码举例
    • 4.1 C++
    • 4.2 PHP
    • 4.3 Java
  • 5 适用性
  • 6 优点
  • 7 缺点
  • 8 参考文献
  • 9 参见

定义[编辑]

抽象工厂模式的实质是“提供接口,创建一系列相关或独立的对象,而不指定这些对象的具体类。”[1]

使用[编辑]

具体的工厂决定了创建对象的具体类型,而且工厂就是对象实际创建的地方(比如在C++中,用“new”操作符创建对象)。然而,抽象工厂只返回一个指向创建的对象的抽象引用(或指针)。

这样,客户端程序调用抽象工厂引用的方法,由具体工厂完成对象创建,然后客户端程序得到的是抽象产品的引用。如此使客户端代码与对象的创建分离开来。[2]

因为工厂仅仅返回一个抽象产品的引用(或指针),所以客户端程序不知道(也不会牵绊于)工厂创建对象的具体类型。然而,工厂知道具体对象的类型;例如,工厂可能从配置文件中读取某种类型。这时,客户端没有必要指定具体类型,因为已经在配置文件中指定了。通常,这意味着:

  • 客户端代码不知道任何具体类型,也就没必要引入任何相关的头文件或类定义。客户端代码仅仅处理抽象类型。工厂确实创建了具体类型的对象,但是客户端代码仅使用这些对象的抽象接口来访问它们。[3]
  • 如果要增加一个具体类型,只需要修改客户端代码使用另一个工厂即可,而且这个修改通常只是一个文件中的一行代码。不同的工厂创建不同的具体类型的对象,但是和以前一样返回一个抽象类型的引用(或指针),因此客户端代码的其他部分不需要任何改动。这样比修改客户端代码创建新类型的对象简单多了。如果是后者的话,需要修改代码中每一个创建这种对象的地方(而且需要注意的是,这些地方都知道对象的具体类型,而且需要引入具体类型的头文件或类定义)。如果所有的工厂对象都存储在全局的单例对象中,所有的客户端代码到这个单例中访问需要的工厂,那么,更换工厂就非常简单了,仅仅需要更改这个单例对象即可。[3]

结构[编辑]

LePUS3图[编辑]

Abstract Factory in LePUS3.png

类图[编辑]

Abstract factory.svg

GuiFactory接口中的createButton方法返回Button类型的对象。返回Button的哪种实现依赖于使用GuiFactory的哪种实现。

需要注意的是,为了简洁起见,以上类图仅仅展示了创建一个类型对象的工厂。而在抽象工厂模式中,通常一个工厂能够创建若干种不同类型的对象。

代码举例[编辑]

假设我们有两种产品接口 Button 和 Border ,每一种产品都支持多种系列,比如 Mac 系列和 Windows 系列。这样每个系列的产品分别是 MacButton, WinButton, MacBorder, WinBorder 。为了可以在运行时刻创建一个系列的产品族,我们可以为每个系列的产品族创建一个工厂 MacFactory 和 WinFactory 。每个工厂都有两个方法 CreateButton 和 CreateBorder 并返回对应的产品,可以将这两个方法抽象成一个接口 AbstractFactory 。这样在运行时刻我们可以选择创建需要的产品系列。

C++[编辑]

我们的产品结构是这样的

class Button; // Abstract Classclass MacButton: public Button {};class WinButton: public Button {};class Border; // Abstract Classclass MacBorder: public Border {};class WinBorder: public Border {};

对应的工厂是这样的

class AbstractFactory {
public:virtual Button* CreateButton() =0;virtual Border* CreateBorder() =0;
};class MacFactory: public AbstractFactory {
public:MacButton* CreateButton() { return new MacButton; }MacBorder* CreateBorder() { return new MacBorder; }
};class WinFactory: public AbstractFactory {
public:WinButton* CreateButton() { return new WinButton; }WinBorder* CreateBorder() { return new WinBorder; }
};

那么客户可以根据需要选择 Mac 风格或者 Win 风格来创建 Button 或 Border

AbstractFactory* fac;
switch (style) {
case MAC:fac = new MacFactory;break;
case WIN:fac = new WinFactory;break;
}
Button* button = fac->CreateButton();
Border* border = fac->CreateBorder();


转:https://www.cnblogs.com/springbarley/p/3361474.html



推荐阅读
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 深入理解OAuth认证机制
    本文介绍了OAuth认证协议的核心概念及其工作原理。OAuth是一种开放标准,旨在为第三方应用提供安全的用户资源访问授权,同时确保用户的账户信息(如用户名和密码)不会暴露给第三方。 ... [详细]
  • 深入理解Cookie与Session会话管理
    本文详细介绍了如何通过HTTP响应和请求处理浏览器的Cookie信息,以及如何创建、设置和管理Cookie。同时探讨了会话跟踪技术中的Session机制,解释其原理及应用场景。 ... [详细]
  • QUIC协议:快速UDP互联网连接
    QUIC(Quick UDP Internet Connections)是谷歌开发的一种旨在提高网络性能和安全性的传输层协议。它基于UDP,并结合了TLS级别的安全性,提供了更高效、更可靠的互联网通信方式。 ... [详细]
  • 2023 ARM嵌入式系统全国技术巡讲旨在分享ARM公司在半导体知识产权(IP)领域的最新进展。作为全球领先的IP提供商,ARM在嵌入式处理器市场占据主导地位,其产品广泛应用于90%以上的嵌入式设备中。此次巡讲将邀请来自ARM、飞思卡尔以及华清远见教育集团的行业专家,共同探讨当前嵌入式系统的前沿技术和应用。 ... [详细]
  • 国内BI工具迎战国际巨头Tableau,稳步崛起
    尽管商业智能(BI)工具在中国的普及程度尚不及国际市场,但近年来,随着本土企业的持续创新和市场推广,国内主流BI工具正逐渐崭露头角。面对国际品牌如Tableau的强大竞争,国内BI工具通过不断优化产品和技术,赢得了越来越多用户的认可。 ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • 在计算机技术的学习道路上,51CTO学院以其专业性和专注度给我留下了深刻印象。从2012年接触计算机到2014年开始系统学习网络技术和安全领域,51CTO学院始终是我信赖的学习平台。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • 本文介绍了如何利用JavaScript或jQuery来判断网页中的文本框是否处于焦点状态,以及如何检测鼠标是否悬停在指定的HTML元素上。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ... [详细]
  • 前言--页数多了以后需要指定到某一页(只做了功能,样式没有细调)html ... [详细]
  • 本文深入探讨了 Java 中的 Serializable 接口,解释了其实现机制、用途及注意事项,帮助开发者更好地理解和使用序列化功能。 ... [详细]
author-avatar
二不-不二
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有