设计模式学习-工厂方法模式

工厂方法模式介绍

工厂方法模式(Factory Pattern),是创建型设计模式之一。是一种结构简单的模式,在平时开发中应用很广泛。如Android中Activity里的各个生命周期方法,以onCreate方法为例,它可以看作成一个工厂方法,我们在其中可以构造我们的view,并通过setContentView返回给framework处理。

工厂方法模式的定义

定义一个创建对象的接口,让子类决定实例化哪个类

工厂方法模式的使用场景

在任何需要生成复杂对象的地方,都可以使用工厂方法模式。复杂对象适合使用工厂方法,用new就可以完成创建的对象无需使用工厂模式。

工厂方法模式的UML图

角色介绍:

  • Factory:抽象工厂,为工厂模式的核心
  • ConcreteFactory:具体工厂,实现具体的业务逻辑
  • Product:抽象产品,是工厂方法模式所创建的产品的父类
  • ConcreteProduct:具体产品,是实现抽象产品的某个具体产品的对象

根据图可以得出如下一个工厂方法模式的通用代码。

1
2
3
4
5
6
7
8
9
10
/**
* <pre>
* author : 残渊
* time : 2019/03/27
* desc : 产品类的抽象类,里面的方法由具体的产品类去实现
* </pre>
*/
public abstract class Product {
public abstract void method();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* <pre>
* author : 残渊
* time : 2019/03/27
* desc : 具体产品类A
* </pre>
*/
public class ConcreteProductA extends Product {
@Override
public void method() {
System.out.println("我是具体的产品A");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* <pre>
* author : 残渊
* time : 2019/03/27
* desc : 具体的产品类B
* </pre>
*/
public class ConcreteProductB extends Product{
@Override
public void method() {
System.out.println("我是具体的产品B");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* <pre>
* author : 残渊
* time : 2019/03/27
* desc : 抽象工厂类
* </pre>
*/
public abstract class Factory {
/**
* 抽象工厂方法,具体的生产由子类实现
* @return
*/
public abstract Product createProduct();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* <pre>
* author : 残渊
* time : 2019/03/27
* desc : 具体工厂类
* </pre>
*/
public class ConcreteFactory extends Factory {
@Override
public Product createProduct() {
return new ConcreteProductA();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* <pre>
* author : 残渊
* time : 2019/03/27
* desc : 客户类
* </pre>
*/
public class Client {
public static void main(String [] args){
Factory factory = new ConcreteFactory();
Product p = factory.createProduct();
p.method();
}
}

上述代码中在Client类中构造了一个产品对象,这时候得到的产品对象是ConcreteProductA的实例,如果想要得到ConcreteProductB的实例的话,直接在ConcreteFactory中的逻辑即可。

1
2
3
4
5
6
7
public class ConcreteFactory extends Factory {
@Override
public Product createProduct() {
return new ConcreteProductB();
//return new ConcreteProductA();
}
}

有时我们还利用反射的方式更加简洁的来生产具体的产品对象,此时工厂方法的参数列表中就得传入一个class类来决定生产哪个产品

1
2
3
4
5
6
7
public abstract class Factory {
/**
* 抽象工厂方法,具体的生产由子类实现
* @return
*/
public abstract <T extends Product> T createProduct(Class<T> concreteProduct);
}

对于具体的工厂类,则通过反射获取类的实例即可

1
2
3
4
5
6
7
8
9
10
11
12
13
public class ConcreteFactory extends Factory {

@Override
public <T extends Product> T createProduct(Class<T> concreteProduct) {
Product p = null;
try{
p = (Product)Class.forName(concreteProduct.getName()).newInstance();
}catch (Exception e){
e.printStackTrace();
}
return (T)p;
}
}

最后来看看Client的实现

1
2
3
4
5
6
7
public class Client {
public static void main(String [] args){
Factory factory = new ConcreteFactory();
Product p = factory.createProduct(ConcreteProductB.class);
p.method();
}
}

工厂方法模式的简单实现

场景:小渊是一家组装电脑厂的厂长,主要的生产的电脑品牌有联想、戴尔、苹果三种,由于组装三种电脑的流程差不多,故对小渊来说,一条生产线足以应对3种品牌。故对于该类生产线小渊定义了一个抽象类定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* <pre>
* author : 残渊
* time : 2019/03/27
* desc : 工厂抽象类
* </pre>
*/
public abstract class ComputerFactory {
/**
* 抽象方法
* @param concreteComputer
* @param <T>
* @return
*/
public abstract <T extends Computer> T createComputer(Class<T> concreteComputer);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
**
* <pre>
* author : 残渊
* time : 2019/03/27
* desc : 具体工厂类
* </pre>
*/
public class ConcreteComputerFactory extends ComputerFactory {
@Override
public <T extends Computer> T createComputer(Class<T> concreteComputer) {
Computer computer = null;
try{
computer = (Computer) Class.forName(concreteComputer.getName()).newInstance();
}catch (Exception e){
e.printStackTrace();
}
return (T) computer;
}
}

具体的产品类以及具体产品类如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* <pre>
* author : 残渊
* time : 2019/03/27
* desc : 抽象产品-电脑
* </pre>
*/
public abstract class Computer {
/**
* 定义电脑一个行为方法,电脑开机
*/
public abstract void action();

/**
* 定义电脑一个行为方法,电脑关机
*/
public abstract void shutdown();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* <pre>
* author : 残渊
* time : 2019/03/27
* desc : 具体产品类-联想品牌
* </pre>
*/
public class LenovoComputer extends Computer {
@Override
public void action() {
System.out.println("联想电脑开机了");
}

@Override
public void shutdown() {
System.out.println("联想电脑关机了");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* <pre>
* author : 残渊
* time : 2019/03/27
* desc : 具体产品类-戴尔
* </pre>
*/
public class DellComputer extends Computer {
@Override
public void action() {
System.out.println("戴尔电脑开机了");
}

@Override
public void shutdown() {
System.out.println("戴尔电脑关机了");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* <pre>
* author : 残渊
* time : 2019/03/27
* desc : 具体产品类 - 苹果
* </pre>
*/
public class AppleComputer extends Computer {
@Override
public void action() {
System.out.println("苹果电脑开机了");
}

@Override
public void shutdown() {
System.out.println("苹果电脑关机了");
}
}

最后来看看客户端的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* <pre>
* author : 残渊
* time : 2019/03/27
* desc : 电脑客户端
* </pre>
*/
public class ComputerClient {
public static void main(String[] args){
ComputerFactory factory = new ConcreteComputerFactory();
Computer lenovo = factory.createComputer(LenovoComputer.class);
lenovo.action();
lenovo.shutdown();

Computer apple = factory.createComputer(AppleComputer.class);
apple.action();
apple.shutdown();

Computer dell = factory.createComputer(DellComputer.class);
dell.action();
dell.shutdown();
}
}

输出结果如下:

联想电脑开机了
联想电脑关机了
苹果电脑开机了
苹果电脑关机了
戴尔电脑开机了
戴尔电脑关机了

总结

  • 优点 :降低了对象之间的耦合度,而且工厂方法模式依赖于抽象的架构,其实例化的任务交由子类完成,故具扩展性。
  • 缺点:每次我们为工厂方法模式添加新产品时就要编写一个新的产品类,同时引用抽象层,会导致类结构的复杂化,故在某些简单情况下,是否使用工厂方法模式就得权衡。
-------------本文结束感谢您的阅读-------------