抽象工厂模式介绍
定义:提供一个创建一系列相关或互相依赖对象的接口,而无需指定他们具体的类。
暂且不管上面的定义,我们来分析一下抽象工厂模式和工厂模式的不同之处:
在工厂模式中我们为每一个抽象产品创建了一个抽象工厂,然后为每一个具体产品提供了一个具体工厂角色,这些具体工厂角色用于创建相应的具体产品对象。(工厂方法模式);
在抽象工厂模式中,不同点是我们为多个抽象产品创建了一个抽象工厂,为所有的具体产品提供了相应的具体工厂角色,但是这些具体工厂角色并不是如同工厂方法模式中一对一,而是一个具体工厂角色对多个具体产品,每一个具体工厂角色对应的是一个产品族的具体产品类。
产品族的概念:位于不同产品等级中,功能相关联产品组成的家族。
看到这里我们应该明白工厂方法模式和抽象工厂模式的最大不同是:工厂方法模式是针对一个产品等级结构的,而抽象工厂模式是针对多个产品等级结构的。
抽象工厂模式相关角色
角色 | 功能 |
---|---|
抽象产品角色 | 是该等级产品结构中所有产品的一个抽象 |
具体产品角色 | 继承了抽象产品角色,实现了具体产品应有的功能 |
抽象工厂角色 | 是所有具体工厂角色的抽象,内部含有获取相应产品等级结构对象的抽象方法 |
具体工厂角色 | 继承了具体工厂角色,每一个具体工厂角色实现了获取所有相应产品族对象的方法,一个具体工厂角色对应一个产品族 |
抽象工厂模式UML
案例
小明有一个衣柜,里面一共有两个隔间,第一个隔间里面是上衣,第二个隔间里面是裤子。其中上衣隔间中有短袖和大衣,第二个隔间中有短裤和秋裤。请使用抽象工厂模式帮小明分别在夏天和秋天选择他应该穿的衣服。
案例分析
在这个案例中产品的等级结构非常清楚,一共有两个产品等级结构或者说产品种类——上衣和裤子,其中上衣种类产品中有两个具体产品,裤子种类产品中有两个具体产品。现在我们来分析一下具体相应的角色应该包含哪些。
(1)抽象产品角色:有两个分别是ShangYi类和KuZi类
(2)具体产品角色:同样有两大类,继承ShangYi类的有短袖和大衣,继承KuZi类的有短裤和秋裤。
(3)抽象工厂角色:只有一个AbstractFactory类,是一个抽象类,内部包含了createShangYi方法和createKuZi方法。
(4)具体工厂角色:有两个分别是SummerSuit和AutumnSuit两个类,继承了AbstractFactory抽象类。
这样我们实现了使用一个抽象工厂服务多个抽象角色的功能,同时在每一个具体工厂中都含有返回对应产品族对象的方法。
案例实现
抽象产品角色
(1)抽象上衣类
package abstracted.factory.pattern;
/**
* @Introduction 该类是一个上衣抽象类
*/
public abstract class ShangYi {
public abstract void wearShangYi();
}
(2)抽象裤子类
package abstracted.factory.pattern;
/**
* @Introduction 该类是一个裤子的抽象类
*/
public abstract class KuZi {
public abstract void wearKuZi();
}
具体产品类
(1)具体短袖类
package abstracted.factory.pattern;
/**
* @Introduction 该类是短袖类,继承了ShangYi抽象类
*/
public class Tshirt extends ShangYi{
//重写穿上衣方法
@Override
public void wearShangYi() {
System.out.println("上身穿短袖");
}
}
(2)具体大衣类
package abstracted.factory.pattern;
/**
* @Introduction 该类是大衣类,继承了ShangYi抽象类
*/
public class Overcoat extends ShangYi{
//重写穿上衣方法
@Override
public void wearShangYi() {
System.out.println("上身穿大衣");
}
}
(3)具体短裤类
package abstracted.factory.pattern;
/**
* @Introduction 该类是短裤类,继承了KuZi抽象类
*/
public class Shorts extends KuZi{
//重写了穿裤子方法
@Override
public void wearKuZi() {
System.out.println("下身穿短裤");
}
}
(4)具体秋裤类
package abstracted.factory.pattern;
/**
* @Introduction 该类是秋裤类,继承了KuZi抽象类
*/
public class LongPants extends KuZi{
//重写了穿裤子方法
@Override
public void wearKuZi() {
System.out.println("下身穿秋裤短裤");
}
}
抽象工厂类
package abstracted.factory.pattern;
/**
* @Introduction 该类是抽象工厂
*/
public abstract class AbstractFactory {
public abstract ShangYi createShangYi();
public abstract KuZi createKuZi();
}
具体工厂类
(1)夏装具体工厂类(就是使用一个具体工厂类来创建所有对应的产品族)
package abstracted.factory.pattern;
/**
* @Introduction 该类是具体工厂类,是夏日套装类,继承了AbstractFactory抽象类,在该类内部对应的产品族为短裤和短袖
*/
public class SummerSuit extends AbstractFactory{
//重写了创建上衣方法
@Override
public ShangYi createShangYi() {
return new Tshirt();
}
//重写了创建裤子方法
@Override
public KuZi createKuZi() {
return new Shorts();
}
}
(2)秋装具体工厂类(使用一个秋装具体工厂类来创建所有求装的产品族)
package abstracted.factory.pattern;
/**
* @Introduction 该类是具体工厂类,是秋日套装类,继承了AbstractFactory抽象类,在该类内部对应的产品族为秋裤和大衣
*/
public class AutumnSuit extends AbstractFactory{
//重写了创建上衣方法
@Override
public ShangYi createShangYi() {
return new Overcoat();
}
//重写了创建裤子方法
@Override
public KuZi createKuZi() {
return new LongPants();
}
}
模拟用户界面的调用该模式
package abstracted.factory.pattern;
/**
* @Introduction 该类模拟用户界面,在用户界面调用相关具体工厂类来创建对应的对象
*/
public class Main {
public static void main(String[] args) {
AbstractFactory clothFactory; //定义一个保存具体工厂对象的引用
ShangYi shangyi; //小明穿的上衣类引用
KuZi kuzi; //小明穿的裤子类引用
//小明在夏天的套装
clothFactory=new SummerSuit();
shangyi=clothFactory.createShangYi(); //获取对应的对象(在这里实现了面对接口编程)
kuzi=clothFactory.createKuZi(); //获取对应的裤子对象
shangyi.wearShangYi();
kuzi.wearKuZi();
//小明在秋天放的套装
clothFactory=new AutumnSuit();
shangyi=clothFactory.createShangYi();
kuzi=clothFactory.createKuZi();
shangyi.wearShangYi();
kuzi.wearKuZi();
}
}
运行的界面如下
抽象工厂模式优缺点及使用场景
优点:
- 在用户界面实现了面对接口编程,增加了程序的拓展性
- 当我们需要增加一个产品族的时候,我们无需修改原有类的内部代码,只需要增加相应的类。
缺点:
如果我们需要增加一个新的产品等级(新加一种新的产品,比如在上面的案例中增加一个小明的鞋子类),我们需要修改抽象工厂角色、具体工厂角色中的代码,这不符合开放-封闭原则。
使用场景:
- 系统中有多个产品族,而每次用于只需要使用一套产品族
- 系统中用户不需要知道产品是如何创建