实例代码(JAVA):模式动机

    在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。
    为了更清晰地理解工厂方法模式,需要先引入两个概念:
    • 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
    • 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
产品族与产品等级结构示意图:

    当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。
    抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态。
    抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。
 

模式定义

    抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。

模式结构

 

抽象工厂模式包含如下角色:
• AbstractFactory:抽象工厂
• ConcreteFactory:具体工厂
• AbstractProduct:抽象产品
• Product:具体产品

模式分析

 

抽象工厂类的典型代码如下:

 public abstract class AbstractFactory
{
public abstract AbstractProductA createProductA();
public abstract AbstractProductB createProductB();
}

 具体工厂类的典型代码如下:

 public class ConcreteFactory1 extends AbstractFactory
{
public AbstractProductA createProductA()
{
return new ConcreteProductA1();
}
public AbstractProductB createProductB()
{
return new ConcreteProductB1();
}
}

模式实例与解析

实例一:电器工厂
    • 一个电器工厂可以产生多种类型的电器,如海尔工厂可以生产海尔电视机、海尔空调等,TCL工厂可以生产TCL电视机、TCL空调等,相同品牌的电器构成一个产品族,而相同类型的电器构成了一个产品等级结构,现使用抽象工厂模式模拟该场景。
 
 

实例代码(JAVA):

 //抽象产品 Television
public interface Television
{
public void play();
} //具体产品 HaierTelevision
public class HaierTelevision implements Television
{
public void play()
{
System.out.println("海尔电视机播放中......");
}
} //具体产品 TCLTelevision
public class TCLTelevision implements Television
{
public void play()
{
System.out.println("TCL电视机播放中......");
}
} //抽象产品 AirConditioner
public interface AirConditioner
{
public void changeTemperature();
} //具体产品 HaierAirConditioner
public class HaierAirConditioner implements AirConditioner
{
public void changeTemperature()
{
System.out.println("海尔空调温度改变中......");
}
} //具体产品 TCLAirConditioner
public class TCLAirConditioner implements AirConditioner
{
public void changeTemperature()
{
System.out.println("TCL空调温度改变中......");
}
} //抽象工厂 EFactory
public interface EFactory
{
public Television produceTelevision();
public AirConditioner produceAirConditioner();
} //具体工厂 HaierFactory
public class HaierFactory implements EFactory
{
public Television produceTelevision()
{
return new HaierTelevision();
} public AirConditioner produceAirConditioner()
{
return new HaierAirConditioner();
}
} //具体工厂 TCLFactory
public class TCLFactory implements EFactory
{
public Television produceTelevision()
{
return new TCLTelevision();
} public AirConditioner produceAirConditioner()
{
return new TCLAirConditioner();
}
} //配置文件 config.xml
<?xml version="1.0"?>
<config>
<className>HaierFactory</className>
</config> //通过反射获得具体工厂的实例 XMLUtil
import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
public class XMLUtil
{
//该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
public static Object getBean()
{
try
{
//创建文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("config.xml")); //获取包含类名的文本节点
NodeList nl = doc.getElementsByTagName("className");
Node classNode=nl.item(0).getFirstChild();
String cName=classNode.getNodeValue(); //通过类名生成实例对象并将其返回
Class c=Class.forName(cName);
Object obj=c.newInstance();
return obj;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
} //客户端类 Client
public class Client
{
public static void main(String args[])
{
try
{
EFactory factory;
Television tv;
AirConditioner ac;
factory=(EFactory)XMLUtil.getBean();
tv=factory.produceTelevision();
tv.play();
ac=factory.produceAirConditioner();
ac.changeTemperature();
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
}

实例代码(C++):

 // 抽象工厂模式
#include <iostream>
using namespace std; //抽象产品类 Television
class Television
{
public:
virtual void play() = ;
}; //具体产品类 HaierTelevision
class HaierTelevision:public Television
{
public:
void play() override
{
cout << "海尔电视播放中..." << endl;
}
}; //具体产品类 TCLTelevision
class TCLTelevision : public Television
{
public:
void play() override
{
cout << "TCL电视播放中..." << endl;
}
}; //抽象产品 AirConditioner
class AirConditioner
{
public:
virtual void changeTemperature() = ;
}; //具体产品 HaierAirConditioner
class HaierAirConditioner : public AirConditioner
{
public:
void changeTemperature() override
{
cout << "海尔空调温度改变中..." << endl;
}
}; //具体产品 TCLAirConditioner
class TCLAirConditioner : public AirConditioner
{
public:
void changeTemperature() override
{
cout << "TCL空调温度改变中..." << endl;
}
}; //抽象工厂 EFactory
class EFactory
{
public:
virtual Television* productTelevision() = ;
virtual AirConditioner* productAirConditioner() = ;
}; //具体工厂 HaierFactory
class HaierFactory : public EFactory
{
public:
Television* productTelevision() override
{
return new HaierTelevision();
} AirConditioner* productAirConditioner() override
{
return new HaierAirConditioner();
}
}; //具体工厂 TCLFactory
class TCLFactory : public EFactory
{
public:
Television* productTelevision() override
{
return new TCLTelevision();
} AirConditioner* productAirConditioner() override
{
return new TCLAirConditioner();
}
}; //客户端
int main()
{
EFactory* factory;
Television* tv;
AirConditioner* ac;
factory = new HaierFactory();
tv = factory->productTelevision();
tv->play();
ac = factory->productAirConditioner();
ac->changeTemperature(); factory = new TCLFactory();
tv = factory->productTelevision();
tv->play();
ac = factory->productAirConditioner();
ac->changeTemperature();
return ;
}
 运行结果:
 

实例二:数据库操作工厂
    • 某系统为了改进数据库操作的性能,自定义数据库连接对象Connection和语句对象Statement,可针对不同类型的数据库提供不同的连接对象和语句对象,如提供Oracle或SQL Server专用连接类和语句类,而且用户可以通过配置文件等方式根据实际需要动态更换系统数据库。使用抽象工厂模式设计该系统。
 

模式优缺点

优点
    • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。
    • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。
    • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
缺点
    • 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
    • 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)

模式适用环境

在以下情况下可以使用抽象工厂模式:
    • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。
    • 系统中有多于一个的产品族,而每次只使用其中某一产品族。
    • 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
    • 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

模式应用

    (1) Java SE AWT(抽象窗口工具包)
        • 在Java语言的AWT(抽象窗口工具包)中就使用了抽象工厂模式,它使用抽象工厂模式来实现在不同的操作系统中应用程序呈现与所在操作系统一致的外观界面。
    (2) 在很多软件系统中需要更换界面主题,要求界面中的按钮、文本框、背景色等一起发生改变时,可以使用抽象工厂模式进行设计。

模式扩展

“开闭原则”的倾斜性
    • “开闭原则”要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
        • (1) 增加产品族:对于增加新的产品族,工厂方法模式很好的支持了“开闭原则”,对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。
        • (2) 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,不能很好地支持“开闭原则”。
    • 抽象工厂模式的这种性质称为“开闭原则”的倾斜性,抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,但不能为新的产品等级结构的增加提供这样的方便。
工厂模式的退化
    • 当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。

抽象工厂模式(JAVA反射)的更多相关文章

  1. 设计模式之第2章-抽象工厂模式(Java实现)

    设计模式之第2章-抽象工厂模式(Java实现) “上次是我的不对,贿赂作者让我先讲来着,不过老婆大人大人有大量,不与我计较,这次还让我先把上次未讲完的应用场景部分给补充上去,有妻如此,夫复何求.”(说 ...

  2. C#设计模式之:抽象工厂模式与反射

    抽象工厂模式[实例]:定义一个用于创建对象的接口,让子类决定实例化哪一个类 UML 代码class User{    private int _id;    public int Id { get = ...

  3. 抽象工厂模式--java代码实现

    抽象工厂模式 抽象工厂模式,对方法工厂模式进行抽象.世界各地都有自己的水果园,我们将这些水果园抽象为一个水果园接口,在中国.英国和美国都有水果园,种植不同的水果,比如苹果.香蕉和梨等.这里将苹果进行抽 ...

  4. 设计模式之抽象工厂模式(Java实现)

    “上次是我的不对,贿赂作者让我先讲来着,不过老婆大人大人有大量,不与我计较,这次还让我先把上次未讲完的应用场景部分给补充上去,有妻如此,夫复何求.”(说完,摸了摸跪的发疼的膝盖,咳咳,我发四我没笑!真 ...

  5. AbstractFactoryPattern(抽象工厂模式)-----Java/.Net

    抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂.该超级工厂又称为其他工厂的工厂.

  6. Java设计模式(三) 抽象工厂模式

    原创文章,同步发自作者个人博客,转载请注明出处 http://www.jasongj.com/design_pattern/abstract_factory/ 抽象工厂模式解决的问题 上文<工厂 ...

  7. iOS 抽象工厂模式

    iOS 抽象工厂模式 什么是抽象工厂模式 简单了解一下 按照惯例,我们先了解一下什么是抽象工厂模式.抽象工厂模式和工厂方法模式很相似,但是抽象工厂模式将抽象发挥的更加极致,是三种工厂模式中最抽象的一种 ...

  8. 重学 Java 设计模式:实战抽象工厂模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获!

  9. JAVA设计模式--抽象工厂模式

    抽象工厂设计模式 1.系统中有多个产品族,而系统一次只可能消费其中一族产品2.同属于同一个产品族的产品以其使用.来看看抽象工厂模式的各个角色(和工厂方法的如出一辙):抽象工厂角色: 这是工厂方法模式的 ...

随机推荐

  1. 841. 字符串哈希(hash)

    给定一个长度为n的字符串,再给定m个询问,每个询问包含四个整数l1,r1,l2,r2l1,r1,l2,r2,请你判断[l1,r1l1,r1]和[l2,r2l2,r2]这两个区间所包含的字符串子串是否完 ...

  2. 使用yum安装报错:[Errno 256] No more mirrors to try

    背景:我使用yum方式安装软件时,比如zabbix这种软件,我们在安装时一般都是直接到zabbix官网,按照官方的步骤进行安装,但是有一个问题,官方的服务器不在国内,时常会在安装时导致超时报错.此时解 ...

  3. Web基础-Uri跟Url的区别

    关于URL和URI的区别,个人见解.    初学java,最近被一个概念搞得头晕脑胀,就是url和uri的概念和区别,网上查了一大通,发现各种回答眼花缭乱,有百科直接粘贴的,有胡说八道的,有故意绕来绕 ...

  4. .gitignore文件说明-git提交时可忽略的文件

    在我们平时做项目时,总有一些文件不想提交到服务器的版本管理上 这时就要设置相应的忽略规则,来忽略这些文件的提交 规则 作用/mtk 过滤整个文件夹*.zip 过滤所有.zip文件/mtk/do.c 过 ...

  5. MySQL 8.0.18 在 Windows Server 2019 上的安装(ZIP)公开

    AskScuti MySQL : Windows Server 2019 安装 MySQL 8.0 温馨提示:为了展现我最“魅力”的一面,请用谷歌浏览器撩我. 一切就绪,点我开撩

  6. python面试的100题(21)

    正则表达式 94.请写出一段代码用正则匹配出ip? ip地址的生成规则. IP地址,是由32位数字二进制转为四个十进制的字符串组成. 怎么转化?下面讲解: 二进制:111111111111111111 ...

  7. react中用swiper实现大图功能

    1.引入Swiper(用的是4.5.0版本)      import Swiper from 'swiper';      //引入样式,还可以加上自己的样式      import '../../s ...

  8. [TJOI2017] DNA - 后缀数组,稀疏表

    [TJOI2017] DNA Description 求模式串与主串的匹配次数,容错不超过三个字符. Solution 枚举每个开始位置,进行暴力匹配,直到失配次数用光或者匹配成功.考虑到容错量很小, ...

  9. 五、抗DDOS防火墙

    简介 DDoS全名是Distribution Denial of service (分布式拒绝服务攻击).拒绝服务攻击的攻击方式有很多种,最基本的Dos攻击就是利用合理的服务请求来占用过多的服务资源, ...

  10. Hydra暴力破解工具

    hydra [[[-l LOGIN|-L FILE] [-p PASS|-P FILE]] | [-C FILE]] [-e nsr] [-o FILE] [-t TASKS] [-M FILE [- ...