工厂模式有简单工厂模式,工厂方法模式和抽象工厂模式几种形态。其中简单工厂模式和工厂方法模式已经在前面作过介绍。在这里,我们来介绍抽象工厂模式。
抽象工厂模式是所有形态的工厂模式中最为抽象和最具广泛性的一种形态。
抽象工厂模式的定义
抽象工厂模式是工厂方法模式的进一步扩广化和抽象化。我们给出抽象工厂模式的类图定义如下。
图1. 抽象工厂模式的类图定义 |
从上图可以看出,简单工厂模式涉及到以下的角色
抽象工厂(AbstractFactory)类或接口
担任这个角色的是工厂方法模式的核心,它是与应用程序无关的。任何在模式中创立对象的工厂类必须实现这个接口,或继承这个类。
实工厂类 (Conrete Factory)
担任这个角色的是与应用程序紧密相关的,直接在应用程序调用下,创立产品实例的那样一些类。
抽象产品 (Abstract Product)
担任这个角色的类是工厂方法模式所创立的对象的父类,或它们共同拥有的接口。
实产品 (Concrete Product)
担任这个角色的类是工厂方法模式所创立的任何对象所属的类。
怎么这个类图和工厂方法模式的类图看起来是一样的?
是的,图是一样的,但是含义有很大的不同。必须指出,在抽象工厂模式中,抽象产品 (AbstractProduct) 可能是一个或多个,从而构成一个或多个产品族(Product Family)。 在只有一个产品族的情况下,抽象工厂模式实际上退化到工厂方法模式。在上面的类图中,只给出了一个产品族,相当于位图中的一个点,而完整的位图应当是三维的,如下图。
图2. 抽象工厂模式的位图 |
从位图可以清楚地看到,与纸面垂直的数轴,即第三维轴,是代表产品族的数轴。上面的位图中展示的是有两个产品族,族A和族B的情形。
在只有一个产品族时,第三维就坍缩掉,位图也就只剩下两维。这时抽象工厂模式就退化得与工厂方法模式一模一样。
在什么情形下应当使用抽象工厂模式
在以下情况下,应当考虑使用抽象工厂模式。
首先,一个系统应当不依赖于产品类实例被创立,组成,和表示的细节。这对于所有形态的工厂模式都是重要的。
其次,这个系统的产品有多于一个的产品族。
第三,同属于同一个产品族的产品是设计成在一起使用的。这一约束必须得在系统的设计中体现出来。
最后,不同的产品以一系列的接口的面貌出现,从而使系统不依赖于接口实现的细节。
其中第二丶第三个条件是我们选用抽象工厂模式而非其它形态的工厂模式的关键性条件。
抽象工厂模式在小花果园系统中的实现
现在,我们在佛罗里达的渡假小屋修整好啦。接下来,一项重要而光荣的工作,就是开发小屋后面的小花园。这意味着,我们有两处小花园需要照料,一处在北方地区,另一处在亚热带地区。抽象工厂模式正好适用于我们的情况。
图3. 抽象工厂模式应用于小花果园系统中。三种不同的背景颜色可以区分工厂类,蔬菜类(第一产品族),和水果类的类图(第二产品族) |
两处花园就相当于两个产品族。显然,给北方花园的植物是要种植在一起的,给南方花园的植物是要另种植在一起的。这种分别应当体现在系统的设计上面。这就满足了应当使用抽象工厂模式的第二和第三个条件。
相关代码如下:
创建JAVA工程
新建三个包:
分别为:factory.impl 存放接口
factory.action 存放类
factory.test 测试类
源代码如下:可运行:
1. FruitIF 接口
package factory.impl;
/**
* 类说明 水果接口
* @author zhaoguoli
* @version v1.0 创建时间:2009-4-10 下午02:09:11
*/
public interface FruitIF {
public String getName();
}
2.Gardener 接口
package factory.impl;
/**
* 类说明 园艺爱好者接口类
* @author zhaoguoli
* @version v1.0 创建时间:2009-4-10 下午01:57:59
*/
public interface Gardener {
// 返回蔬菜类接口
public VeggieIF createVeggie(String name);
// 返回水果类接口
public FruitIF createFruit(String name) ;
}
3.FruitIF 接口
package factory.impl;
/**
* 类说明 水果接口
* @author zhaoguoli
* @version v1.0 创建时间:2009-4-10 下午02:09:11
*/
public interface FruitIF {
public String getName();
}
package factory.action;
import factory.impl.FruitIF;
/**
* 类说明 南方水果实现类
* @author zhaoguoli
* @version v1.0 创建时间:2009-4-10 下午02:14:09
*/
public class NorthernFruit implements FruitIF {
public String name;
public NorthernFruit(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package factory.action;
import factory.impl.FruitIF;
import factory.impl.Gardener;
import factory.impl.VeggieIF;
/**
* 类说明 南方园艺受好者
*
* @author zhaoguoli
* @version v1.0 创建时间:2009-4-10 下午01:59:25
*/
public class NorthernGardener implements Gardener {
// 返回蔬菜类接口
public VeggieIF createVeggie(String name) {
return new NorthernVeggie(name);
}
// 返回水果类接口
public FruitIF createFruit(String name) {
return new NorthernFruit(name);
}
}
package factory.action;
import factory.impl.VeggieIF;
/**
* 类说明 南方菜实现类
* @author zhaoguoli
* @version v1.0 创建时间:2009-4-10 下午02:11:58
*/
public class NorthernVeggie implements VeggieIF {
private String name;
public NorthernVeggie(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package factory.action;
import factory.impl.FruitIF;
/**
* 类说明 北方水果实现类
* @author zhaoguoli
* @version v1.0 创建时间:2009-4-10 下午02:20:57
*/
public class SouthernFruit implements FruitIF {
public String name;
public SouthernFruit(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package factory.action;
import factory.impl.FruitIF;
import factory.impl.Gardener;
import factory.impl.VeggieIF;
/**
* 类说明
* @author zhaoguoli
* @version v1.0 创建时间:2009-4-10 下午02:23:52
*/
public class SouthernGardener implements Gardener {
// 返回蔬菜类接口
public VeggieIF createVeggie(String name) {
return new SouthernVeggie(name);
}
// 返回水果类接口
public FruitIF createFruit(String name) {
return new SouthernFruit(name);
}
}
package factory.action;
import factory.impl.VeggieIF;
/**
* 类说明 北方菜实现类
* @author zhaoguoli
* @version v1.0 创建时间:2009-4-10 下午02:22:02
*/
public class SouthernVeggie implements VeggieIF {
public String name;
public SouthernVeggie(String name){
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package factory.test;
import factory.action.NorthernGardener;
import factory.action.SouthernGardener;
import factory.impl.Gardener;
/**
* 类说明 测试抽象工厂模式
* @author zhaoguoli
* @version v1.0 创建时间:2009-4-10 下午02:26:18
*/
public class FactoryTest {
/**
* 方法说明:
* @param args
*/
public static void main(String[] args) {
// TODO 自动生成方法存根
// 南方园艺者生产花和菜
String name = null;
// 南方园艺者生产花和菜
NorthernGardener northernGardener = new NorthernGardener();
Gardener gardener = (Gardener)northernGardener;
name = "香蕉";
System.out.println(northernGardener.createFruit(name).getName());
name = "南菜";
System.out.println(northernGardener.createVeggie(name).getName());
// 北方园艺者生产花和菜
SouthernGardener southernGardener = new SouthernGardener();
name = "苹果";
System.out.println(southernGardener.createFruit(name).getName());
name = "北菜";
System.out.println(southernGardener.createVeggie(name).getName());
}
}
运行结果如下:
香蕉
南菜
苹果
北菜
spring使用时,会将园艺者接口中也定义方法,一切尽量用接口。