所有的工厂模式都用来封装对象的创建。工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程封装的目的。
设计原则
依赖倒置原则
要依赖抽象,不要依赖具体类
定义
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。
如同定义中所说的,工厂方法让子类决定要实例化的类是哪一个。所谓的“决定”,并不是指模式允许子类本身再运行时做决定,而是指在编写创建者类时,不需要知道实际创建的产品是哪一个。选择了使用哪个子类,自然就决定了实际创建的产品是什么。
类图
代码实现
我们还是以上面咖啡店为例。
一个大的咖啡店不可能只有一个,而是遍布在全国各地,上海、北京、深圳……都会有分店。而且如果经营的好,分店还会增加。
那么,每个地区的分店虽然都是售卖咖啡,但是为了满足各地区客户的需求偏好,也会根据当地特色有些许的不同。比如上海人喜欢吃甜的,那么上海分店可能生产出来的同样的咖啡味道为偏甜,北京人口味偏咸和鲜,讲究浓,那么同样的咖啡口味就会更浓,深圳属于南方,口味清淡,那可能就会是原味咖啡居多,不放牛奶也不放糖,浓淡适中……
对于咖啡厅,从制作好咖啡到送到客户手中还需要一系列步骤,比如打包……,而这个打包的过程程序就与咖啡的类别没有太大关系。
下面我们用代码来实现:
package com.study.design.Factory.factorymethod;
/**
* 被生产对象的抽象父类
*/
public abstract class Coffe {
protected String coffeName;
public String getCoffeName() {
return coffeName;
}
}
package com.study.design.Factory.factorymethod;
public class SHLatteCoffe extends Coffe{
public SHLatteCoffe(){
coffeName = "shanghai latte";
};
}
package com.study.design.Factory.factorymethod;
public class SHMochaCoffe extends Coffe{
public SHMochaCoffe(){
coffeName = "shanghai mocha";
}
}
package com.study.design.Factory.factorymethod;
public class BJLatteCoffe extends Coffe{
public BJLatteCoffe(){
coffeName = "beijing latte";
}
}
package com.study.design.Factory.factorymethod;
public class BJMochaCoffe extends Coffe{
public BJMochaCoffe(){
coffeName = "beijing mocha";
}
}
package com.study.design.Factory.factorymethod;
public class SZLatteCoffe extends Coffe{
public SZLatteCoffe(){
coffeName = "shenzhen latte";
}
}
package com.study.design.Factory.factorymethod;
public class SZMochaCoffe extends Coffe{
public SZMochaCoffe(){
coffeName = "shenzhen mocha";
}
}
package com.study.design.Factory.factorymethod;
/**
* 咖啡店,现在它是个抽象类
* 完成生产咖啡的所有工序,但是生产咖啡的具体口味由子类决定
*/
public abstract class CoffeStores {
/**
* 生产咖啡的工厂方法
* @param type
* @return
*/
public Coffe productCoffe(int type){
Coffe coffe = makeCoffe(type);
box();
return coffe;
}
/**
* 打包
*/
private void box(){
System.out.println("packed……");
}
/**
* 工厂方法
* 生产咖啡的动作交由子类实现
* @param type
* @return
*/
protected abstract Coffe makeCoffe(int type);
}
package com.study.design.Factory.factorymethod;
/**
* 工厂类
* 上海咖啡店
*/
public class SHCoffeStores extends BJCoffeStores {
@Override
protected Coffe makeCoffe(int type) {
if (1 == type){
return new SHMochaCoffe();
}else{
return new SHLatteCoffe();
}
}
}
package com.study.design.Factory.factorymethod;
public class BJCoffeStores extends CoffeStores{
@Override
protected Coffe makeCoffe(int type) {
if (1 == type){
return new BJMochaCoffe();
}else {
return new BJLatteCoffe();
}
}
}
package com.study.design.Factory.factorymethod;
public class SZCoffeStores extends CoffeStores{
@Override
protected Coffe makeCoffe(int type) {
if (1 == type){
return new SZMochaCoffe();
}else{
return new SZLatteCoffe();
}
}
}
package com.study.design.Factory.factorymethod;
public class SHConsumer {
private CoffeStores coffeStores;
public SHConsumer(CoffeStores coffeStores){
this.coffeStores = coffeStores;
}
public void drink(int type){
Coffe coffe = coffeStores.productCoffe(type);
System.out.println("I got a cup of " + coffe.getCoffeName());
}
}
package com.study.design.Factory.factorymethod;
public class BJConsumer {
private CoffeStores coffeStores;
public BJConsumer(CoffeStores coffeStores){
this.coffeStores = coffeStores;
}
public void drink(int type){
Coffe coffe = coffeStores.productCoffe(type);
System.out.println("I got a cup of " + coffe.getCoffeName());
}
}
package com.study.design.Factory.factorymethod;
public class SZConsumer {
private CoffeStores coffeStores;
public SZConsumer(CoffeStores coffeStores){
this.coffeStores = coffeStores;
}
public void drink(int type){
Coffe coffe = coffeStores.productCoffe(type);
System.out.println("I got a cup of " + coffe.getCoffeName());
}
}
package com.study.design.Factory.factorymethod;
public class FactoryMethodTest {
public static void main(String[] args) {
// 创建三个地区的咖啡厅实例
SHCoffeStores shCoffeStores = new SHCoffeStores();
BJCoffeStores bjCoffeStores = new BJCoffeStores();
SZCoffeStores szCoffeStores = new SZCoffeStores();
// 创建三个地区的消费者
SHConsumer shConsumer = new SHConsumer(shCoffeStores);
BJConsumer bjConsumer = new BJConsumer(bjCoffeStores);
SZConsumer szConsumer = new SZConsumer(szCoffeStores);
// 消费者消费各自地区的咖啡
shConsumer.drink(1);
bjConsumer.drink(2);
szConsumer.drink(1);
}
}
要点
- 所谓工厂方法,就是有一个方法起到工厂创建对象的作用。这个方法定义为抽象的,依赖子类处理对象的创建。而在父类中又可以定义一些所有对象通用的行为,比如打包……。
- 每个抽象方法的具体实现子类,又可以看做是一个简单工厂。一般只负责创建实例对象。
- 使用者通过选择不同的子类来获取不同的对象
简单工厂与工厂方法模式的区别:
简单工厂把全部的事情,在一个地方都处理完了,而工厂方法却是创建一个框架,让子类决定如何实现具体对象的创建。简单工厂可以将对象创建出来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。
当只有一个 SHCoffeStores 的时候,工厂方法模式有什么优点?
尽管只有一个具体创建者,工厂方法模式依然很有用,它帮助我们将产品的“实现”从“使用”中解耦。如果增加新的咖啡品种,CoffeStores 不会受到影响,因为 CoffeStores 与任何 SHCoffeStores 之间都不是紧耦合的。
WX 搜索-程序员个人修养