设计模式(GOF)之我见(1)——Factory

时间:2022-09-08 20:58:11

前言:从本篇开始谈设计模式时应该有好些词组或者是说法可能是我杜撰的,不过可以顾名思义。我重在用通俗的话和代码说明我理解的设计模式。

一、简介

1 . 本质
Factory,工厂设计模式,属于创建型设计模式之一。它主要做到了实例化对象时用工厂方法代替new操作,将选择实现类、创建对象进行了的统一管理和控制,从而将调用者和实现类解耦。
2 . 分类
工厂模式分为如下几类:
(1). Simple Factory(简单工厂)
又称为静态工厂,用来生产同一等级结构中的任意产品。对于增加新的产品,需要修改已有的代码,违反了OCP(开闭原则)。
(2). Factory Method(工厂方法)
用来生产同一等级结构中的固定产品,支持增加任意产品。
(3). Abstract Factory(抽象工厂)
用来生产不同产品族的全部产品,不过对于增加新的产品无能为力,只能是增加产品族。

二、问题引入

既然是工厂设计模式,我们就以造汽车的工厂为例。汽车工厂可以造BMW、BYD等汽车。
首先我们来看看没有工厂模式的情形。
1. 代码结构如下:
设计模式(GOF)之我见(1)——Factory
其中Car为接口,BMW和BYD均为Car的实现类

public interface Car {
public void run();
}
public class BYD implements Car{

@Override
public void run() {
System.out.println("BYD is running");
}

}
public class BMW implements Car {

@Override
public void run() {
System.out.println("BMW is running");
}

}

现在调用者要创建BMW和BYD对象了

public class TestNoFactory {
public static void main(String[] args) {
Car c1 = new BYD();
Car c2 = new BMW();

c1.run();
c2.run();
}
}

2 . 分析上述的UML图
后面所画的UML都是用的IDE画的,方法见上篇blog(http://blog.csdn.net/u014294166/article/details/52494277)。
设计模式(GOF)之我见(1)——Factory
3. 问题来了
这里将TestNoFactory称之为调用者,那么这里想要去调用BYD和BMW的run方法,则既需要知道Car,还需要知道BYD和BMW类。需要知道的太多对调用者来说并不是什么好事,因此要引入下面的SimpleFactory来解决。

三、SimpleFactory(简单工厂)

  1. 代码结构
    设计模式(GOF)之我见(1)——Factory
    同样的,Car为接口,BMW和BYD均为Car的实现类,代码同上。如下为CarFactory.java的实现代码。
public class CarFactory {
public static Car createBMW() {
return new BMW();
}

public static Car createBYD() {
return new BYD();
}
}

当然CarFactory类里的createXX方法实现逻辑可以自己写,比如说写成如下if-else

public class CarFactory {
public static Car createCar(String carBrand) {
if ("BYD".equals(carBrand)) {
return new BYD();
} else if ("BMW".equals(carBrand)) {
return new BMW();
} else {
return null;
}
}
}

再来看看调用者是如何调用的。

public class TestSimpleFactory {
public static void main(String[] args) {
Car c1 = CarFactory.createCar("BYD");
Car c2 = CarFactory.createCar("BMW");

c1.run();
c2.run();
}
}

2 . UML图分析
设计模式(GOF)之我见(1)——Factory
3. 问题来了
经过分析可以知道,调用者TestSimpleFactory只需要Car和CarFactory就可以造出BMW和BYD,解决了没有factory时“需要知道太多”的问题。但是,也存在这么一个问题,试想如果要增加Ford汽车类,那么除了增加Ford类的代码外,还得修改CarFactory类的代码。违反了OCP(开闭原则)。下面再看看FactoryMethod方法是如何解决的OCP问题的。

四、FactoryMethod(工厂方法)

  1. 代码结构
    设计模式(GOF)之我见(1)——Factory
    CarFactory现在也是接口,BYDFactory类和BMWFactory类均为CarFactory的实现类。
public interface CarFactory {
public Car ceateCar();
}
public class BYDFactory implements CarFactory {

@Override
public Car ceateCar() {
return new BYD();
}

}
public class BMWFactory implements CarFactory {

@Override
public Car ceateCar() {
return new BMW();
}

}

再来看看调用者。

public class TestFactoryMethod {
public static void main(String[] args) {
Car c1 = new BYDFactory().ceateCar();
Car c2 = new BMWFactory().ceateCar();

c1.run();
c2.run();
}

}

2 . UML图
设计模式(GOF)之我见(1)——Factory

3 . 问题来了
工厂方法解决了simpleFactory不满足OCP原则。在工厂方法中如果需要扩展一个Ford汽车类,那么只需要创建一个Ford类和一个FordFactory类,而不需要去动其他的类。
但是存在这样一个问题:相对于simpleFactory来说,FactoryMethod增加了更多的类。其实在simpleFactory下也是可以做到增加类的,比如说在CarFactory中继续增加方法,只是这样做就会因为增加一个类还去改变了另外一个类(违反OCP)。所以可以这么理解吧,FactoryMethod以牺牲更多的类来弥补SimpleFactory违反OCP的问题。
两种模式的采取依具体而定吧,项目开发中可能simpleFactory更多。

五、AbstractFactory(抽象工厂)

这是用来生产产品族的模式,可能跟上面的两种方法不能做到很好的承上启下,我这里只是把这种思维尽量的表述清楚而已。
1 . 代码结构
设计模式(GOF)之我见(1)——Factory
其中CarFactory为接口,LowCarFactory和LuxuryCarFactory为实现CarFactory的实现类;MyEngine、MySeat、MyTyre也为接口,Luxury(low)Seat、Luxury(low)Engine、Luxury(Low)Tyre均为实现他们的类。
2 . 模型通俗化
看到上面的代码结构也就知道AbstractFactory是比较复杂的了。这些代码其实是在解决这么一个问题。我们都知道CarFactory是用来造汽车的,但是汽车也是有高低档(Luxury/Low)之分的,那么他们的高低档提现在哪里呢?体现在造车用的零配件,高档汽车就用高档的零件,低档就用低档的零件,因此就需要演化出等级结构,比如说生产发动机的等级结构,既生产高档的发动机,又生产低档的发动机;比如说生产轮胎的等级,即生产高档的轮胎也生产低档的轮胎……因此就需要抽象出MyEngine、MyTyre等接口用来生产。

/**
* 发动机:分为高端和低端发动机
* @author herdyouth
*
*/

public interface MyEngine {
public void run();
public void start();
}

当有了不同档次的零件之后,高端工厂就利用高端的零件组装高端的汽车,低端工厂就利用低端的零件组装低端的汽车,高端汽车和低端汽车就称之为产品族,而能生产(组装)出完整的高低端汽车的地方就是一个具体的工厂。

public class LuxuryCarFactory implements CarFactory {

@Override
public MyEngine createEngine() {
return new LuxuryEngine();
}

@Override
public MySeat createSeat() {
return new LuxurySeat();
}

@Override
public MyTyre createTyre() {
return new LuxuryTyre();
}

}
public class LowCarFactory implements CarFactory {

@Override
public MyEngine createEngine() {
return new LowEngine();
}

@Override
public MySeat createSeat() {
return new LowSeat();
}

@Override
public MyTyre createTyre() {
return new LowTyre();
}

}

再来看看调用者如何获取高/低档汽车的。

public class TestAbstractFactory {
public static void main(String[] args) {
CarFactory factory = new LuxuryCarFactory();
MyEngine e = factory.createEngine();
e.start();
e.run();
}
}

抽象出这样一个理解模型(这是在网上找的一个,还比较贴切),一种形状代表一种类型的产品,比如矩形都是发动机。
设计模式(GOF)之我见(1)——Factory
3 . 问题来了
有上分析知道,AbstractFactory对于增加单个新产品是无能为力的,只能新增加产品族,因为你增加单个产品就意味着得修改已有的类,违反OCP,而你增加新的产品族,就只是将已有的产品组合一下,比如说一个高档的发动机配上低档的轮胎等组成中档汽车族。

六、有了对比也没有伤害

每种方式来的最后我都做了“问题来了”的分析,即是一种对比。下面稍微“官方”或者说更抽象一点来PK一下。

1. 简单工厂模式和工厂方法模式

(1). 结构复杂度
从上面的代码结构分析知道,简单工厂没有工厂方法复杂,因为简单工厂只是需要增加一个类,而工厂方法是要增加一个相应的接口和实现类的。
(2). 代码复杂度
结构复杂度和代码复杂度是相反的。从UML图知道,工厂方法需要知道的更少。
(3). 管理难度
工厂方法模式完全满足OCP,即具有良好的扩展性。但是并不是说简单工厂方法因为不完全满足OCP就不举有良好的扩展性,简单工厂在扩展的时候其实也是只需要改动其他类的少量代码的。根据设计理论建议,是建议用工厂方法模式,但实际中一般都用的简单工厂模式,不要太拘泥于设计理论,据说jdk中也有很多没有完全满足OCP的例子。

2. 情形建议

适合使用工厂模式的情形:
(1). 有一组类似的对象需要创建;
(2). 在编码时不能预见需要创建哪种类的实例;
(3). 系统需要考虑扩展性,不应依赖于产品类实例如何被创建、组合和表达的细节

3. Factory模式要点总结

(1) . 简单工厂(静态工厂)
虽然某种程度上不符合设计原则,但实际使用最多。
(2). 工厂方法
完全符合OCP,在不修改已有类的前提下,通过增加新的工厂类实现扩展。
(3). 抽象工厂
不可以增加产品,但是可以增加产品族。

示例代码:https://github.com/herdyouth/DesignPatterns_Factory

七、Android源码中的Factory模式

1 .Android 源码中的静态工厂方法
http://mp.weixin.qq.com/s?__biz=MzA3MDMyMjkzNg==&mid=2652262004&idx=1&sn=ffe14ffbcb1f45dc67d6627642da9aa9&chksm=84dc71e3b3abf8f53eb87c722d16b3c2b9cfaa85656f2b82079578907b3032464d5480e76f46&scene=0#wechat_redirect
2 .Android源码中的工厂方法模式
http://mp.weixin.qq.com/s?__biz=MzA3MDMyMjkzNg==&mid=2652262006&idx=1&sn=75f237173d12a26faa9262e7648c7dbb&chksm=84dc71e1b3abf8f709770e0eab09906a85fde5170c067d8d3fb6fd6c5ff6f7e240547b9bd635&scene=0#wechat_redirect

=====================无聊分割线=================
GOF确实是一种很高的境界,我这里只是谈谈我的理解,可能存在问题的,希望能相互探讨。