又是一天的修炼,今日主题是工厂模式-----Factory Pattern
工厂模式是一个很有意思的模式,因为它和另一个模式,装饰者模式,有着血缘关系,但是应用和表现形式都有着不同。其实在此之前本该先写装饰者模式-----Decorator Pattern,但是在看完这两个模式之后,决定先写工厂,主要装饰者的弊处不小,需要整合其他模式一起使用方显威力,不然其带来的不便甚至会是一场灾难。
这里先说明一下,这俩模式的血缘关系就在于同属于为了创建对象或者对象集而用。
好,进入正题。
先简单解释下,为啥它是第一层,而且还有个“方法”存在。首先,它属于工厂模式中较容易理解的一层,逻辑简单,就是为了创建某个对象所用,并且,通过一个神秘的方法,叫Factory Method来实现,只要实现了Factory Method,就能实现工厂方法模式。
接下来,想象一下这样一个场景,星巴克要建立一套咖啡购买系统,考虑到今后可能会提供非咖啡饮品,于是,很自然的搭建了这样一个结构。
很清晰对不,不同咖啡继承自饮料这个基类。当需要某个具体的咖啡的时候,只要创建对应的对象即可。
继续想象,当咖啡越来越多的时候,会怎么样。
这是什么呢?Class Explosion。。。Boommm!!!! 氪金狗眼一阵乱瞎。。。。
怎么办呢?没有关系,这时候,我们可以请出工厂方法模式来帮忙。
我们先做这样一段分析,咖啡都来自于咖啡豆的研磨,冲泡和配料的添加。那我们是否可以首先根据咖啡豆的产地,讲咖啡做一个抽象的分类,然后在按照咖啡的种类,去具体实现某种特定的咖啡呢?
好,上代码,这里就贴上Africa的咖啡豆相关代码,巴西的类似,就不贴了。
CoffeeBean:
public abstract class CoffeeBean {
public Coffee orderCoffee(String type){
Coffee c=createCoffee(type);
c.bake();
c.deliver();
return c;
}
/**
* Factory method
* @return
*/
protected abstract Coffee createCoffee(String type);;
}
AfricaCoffeeBean:
public class AfricaCoffeeBean extends CoffeeBean {
@Override
protected Coffee createCoffee(String type) {
// TODO Auto-generated method stub
if (type.equals("mocha")) {
return new AfricaMochaCoffee();
} else if (type.equals("latie")) {
return new AfricaLatieCoffee();
} else if (type.equals("cappucino")) {
return new AfricaCappucinoCoffee();
} else {
return new AfricaBlackCoffee();
}
}
}
PS:以上所有咖啡都继承自以下这个Coffee类
Coffee:
public abstract class Coffee {
String name;
public String getName(){
return this.name;
}
public void bake() {
// TODO Auto-generated method stub
}
public void deliver() {
// TODO Auto-generated method stub
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
AfricaCoffeeBean c=new AfricaCoffeeBean();
c.orderCoffee("mocha");
}
乍看之下,所谓的工厂方法模式,只是把复杂的业务逻辑分割到了3个类里面去实现。但是,仔细看CoffeeBean这个虚基类里面的orderCoffee函数,它其实是整个制作咖啡业务逻辑的主函数,但是,其实它根本不知道我到底是用了Africa还是Brazil,更不知道createCoffee返回的是哪个具体对象。也就是,orderCoffee已经被彻底的剥离于具体实现,仅仅只是一套业务逻辑。而这一切幕后功臣,就是上面那个注释有Factory Method的createCoffee。它是一个虚函数,依赖于子类的实现。子类的实现?对,就是这个,这就是工厂方法模式的核心-----let the subclass implement the creation and get the super class away from knowledge of what type of object it is dealing with. 让子类去实现对象创建,让父类处理业务逻辑而不用关心到底处理哪个具体类。同时,这也引出了,我们另一条设计原则-----Depend upon abstractions. Do not depend upon concrete classes.
如何理解这条原则呢,其实仔细看以上程序结构,假如按照之前的设计,那么父类的实现就完全依赖于创建的实体类,也就是具体哪个咖啡,那么对应的业务逻辑必须有对应的实现。这就是depend on concrete classes. 而之后的设计,上层业务逻辑依赖于Coffee这个虚基类,下层的具体咖啡对象也依赖与咖啡这个虚基类,所有,他们都依赖于一个abstraction。这样,制作咖啡的操作就和具体品种选择操作分离,并且任何一处的修改都不会影响彼此。除非,他要做一个不是咖啡的饮料,那么就另当别论。
最后给出工厂方法模式的定义-----The Factory Method Pattern defines and interface for creating an object,but lets subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
public interface CoffeeIngredientFactory {
public String putSugar();
public String putChocolate();
public String putMilk();
}
AfricaIngredientFactory:
public class AfricaIngredientFactory implements CoffeeIngredientFactory {
@Override
public String putSugar() {
// TODO Auto-generated method stub
return "Sugar for Africa coffee bean";
}
@Override
public String putChocolate() {
// TODO Auto-generated method stub
return "Chocolate for Africa coffee bean";
}
@Override
public String putMilk() {
// TODO Auto-generated method stub
return "Milk for Africa coffee bean";
}
}
public class AfricaCoffeeBean extends CoffeeBean {
CoffeeIngredientFactory factory;
public AfricaCoffeeBean() {
// TODO Auto-generated constructor stub
this.factory=new AfricaIngredientFactory();
}
@Override
protected Coffee createCoffee(String type) {
// TODO Auto-generated method stub
if (type.equals("mocha")) {
return new MochaCoffee(factory);
} else if (type.equals("latie")) {
return new LatieCoffee(factory);
} else if (type.equals("cappucino")) {
return new CappucinoCoffee(factory);
} else {
return new BlackCoffee(factory);
}
}
}
public abstract class Coffee {
String sugar;
String milk;
String chocolate;
public String getSugar() {
return sugar;
}
public String getMilk() {
return milk;
}
public String getChocolate() {
return chocolate;
}
public abstract void bake();
public void deliver() {
// TODO Auto-generated method stub
}
}
public class MochaCoffee extends Coffee {
CoffeeIngredientFactory factory;
public MochaCoffee(CoffeeIngredientFactory f) {
// TODO Auto-generated constructor stub
this.factory=f;
}
@Override
public void bake() {
// TODO Auto-generated method stub
this.sugar=factory.putSugar();
this.milk=factory.putMilk();
this.chocolate=factory.putChocolate();
}
}