淘先锋技术网

首页 1 2 3 4 5 6 7

设计模式之工厂模式

1. 简介

工厂模式(Factory Pattern)是开发中比较常用的设计模式之一.

工厂模式(Factory Pattern)简单点理解就是创建对象的模式,比如使用频率最高的单例模式就是创建型模式的一种。

这种类型的设计模式属于创建型模式(提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活)。

2. 类别

工厂模式(Factory Pattern)可以分为三种,分别是:

  1. 简单工厂模式
  2. 工厂方法模式
  3. 抽象工厂模式

后面的两种模式都是基于第一种模式进行的。

3. 简单工厂模式

3.1 需求

支付宝推广蚂蚁森林,假设要在库布其种植树苗(梭梭树、樟子松、胡杨等),根据用户兑换的幼苗,蚂蚁森林会进行对应幼苗的获取、挖坑、入坑、填土、浇水。

3.2 普通实现方式

3.2.1 由于有多种树苗,所以首先设计一个接口Tree来表示树苗(该类具有幼苗的获取、挖坑、入坑、填土、浇水等功能),接着定义多个Tree的实现类来实现相应树的接口功能。下面定义树接口Tree及其3个接口实现类PinusSylvestrisVar、Populus、sacsaoul。

/** 树接口 */
public interface Tree {
	/** 获取幼苗 */
	public void getSeedling();
	
	/** 挖坑 */
	public void digHollow();
	
	/** 幼苗入坑 */
	public void putSeedingIntoHollow();
	
	/** 填土 */
	public void fillSoil();
	
	/** 浇水 */
	public void watering();
	
}
/** 樟子松 */
public class PinusSylvestrisVar implements Tree {

	@Override
	public void getSeedling() {
		System.out.println("获取樟子松幼苗。");
	}

	@Override
	public void digHollow() {
		System.out.println("挖适合种樟子松幼苗的坑。");
	}

	@Override
	public void putSeedingIntoHollow() {
		System.out.println("将樟子松幼苗放入坑中。");
	}

	@Override
	public void fillSoil() {
		System.out.println("给樟子松幼苗填土。");
	}

	@Override
	public void watering() {
		System.out.println("给樟子松幼苗浇水。");
	}
}
/** 胡杨 */
public class Populus implements Tree {

	@Override
	public void getSeedling() {
		System.out.println("获取胡杨幼苗。");
	}

	@Override
	public void digHollow() {
		System.out.println("挖适合种胡杨幼苗的坑。");
	}

	@Override
	public void putSeedingIntoHollow() {
		System.out.println("将胡杨幼苗放入坑中。");
	}

	@Override
	public void fillSoil() {
		System.out.println("给胡杨幼苗填土。");
	}

	@Override
	public void watering() {
		System.out.println("给胡杨幼苗浇水。");
	}
}
/** 梭梭树 */
public class sacsaoul implements Tree {

	@Override
	public void getSeedling() {
		System.out.println("获取梭梭幼苗。");
	}

	@Override
	public void digHollow() {
		System.out.println("挖适合种梭梭幼苗的坑。");
	}

	@Override
	public void putSeedingIntoHollow() {
		System.out.println("将梭梭幼苗放入坑中。");
	}

	@Override
	public void fillSoil() {
		System.out.println("给梭梭幼苗填土。");
	}

	@Override
	public void watering() {
		System.out.println("给梭梭幼苗浇水。");
	}
}

3.2.2 接下来需要根据用户的选择进行对应树苗的获取、挖坑、入坑、填土、浇水等操作,所以需要定义一个TreeStoreSimple类,其中有一个方法plantTheTree将这些操作包含进去。

public class TreeStoreSimple {
	public void plantTheTree(String treeType) throws Exception {
		Tree tree = null;
		switch(treeType) {
			case "PinusSylvestrisVar":  tree = new PinusSylvestrisVar();break;
			case "Populus": tree = new Populus();break;
			case "sacsaoul": tree = new sacsaoul();break;
			default: throw new Exception("树类型不准确!");
		}
		
		tree.getSeedling();
		tree.digHollow();
		tree.putSeedingIntoHollow();
		tree.fillSoil();
		tree.watering();
	}
}

3.2.3 上面代码有一个很明显的问题,假设除了TreeStoreSimple以外的一个A类也要根据树类型获取相应的树对象,那么switch中的代码也要再写一遍,如果蚂蚁森林要新增一个树种“沙柳”,就必须将TreeStoreSimple与A中的相应代码进行修改,这样不利于代码维护,增加了维护成本。因此,此处就可以使用简单工厂模式进行实现。

3.3 简单工厂模式实现方式

专门创建一个SimpleTreeFactory类将创建Tree对象的过程单独剥离开来。

public class SimpleTreeFactory {

	public Tree createTree(String treeType) throws Exception {
		Tree tree = null;
		switch(treeType) {
			case "PinusSylvestrisVar":  tree = new PinusSylvestrisVar();break;
			case "Populus": tree = new Populus();break;
			case "sacsaoul": tree = new sacsaoul();break;
			default: throw new Exception("树类型不准确!");
		}
		return tree;
	}
}

修改TreeStoreSimple类

public class TreeStoreSimpleFactory {
	SimpleTreeFactory stf;
	public TreeStoreSimple(SimpleTreeFactory stf) {
		this.stf = stf;
	}
	
	public void plantTheTree(String treeType) throws Exception {
		Tree tree = stf.createTree(treeType);
		
		tree.getSeedling();
		tree.digHollow();
		tree.putSeedingIntoHollow();
		tree.fillSoil();
		tree.watering();
	}
	
	public static void main(String[] args) {
		try {
			SimpleTreeFactory stf = new SimpleTreeFactory();
			TreeStoreSimple ts = new TreeStoreSimple(stf);
			ts.plantTheTree("PinusSylvestrisVar");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

看了上述的案例,现在我们来总结一下:其实简单工厂不是一个设计模式,反而比较像一种编程习惯,将创建对象的过程从对象使用者中分离开来,这样就可以通过简单工厂专门负责创建产品了。在上面的例子中,SimpleTreeFactory就是专门负责创建产品的简单工厂。

4. 工厂方法模式

在工厂方法模式中,定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。

工厂方法让类把实例化推迟到子类。选择了使用哪个子类,自然就决定了实际创建的产品是什么。工厂方法模式通过让子类决定创建的对象是什么,来达到将对象创建的过程封装的目的。以下是代码(其中的Tree及其3个接口实现类PinusSylvestrisVar、Populus、sacsaoul参考3中的实现):

public interface TreeFactory {
	/** 获取Tree对象 */
	Tree createTree();
}
public class PinusSylvestrisVarFactory implements TreeFactory {

	@Override
	public Tree createTree() {
		return new PinusSylvestrisVar();
	}
}
public class PopulusFactory implements TreeFactory {

	@Override
	public Tree createTree() {
		return new Populus();
	}
}
public class SacsaoulFactory implements TreeFactory {

	@Override
	public Tree createTree() {
		return new Sacsaoul();
	}
}
public class TreeStoreMethod {
	TreeFactory tf;
	public TreeStoreMethod(TreeFactory tf) {
		this.tf = tf;
	}
	
	public void plantTheTree() throws Exception {
		Tree tree = tf.createTree();
		
		tree.getSeedling();
		tree.digHollow();
		tree.putSeedingIntoHollow();
		tree.fillSoil();
		tree.watering();
	}

	public static void main(String[] args) {
		try {
			PinusSylvestrisVarFactory psvf = new PinusSylvestrisVarFactory();
			TreeStoreMethod tsm = new TreeStoreMethod(psvf);
			tsm.plantTheTree();
			System.out.println("-----------------------");
			PopulusFactory pf = new PopulusFactory();
			tsm = new TreeStoreMethod(pf);
			tsm.plantTheTree();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

5. 抽象工厂模式

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类,是工厂方法模式的升级版本。

抽象工厂模式有一个缺点在于如果我们需要新增一个产品,就需要修改接口及其所有的实现类,这可能是一项很繁重的工作。

抽象工厂模式侧重一个工厂可以创建一组相关的对象;但是这组相关对象是平等地位,没有主次之分,也没有整体与部分的概念,如何使用由客户决定;

相关代码实现以后再说吧。

参考链接

设计模式之死磕工厂模式(原创)
设计模式——工厂模式
设计模式之抽象工厂模式

最后,谢谢各位读者的耐心阅读,如有语句不通顺或者不准确的地方,还请指正!谢谢!(__)