抽象工厂模式针对的是对一系列产品进行扩展的问题。
工厂方法模式针对的是对一类产品进行替换的问题。这两种要区分开。
比如房屋装修,你找装修公司,每个装修公司都有自己的一套装修方案,用的瓷砖,木板,桌子,椅子每个公司都不一样,你选用不同的装修公司,这一套产品都要跟着换,这就是抽象工厂模式的使用环境。
而工厂方法模式就好像是一个司机开车,开的是什么车,只对车这个产品进行替换,是同类产品间的替换。容易引起工厂泛滥。
下面来看一个例子,模拟一个场景
一个人开着XXX交通工具,拿着XXX武器,吃着XXX食物,去东北。。。。。
对于这个场景,我有几套方案,如果换的话要把整套的都替换掉。
比如我又两套方案
(1)交通工具是Car,武器是Ak47,食物是Apple
(2)交通工具是Broom(哈利波特的扫帚),武器是MagicStrick,食物是Mushroom
首先我们要对交通工具,武器,食物,分别提供一个接口或者抽象类,代码如下:
package com.feng.factory.abstractfactory;
public abstract class Vehicle {
public abstract void run();
}
package com.feng.factory.abstractfactory;
public abstract class Weapon {
public abstract void shoot();
}
package com.feng.factory.abstractfactory;
public abstract class Food {
public abstract void printName();
}
然后,我们把具体的交通工具,武器,食物都构造出来,分别继承相应的抽象类,或者是实现相应的接口
先看交通工具类,实现两个类,Car和Broom
package com.feng.factory.abstractfactory;
public class Car extends Vehicle{
public void run()
{
System.out.println("开着车,车跑了。。。。。");
}
}
package com.feng.factory.abstractfactory;
public class Broom extends Vehicle{
public void run()
{
System.out.println("起着扫帚去东北。。。");
}
}
再看武器类,实现两个类,AK47和MagicStrick
package com.feng.factory.abstractfactory;
public class Ak47 extends Weapon{
public void shoot()
{
System.out.println("使用AK47射击。。。。。");
}
}
package com.feng.factory.abstractfactory;
public class MagicStrick extends Weapon{
public void shoot()
{
System.out.println("使用魔法棒攻击敌人。。。");
}
}
再看食物类,实现两个类,Apple和Mushroom
package com.feng.factory.abstractfactory;
public class Apple extends Food{
public void printName()
{
System.out.println("Apple");
}
}
package com.feng.factory.abstractfactory;
public class Mushroom extends Food{
public void printName()
{
System.out.println("Mushroom");
}
}
对于每一套方案,我们都应该有一个工厂,工厂要有一个统一的接口
先看统一的接口
package com.feng.factory.abstractfactory;
public abstract class AbstractFactory {
public abstract Vehicle createVehicle();
public abstract Weapon createWeapon();
public abstract Food createFood();
}
每套方案都要继承这个抽象类,这里有两套方案,一种是DefaultFactory对应第一套方案,另一种是MagicFactory对应第二套方案
package com.feng.factory.abstractfactory;
public class DefaultFactory extends AbstractFactory{
@Override
public Vehicle createVehicle() {
// TODO Auto-generated method stub
return new Car();
}
@Override
public Weapon createWeapon() {
// TODO Auto-generated method stub
return new Ak47();
}
@Override
public Food createFood() {
// TODO Auto-generated method stub
return new Apple();
}
}
package com.feng.factory.abstractfactory;
public class MagicFactory extends AbstractFactory{
@Override
public Vehicle createVehicle() {
// TODO Auto-generated method stub
return new Broom();
}
@Override
public Weapon createWeapon() {
// TODO Auto-generated method stub
return new MagicStrick();
}
@Override
public Food createFood() {
// TODO Auto-generated method stub
return new Mushroom();
}
}
最后就是测试:
package com.feng.factory.abstractfactory;
public class Test {
public static void main(String[] args) {
//现在有一个用户,这个用户拿着Ak47,吃着苹果,开着车
AbstractFactory factory = new DefaultFactory();
Vehicle c = factory.createVehicle();
c.run();
Weapon w = factory.createWeapon();
w.shoot();
Food f = factory.createFood();
f.printName();
}
}
执行结果:
如果想换成另一套方案的话,在测试类中将AbstractFactory factory = new DefaultFactory(); 改为 AbstractFactory factory = new MagicFactory();即可其他的地方不需要改变
执行结果如下:
如果想增加新的方案,增加一个新的工厂即可,工厂继承AbstractFactory,如果要增加新的规定类型的产品,新建类就可以。
但是如果要添加新的类型,例如上面的例子
一个人开着XXX交通工具,拿着XXX武器,吃着XXX食物,去东北。。。。。
现在我要更改需求了,改为:
一个人开着XXX交通工具,拿着XXX武器,听着xxx音乐,吃着XXX食物,去东北。。。。。
这样的话新添加了一种类型,这种变化对抽象工厂模式的扩展是非常不利的。会引起大部分文件内容的改变。