初学设计模式(2)-----工厂模式(此心法共分2层)

又是一天的修炼,今日主题是工厂模式-----Factory Pattern

工厂模式是一个很有意思的模式,因为它和另一个模式,装饰者模式,有着血缘关系,但是应用和表现形式都有着不同。其实在此之前本该先写装饰者模式-----Decorator Pattern,但是在看完这两个模式之后,决定先写工厂,主要装饰者的弊处不小,需要整合其他模式一起使用方显威力,不然其带来的不便甚至会是一场灾难。

这里先说明一下,这俩模式的血缘关系就在于同属于为了创建对象或者对象集而用。

好,进入正题。

心法(2):工厂模式。

第一层心法-----工厂方法模式-----Factory Method 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
		
	}

}


Main:

	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.


第二层心法-----抽象工厂模式-----Abstract Factory Pattern。(就是俗称的工厂模式)

看到这个模式第一个想法就是,既然已经有了工厂方法模式,为什么还要有这个,它比工厂方法模式有啥改进的地方么?
改进或许提不上有很大的改进,至少,以我现在的理解如此,但是,它却可以处理更加精细的对象创建工作,比如之前我们还得将咖啡豆分成Africa和Brazil,在根据这俩个分出对应的4种咖啡,也就是说,我们创建了8个品种咖啡类,其中两种是相似的,只是咖啡豆不同而已。而现在,我们可以把Africa和Brazil作为工厂参数,然后只需按照Mocha,Latie,Cappuccino和Black四种类型创建四种咖啡类即可。这样,只需2个工厂和4个咖啡品种类即可实现。
那么,上代码。
CoffeeIngredientFactory:
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";
	}

}

修改后的AfricaCoffeeBean类:
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);
		}
	}

}


修改后的Coffee类:
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

	}

}

修改后的MochaCoffee类:
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();
	}
}

类似的其他咖啡品种类就不创建了。
其实看这些代码没多大的意义,甚至连我自己写完之后都懒得去看,除了要做出错处理之外。那就直接来把核心部分挑出来讲。首先,我们把原来的bake()函数给虚化了,交给了每个品种的咖啡自行实现,因为每种咖啡所需添加的佐料不同,因此,采用继承。
可以看到,我们不再在每种咖啡前面加上国家名,而是通过一个国家名命名的factory去识别是哪种国家的,并且把国家名直接创建在对应的咖啡豆里面,通过构造函数,不暴露给client code,即main函数。而佐料的添加实现都交给了对应的工厂类。还有一点可注意的是,在每种咖啡里面保存的工厂引用都是用一个接口命来声明,而不是一个concrete type,也就验证了之前工厂方法模式中的那条depend on abstraction的原则,并且,所有佐料的添加,都不是靠new出来的,而是依靠factory创建出来了,这样就将佐料添加,咖啡研磨,和咖啡订制,3套逻辑彻底隔离,且细化了咖啡的订制过程。使咖啡更加香滑可口。。。#¥%……&&***(#@!#¥¥囧
最后,我们要提到一个众人皆知的设计原则: 依赖倒置,dependency inversion. 个人理解为,就是依赖于abstraction,而不是concrete type。
那么工厂方法模式和抽象工厂模式到底何时用呢?我经验也不多,不过按照以上代码来看,前者适合在某处简单创建一个对象,并且是属于即创即用,对象本身与其他工厂创建的对象无关联;而后者,更类似于创建一套有关的对象,比如,咖啡需要sugar,milk and chocolate。这一切与coffee相关。所以,我们用抽象工厂模式的定义来解释: The Abstract Factory Pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes.
To be continued......

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值