设计模式之工厂模式
1. 简介
工厂模式(Factory Pattern)是开发中比较常用的设计模式之一.
工厂模式(Factory Pattern)简单点理解就是创建对象的模式,比如使用频率最高的单例模式就是创建型模式的一种。
这种类型的设计模式属于创建型模式(提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活)。
2. 类别
工厂模式(Factory Pattern)可以分为三种,分别是:
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
后面的两种模式都是基于第一种模式进行的。
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. 抽象工厂模式
提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类,是工厂方法模式的升级版本。
抽象工厂模式有一个缺点在于如果我们需要新增一个产品,就需要修改接口及其所有的实现类,这可能是一项很繁重的工作。
抽象工厂模式侧重一个工厂可以创建一组相关的对象;但是这组相关对象是平等地位,没有主次之分,也没有整体与部分的概念,如何使用由客户决定;
相关代码实现以后再说吧。
参考链接
设计模式之死磕工厂模式(原创)
设计模式——工厂模式
设计模式之抽象工厂模式
最后,谢谢各位读者的耐心阅读,如有语句不通顺或者不准确的地方,还请指正!谢谢!(__)