内容简介:简单的案例实现抽象工厂模式,分析抽象工厂的优势与存在的问题。
单例模式 Build 模式
简单工厂根据对象类型信息创建对象,但责任太重,不符合单一职责原则;工厂模式引入等级结构,解决了简单工厂责任太重的问题,那抽象工厂的主要作用是什么呢?
如果要区分工厂和抽象工厂,理解产品等级结构和产品簇是必要条件。
图片引自:https://www.cnblogs.com/lfxiao/p/6811820.html
上图展示了产品等级和产品簇之间的区别。
在横坐标方向,图形分正方形,原型,椭圆;在纵坐标方向上,为每种图形的不同颜色。产品等级结构是相同产品的不同表现形式,比如车->黑色的车->白色的车,在产品等级结构中,所有的产品都有共同的基类;产品簇是具有某种相同属性的不同产品,比如黑色的宝马车->黑色的自行车->黑色的手扶拖拉机,在产品簇中,所有的产品拥有相同的约束–黑色的车。
为创建一组或具有相同约束的对象提供一个接口。
一个产品由相同的约束。比如都是黑色的交通工具,都是黑色的图形……
在介绍工厂模式时,使用的示例如下:
工厂的基类 Factory 定义了createAnimal 方法,具体的工厂根据待生产的产品的不同分 CatFactory 和 DogFactory ,这两个 Factory 的子类分别用于新建 Cat 对象和 Dog 对象。
假设现在对猫 Animal 进行具体化,分为黑颜色的猫 BlackCat ,白颜色的猫 WhiteCat ,黑颜色的狗 BlackDog ,白颜色的狗 WhiteDog ,如果使用工厂模式,结构图如下:
可以发现系统中的类会成对增加,造成这种情况的原因在于每个工厂只能生产一种具体的产品,每增加一个产品均需要新建一个工厂,那有没有什么方法能够避免这种情况的出现呢?
在以上的示例中,白色的狗 WhiteDog 和白色的猫 WhiteCat 都是相同颜色的动物,相同颜色的狗和猫是相同颜色的小动物,将他们放在同一个产品簇中,修改后的结构如下:
如果继续添加黑色的猪 BlackPig ,白色的猪 WhitePig ,则只需要增加新的 Animal 类型,在 Factory 中添加对应的 create 方法即可,不会出现类急剧增多的情况。
具体实现如下:
public interface Animal {
void eat();
}
public class Cat implements Animal {
private String color;
public Cat(String color) {
// TODO Auto-generated constructor stub
this.color = color;
}
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println(color + " cat eats");
}
}
public class Dog implements Animal {
private String color;
public Dog(String color) {
// TODO Auto-generated constructor stub
this.color = color;
}
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println(color + " dog eats");
}
}
public abstract class AbstractAnimalFactory {
abstract Animal makeCat();
abstract Animal makeDog();
}
public class BlackAnimalFactory extends AbstractAnimalFactory {
@Override
Animal makeCat() {
// TODO Auto-generated method stub
return new Cat("black");
}
@Override
Animal makeDog() {
// TODO Auto-generated method stub
return new Dog("black");
}
}
public class WhiteAnimalFactory extends AbstractAnimalFactory {
@Override
Animal makeCat() {
// TODO Auto-generated method stub
return new Cat("white");
}
@Override
Animal makeDog() {
// TODO Auto-generated method stub
return new Dog("white");
}
}
测试代码如下:
public static void main(String [] args) {
AbstractAnimalFactory whiteAnimalFactory = new WhiteAnimalFactory();
Cat whiteCat = (Cat) whiteAnimalFactory.makeCat();
Dog whiteDog = (Dog) whiteAnimalFactory.makeDog();
whiteCat.eat();
whiteDog.eat();
AbstractAnimalFactory blackAnimalFactory = new BlackAnimalFactory();
Cat blackCat = (Cat) blackAnimalFactory.makeCat();
Dog blackDog = (Dog) blackAnimalFactory.makeDog();
blackCat.eat();
blackDog.eat();
}
运行结果如下:
white cat eats white dog eats black cat eats black dog eats
似乎抽象工厂很完美,现在有一个新的需求过来了,需要在系统中添加白色的猪 WhitePig 和黑色的猪 BlackPig 。突然发现在原有的抽象工厂结构中,如果需要添加这两种 Animal ,需要对 Factory 进行修改,添加 makePig 方法,同时 WhiteAnimalFactory 和 BlackAnimalFactory 都需要实现 makePig 方法。
这样的设计违反了开闭原则(一个软件实体应当对扩展开放,对修改关闭),有没有什么办法解决这个问题呢?抽象工厂无法解决这样的问题。可以发现,使用抽象工厂时,增加产品簇(在本文中可以理解为为现有动物添加新的颜色分类)可以满足开闭原则,但是增加产品等级结构(在本文中可以理解为增加新的动物),就需要对原结构进行大量的修改。
简单工厂侧重根据类型信息创建对象,但是不符合单一职责原则;工厂模式中每个工厂只生产一种具体的产品,如果产品过多,可能会导致系统中存在大量的工厂类;抽象工厂将工厂模式中相关的产品组成产品簇,由一个工厂生产,减少了系统中类的数量。
使用抽象工厂增加产品簇符合开闭原则,但增加产品等级结构不满足开闭原则。
在使用抽象工厂模式之前,需要设计好产品簇和产品等级结构,防止由于增加产品等级结构而造成系统大幅度的改动。
–END–
识别二维码,关注我们