之前我们介绍了Factory Pattern工厂模式,其较适合于只有一种类型产品的场景。但有些时候一家工厂可能会生产多种类型的产品。比如家电厂无论海尔还是美的,都会生产冰箱、洗衣机、空调等多种不同类型的产品。这个时候,就可以应用我们这里所说的Abstract Factory Pattern抽象工厂模式
简介
这里我们以家电厂商为例来进入引入介绍。对于海尔,美的这些家电厂商而言,其会去生产销售冰箱,洗衣机,空调等这些产品。换句话说,在这里,一家工厂将不再是只提供一种产品了,而是会去提供多种产品。所以对于Abstract Factory Pattern抽象工厂模式而言,其和Factory Pattern工厂模式相比,最大的不同就在于抽象工厂角色和具体工厂角色部分。这里我们先来简单介绍下Abstract Factory Pattern抽象工厂模式下的角色
- 抽象产品角色:其定义了具体产品的实现类所具有的共有方法,一般通过接口实现。本文中即为Refrigerator、AirConditioner、WashingMachine接口类。它们分别定义了各自产品的公共特性
- 具体产品角色:其是抽象产品角色的具体实现类,即是客户真正需要的产品。这里即为不同家电厂家所提供的产品
- 抽象工厂角色:其定义了不同家电厂商的工厂的通用接口,用以提供该家电厂商所生产的各种不同种类的产品。故这也是其于Factory Pattern工厂模式最大的区别之处,后者(工厂模式)只提供一种类型的产品
- 具体工厂角色:其是抽象工厂的具体实现类,一个具体的工厂类负责提供其生产多种类型的产品这里提出一个重要概念,产品族,而工厂方法是针对单个产品
实践
现在让我们利用上文所提到的不同家电厂商(海尔、美的)的多种家电产品(空调、洗衣机、冰箱)为例,通过代码进行地具体演示。相信大家对于抽象产品角色、具体产品角色的设计应该是比较熟悉的了。这里我们先给出冰箱的接口及具体实现类
/**
* 抽象产品角色: 冰箱
*/
public interface Refrigerator {
/**
* 冰冻食物
*/
void iceFood();
}
...
/**
* 具体产品-美的冰箱
*
*/
public class MediaRefrigerator implements Refrigerator {
/**
* 冰冻食物
*/
@Override
public void iceFood() {
System.out.println("美的冰箱正在制冷食物!");
}
}
...
/**
* 具体产品-海尔冰箱
*
*/
public class HaierRefrigerator implements Refrigerator {
/**
* 冰冻食物
*/
@Override
public void iceFood() {
System.out.println("海尔冰箱正在制冷食物!");
}
}
接下来空调,洗衣机
/**
* 抽象产品角色: 空调
*/
public interface AirConditioner {
/**
* 空调制冷
*/
void cool();
}
...
/**
* 具体产品-美的空调
*/
public class MediaAirConditioner implements AirConditioner {
/**
* 空调制冷
*/
@Override
public void cool() {
System.out.println("美的空调正在制冷");
}
}
...
/**
* 具体产品-海尔空调
*/
public class HaierAirConditioner implements AirConditioner {
/**
* 空调制冷
*/
@Override
public void cool() {
System.out.println("海尔空调正在制冷");
}
}
...
/**
* 抽象产品角色: 洗衣机
*/
public interface WashingMachine {
/**
* 洗衣服
*/
void wash();
}
...
/**
* 具体产品-美的洗衣机
*/
public class MediaWashingMachine implements WashingMachine {
/**
* 洗衣服
*/
@Override
public void wash() {
System.out.println("美的洗衣机正在洗衣服!");
}
}
...
/**
* 具体产品-海尔洗衣机
*/
public class HaierWashingMachine implements WashingMachine {
/**
* 洗衣服
*/
@Override
public void wash() {
System.out.println("海尔洗衣机正在洗衣服!");
}
}
现在我们来定义一个抽象工厂角色——即家用电器厂商的接口类HouseholdElectricAppliancesFactory,其可以提供各种不同类型产品
/**
* 抽象工厂-家用电器
*/
public interface HouseholdElectricAppliancesFactory {
/**
* 提供空调产品
*
* @return
*/
AirConditioner getAirConditioner();
/**
* 提供冰箱产品
*
* @return
*/
Refrigerator getRefrigerator();
/**
* 提供洗衣机产品
*
* @return
*/
WashingMachine getWashingMachine();
}
有了抽象工厂角色,那么具体的工厂角色就简单了。本文就是Media、Haier的工厂类MediaFactory、HaierFactory,Client通过各自家电厂商的工厂类就可以获取相应的产品了
/**
* 具体工厂-美的工厂
*/
public class MediaFactory implements HouseholdElectricAppliancesFactory{
/**
* 提供空调产品
*
* @return
*/
@Override
public AirConditioner getAirConditioner() {
return new MediaAirConditioner();
}
/**
* 提供冰箱产品
*
* @return
*/
@Override
public Refrigerator getRefrigerator() {
return new MediaRefrigerator();
}
/**
* 提供洗衣机产品
*
* @return
*/
@Override
public WashingMachine getWashingMachine() {
return new MediaWashingMachine();
}
}
/**
* 具体工厂-海尔工厂
*/
public class HaierFactory implements HouseholdElectricAppliancesFactory{
/**
* 提供空调产品
*
* @return
*/
@Override
public AirConditioner getAirConditioner() {
return new HaierAirConditioner();
}
/**
* 提供冰箱产品
*
* @return
*/
@Override
public Refrigerator getRefrigerator() {
return new HaierRefrigerator();
}
/**
* 提供洗衣机产品
*
* @return
*/
@Override
public WashingMachine getWashingMachine() {
return new HaierWashingMachine();
}
}
至此我们的抽象工厂模式就已经实现完毕了,那么现在就通过一个测试用例来看看是否可以正常工作。
public class AbstrctFactoryDemoTest {
public static void main(String[] args) {
System.out.println("-----Media Test--------");
HouseholdElectricAppliancesFactory heaf = new MediaFactory();
AirConditioner airConditioner = heaf.getAirConditioner();
Refrigerator refrigerator = heaf.getRefrigerator();
WashingMachine washingMachine = heaf.getWashingMachine();
airConditioner.cool();
refrigerator.iceFood();
washingMachine.wash();
System.out.println("-----Haier Test--------");
HouseholdElectricAppliancesFactory heaf1= new HaierFactory();
AirConditioner airConditioner1 = heaf1.getAirConditioner();
Refrigerator refrigerator1 = heaf1.getRefrigerator();
WashingMachine washingMachine1 = heaf1.getWashingMachine();
airConditioner1.cool();
refrigerator1.iceFood();
washingMachine1.wash();
}
}
测试结果 |
---|
开闭原则的倾斜性
开闭原则是指对扩展开放、对修改封闭,通过扩展的方式来实现功能的增强。而在Abstract Factory Pattern抽象工厂模式下,如果我们期望在本文例子中再增加一个家电厂商格力,那么就只需要添加格力的工厂类及相关产品类即可,即此种功能拓展是符合开闭原则的;但如果是期望增加一种新的家电产品,比如空气净化器,那么我们不仅需要添加相关的产品类,更重要的是我们还需要在现有的工厂类(包括抽象工厂角色和具体工厂角色)中添加方法,而这种功能拓展显然就违背了开闭原则。综上所述,在Abstract Factory Pattern抽象工厂模式中开闭原则是有倾斜性的