在阅读本篇以前,为了方便理解,请首先阅读本博的“JAVA设计模式之简单工厂(Simple Factory)模式”和“JAVA设计模式之工厂方法(Factory Method)模式”。
抽象工厂模式是对象的创建模式,它是工厂方法模式的进一步推广。抽象工厂的“抽象”来自于“抽象的产品角色”,而抽象工厂就是抽象产品角色的工厂。每一个设计模式都是针对一系列的问题的解决方案。抽象模式就是针对多个等级产品结构的系统而设计的。抽象工厂模式就是向客户端提供一个接口,使得客户端在不必知道产品的具体类型的情况下,创建多个产品族中的产品。
抽象工厂中的各个角色又是怎么样的呢?
抽象工厂(Abstract Factory)角色:该角色是工厂方法模式的核心,它是以应用程序无关的。它往往由接口或抽象类来实现。所有的具体工厂类都应该实现这个Java接口或是继承这个Java类。
具体工厂(Concrete Factory)角色:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑与系统的商业逻辑紧密相连。通常用具体的Java类来实现这个角色。
抽象产品(Abstract Product)角色:工厂方法模式所创建的对象的父类或它们的共同接口,它往往由接口或抽象类来实现。
具体产品(Concrete Product)角色:抽象工厂所创建的任何产品对象都是某一个具体产品的实例。这是客户端最终需要的东西。
下面我们就来看看,这几个角色在代码中是怎么展现的。
1、创建抽象产品,这里我们创建两个抽象产品。两个动物类别(哺乳动物和鸟类动物)。
package org.dbablog.abstractfactory;
/**
* Title: DesignPattern
* Description: 哺乳动物接口
* Work: Programmer
* @author 蛋蛋
* @version 1.0
* @Date Sep 9, 2008
* Copyright: Copyright (c) 2008
*/
public interface ILactationAnimal {
/**
* 哺乳
*/
public void suckle();
/**
* 胎生
*/
public void viviparity();
} |
package org.dbablog.abstractfactory;
/**
* Title: DesignPattern
* Description: 鸟类动物接口
* Work: Programmer
* @author 蛋蛋
* @version 1.0
* @Date Sep 9, 2008
* Copyright: Copyright (c) 2008
*/
public interface IBirdAnimal {
/**
* 飞行
*/
public void fly();
} |
2、创建具体产品都是实现抽象产品的接口来的。
package org.dbablog.abstractfactory;
/**
* Title: DesignPattern
* Description: 狗类实现哺乳动物接口
* Work: Programmer
* @author 蛋蛋
* @version 1.0
* @Date Sep 9, 2008
* Copyright: Copyright (c) 2008
*/
public class Dog implements ILactationAnimal {
/**
* 哺乳
*/
public void suckle() {
print("狗狗正在哺乳");
}
/**
* 胎生
*/
public void viviparity() {
print("狗妈妈要生小狗狗了");
}
/**
* 打印输出的辅助方法
* @param message 打印内容
*/
public static void print(String message) {
System.out.println(message);
}
} |
package org.dbablog.abstractfactory;
/**
* Title: DesignPattern
* Description: 喜鹊实现鸟类接口
* Work: Programmer
* @author 蛋蛋
* @version 1.0
* @Date Sep 9, 2008
* Copyright: Copyright (c) 2008
*/
public class Magpie implements IBirdAnimal {
/**
* 飞行
*/
public void fly() {
print("喜鹊在空中飞");
}
/**
* 打印输出的辅助方法
* @param message 打印内容
*/
public static void print(String message){
System.out.println(message);
}
} |
3、这下我们的代码就有层次结构关系了。哺乳类(狗),鸟类(喜鹊)。那下面我们就来创建抽象工厂吧。
package org.dbablog.abstractfactory;
/**
* Title: DesignPattern
* Description: 抽象工厂角色,工厂的核心类
* Work: Programmer
* @author 蛋蛋
* @version 1.0
* @Date Sep 9, 2008
* Copyright: Copyright (c) 2008
*/
public interface IAnimalFactory {
/**
* 工厂方法
* @return 鸟类接口
*/
public IBirdAnimal birdFactory();
/**
* 工厂方法
* @return 哺乳类接口
*/
public ILactationAnimal lactationFactory();
} |
4、创建具体工厂类,必须实现抽象工厂这个接口或者抽象类。
package org.dbablog.abstractfactory;
/**
* Title: DesignPattern
* Description: 具体工厂,动物工厂
* Work: Programmer
* @author 蛋蛋
* @version 1.0
* @Date Sep 9, 2008
* Copyright: Copyright (c) 2008
*/
public class AnimalFactory implements IAnimalFactory {
/**
* 实现工厂方法
*/
public IBirdAnimal birdFactory() {
return new Magpie();
}
/**
* 实现工厂方法
*/
public ILactationAnimal lactationFactory() {
return new Dog();
}
} |
5、测试一下我们所做的结果,和前面的两个工厂有什么不同吧。
package org.dbablog.abstractfactory;
/**
* Title: DesignPattern
* Description: 测试类
* Work: Programmer
* @author 蛋蛋
* @version 1.0
* @Date Sep 10, 2008
* Copyright: Copyright (c) 2008
*/
public class Test {
/**
* AnimalFactory这个具体工厂在客户端的调用下创建产品的实例。
*/
public static void main(String[] args) {
IBirdAnimal magpie = new AnimalFactory().birdFactory();
magpie.fly();
ILactationAnimal dog = new AnimalFactory().lactationFactory();
dog.suckle();
dog.viviparity();
}
} |
6、客户端所要的结果是出来了,那到底抽象工厂模式的好处在哪?现在和大家讲讲它所支持的“开-闭”原则(理论在“JAVA设计模式之简单工厂(Simple Factory)模式”中提到过,有兴趣的可以看看,在这不再啰嗦)。
现在我们要做的就是不修改原来代码的基础上,加上一个新功能。比方说,我们加个猪类(哺乳动物)和布谷鸟(鸟类)。
6.1、创建具体产品吧。
package org.dbablog.abstractfactory;
/**
* Title: DesignPattern
* Description: 猪类实现哺乳动物接口
* Work: Programmer
* @author 蛋蛋
* @version 1.0
* @Date Sep 9, 2008
* Copyright: Copyright (c) 2008
*/
public class Pig implements ILactationAnimal {
/**
* 哺乳
*/
public void suckle() {
print("猪猪正在哺乳");
}
/**
* 胎生
*/
public void viviparity() {
print("猪妈妈要生小猪猪了");
}
/**
* 打印输出的辅助方法
* @param message 打印内容
*/
public static void print(String message) {
System.out.println(message);
}
} |
package org.dbablog.abstractfactory;
/**
* Title: DesignPattern
* Description: 布谷鸟类
* Work: Programmer
* @author 蛋蛋
* @version 1.0
* @Date Sep 9, 2008
* Copyright: Copyright (c) 2008
*/
public class Cuckoo implements IBirdAnimal {
/**
* 飞行
*/
public void fly() {
print("布谷鸟在田里飞");
}
/**
* 打印输出的辅助方法
* @param message 打印内容
*/
public static void print(String message){
System.out.println(message);
}
} |
6.1.2、我们可以在不用修改原代码的基础上,再创建一个新的具体工厂。
package org.dbablog.abstractfactory;
/**
* Title: DesignPattern
* Description: 新加的具体工厂
* Work: Programmer
* @author 蛋蛋
* @version 1.0
* @Date Sep 10, 2008
* Copyright: Copyright (c) 2008
*/
public class NewAnimalFactory implements IAnimalFactory {
public IBirdAnimal birdFactory() {
return new Cuckoo();
}
public ILactationAnimal lactationFactory() {
return new Pig();
}
} |
6.1.3、测试下,看是不是一切OK了,要加什么产品完全不用去修改原代码,想要什么就加什么。
package org.dbablog.abstractfactory;
/**
* Title: DesignPattern
* Description: 测试类
* Work: Programmer
* @author 蛋蛋
* @version 1.0
* @Date Sep 10, 2008
* Copyright: Copyright (c) 2008
*/
public class Test {
/**
* AnimalFactory这个具体工厂在客户端的调用下创建产品的实例。
*/
public static void main(String[] args) {
IBirdAnimal magpie = new AnimalFactory().birdFactory();
magpie.fly();
ILactationAnimal dog = new AnimalFactory().lactationFactory();
dog.suckle();
dog.viviparity();
IBirdAnimal cuckoo = new NewAnimalFactory().birdFactory();
cuckoo.fly();
ILactationAnimal pig = new NewAnimalFactory().lactationFactory();
pig.suckle();
pig.viviparity();
}
} |
总结:
在什么情况下使用抽象工厂模式?
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节。这对于所有的工厂模式都是重要的。
- 这个系统的产品有多余一个产品族,而系统只消费某一族的产品。
- 同属于一个产品族中的产品是在一起使用的,这一约束必须在系统的设计中体现出来的。
- 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。