Yves

工厂模式

工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。

工厂模式分类:

简单工厂模式

组成

  • 工厂类
    工厂模式中的核心,包含一定的判断逻辑。
  • 抽象产品类
  • 具体产品类

UML

实例

某玩具店老板,想要卖一种新型玩具,并且有不同的颜色分类,所以他找到某厂商订制生产。

抽象产品类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package factory;
/**
* 某新型玩具
*
* Created by yves on 17-2-6.
*/
public abstract class Toy {
/**
* 产品的共性
* @return
*/
public int getSize(){
return 10;
}
/**
* 抽象的产品个性
*
* @return
*/
public abstract String getColor();
}

具体的产品:

1
2
3
4
5
6
7
8
9
10
11
12
13
package factory.toys;
import factory.Toy;
/**
* Created by yves on 17-2-6.
*/
public class RedToy extends Toy {
@Override
public String getColor() {
return "Red";
}
}

产品的工厂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package factory;
/**
* 某玩具生产厂商
*
* Created by yves on 17-2-6.
*/
public class ToyFactory {
/**
* 生产方法,输入的参数可以自行定义
* 一般为String,Enum,Class等,或为空,用于判断具体生产哪种产品
*
* @param c
* @return
*/
public static Toy create(Class<? extends Toy> c){
Toy toy = null;
try {
toy = (Toy) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return toy;
}
}

客户端:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package factory;
import factory.toys.RedToy;
/**
* 某玩具店
*
* Created by yves on 17-2-6.
*/
public class Client {
public static void main(String[] args){
Toy toy = ToyFactory.create(RedToy.class);
System.out.println(toy.getColor());
}
}

工厂方法模式

从上面的栗子中看到,具体生产什么还是由工厂决定的,这样工厂和产品的耦合度还是比较高的,如果不是使用反射,而是使用其他参数进行产品类型判断的话,显然需要一堆的if else 或者switch

从现实中的应用来看,这也是不合理的,一条生产线,如果既生产甲类产品,又生产乙类产品的话,那么效率肯定是特别低的。因此需要把工厂拆分成几个不同的生产线,专注于生产不同的产品。

工厂方法模式就是在简单工厂的基础上,抽象生产方法,至于生产什么,由其子类决定。

组成

  • 抽象工厂
  • 具体工厂,即生产线
  • 抽象产品
  • 具体产品

UML

实例

抽象后的工厂:

1
2
3
4
5
6
7
8
9
10
11
12
package factory;
/**
* 某玩具生产厂商
* <p>
* Created by yves on 17-2-6.
*/
public interface ToyFactory {
Toy create();
}

生产线:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package factory.lines;
import factory.Toy;
import factory.ToyFactory;
import factory.toys.RedToy;
/**
* 红色玩具生产线
*
* Created by yves on 17-2-6.
*/
public class RedToyLine implements ToyFactory{
@Override
public Toy create() {
return new RedToy();
}
}

客户端:

1
2
3
4
5
6
7
8
9
10
11
12
public class Client {
public static void main(String[] args){
ToyFactory factory = new RedToyLine();
Toy toy = factory.create();
System.out.println(toy.getColor());
}
}

这样,如果增加需求,生产蓝色或者其他颜色的产品,只要增加一条生产线就可以了,而不是直接去修改原有的判断逻辑,这是符合开闭原则的。

上面的两个栗子对比一下,似乎简单工厂模式更好一点,工厂方法模式中需要在客户端指定具体的生产线,产品的更替必然带来生产线的变化,反而变得更加繁琐。这是因为第一个栗子中使用了反射机制的缘故,省去了原本繁琐的逻辑判断。但是反射往往意味着效率的降低,这在移动端是需要多加考虑的。而如果不用反射,在需求变动的情况下,无疑第二种方法更为合理。

抽象工厂模式

抽象工厂模式的定义是:为客户端提供一个接口,可以创建一组相关或相互依赖的对象,而且无需指定它们的具体类。

抽象工厂模式与工厂方法模式的区别就在于需要创建对象的复杂程度上。

抽象工厂模式需要满足以下条件:

  • 系统中有多个产品族
  • 同属于同一个产品族的产品一起使用

组成

抽象工厂模式的组成和工厂方法模式一样

  • 抽象工厂
  • 具体工厂,即生产线
  • 抽象产品
  • 具体产品

但是从UML图上看无疑复杂不少:

实例

玩具店的老板觉得原本的生意还是不够好,一件玩具卖出去了就完了,如果有这是消耗型的玩具,那就更好了。于是一种新的玩具出炉了。玩具分成了AB两个部分,而且B部分是消耗型的。

由于发展良好,生产商也开设了分厂了。
抽象的工厂:

1
2
3
4
5
6
7
public interface ToyFactory {
ToyA createA();
ToyB createB();
}

假设AB按相同颜色作为配对的话,那么相同颜色的AB就作为同一族一起生产。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 红色玩具生产厂房
*
* Created by yves on 17-2-6.
*/
public class RedToyFactory implements ToyFactory{
@Override
public ToyA createA() {
return new RedToyA();
}
@Override
public ToyB createB() {
return new RedToyB();
}
}

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Client {
public static void main(String[] args){
ToyFactory factory = new RedToyFactory();
ToyA toyA = factory.createA();
ToyB toyB = factory.createB();
System.out.println(toyA.getColor() + "的A 配合 " + toyB.getColor() + "的B 一起使用");
}
}

抽象工厂模式的优缺点

抽象工厂模式的优点是封装性,不关心对象是如何创建出来的,只要知道工厂类是谁,就可以创建一个对象出来。

但其最大的缺点是产品族扩展非常困难。假设需要在原本的AB族中添加一个C产品,抽象类或接口中就需要增加一个createC()方法,这样其所有实现类都需要修改,这就违反了开闭原则了。