设计模式-工厂模式

工厂模式属于创建型模式。
工厂模式有四种类型:

  • 工厂方法模式
  • 抽象工厂模式
  • 静态工厂方法
  • 简单工厂模式

不使用设计模式

  • 当我一个人在家写代码,我不使用设计模式。
  • 小规模的项目,不需要经常修改的项目,我不使用设计模式。

使用设计模式需要权衡它的优势可读性、可理解性

工厂模式的目的是常见对象,对于简单的对象,我们可以直接使用构造器创建。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class SimpleClass {
private final Integer arg1;
private final Integer arg2;
SimpleClass(Integer arg1, Integer arg2) {
this.arg1 = arg1;
this.arg2 = arg2;
}
public Integer getArg1(){
return arg1;
}
public Integer getArg2(){
return args;
}
}
...
public class BusinessClassXYZ {
public static void someFunction(){
SimpleClass mySimpleClass = new SimpleClass(1,2);
// some stuff
}
}

何时需要工厂模式

控制实例对象数量

当企业应用想要限制实例的数量。如何保证只有一个(几个)实例对象。如socket,database connection
你也许可以使用共享变量。但是:

  • 使用共享变量的方法与共享变量紧密耦合,因为它们都修改同一个变量。
  • 每个方法都要检查变量是否已经实例化,冗余代码

使用静态工厂方法,我们可以轻松做到。

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
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return INSTANCE;
}
...
}
...
public class ClassXXX{
...
public static void someFunctionInClassXXX(){
Singleton instance = Singleton.getInstance();
//some stuff
}
}
...
public class ClassYYY{
...
public static void someFunctionInClassYYY(){
Singleton instance = Singleton.getInstance();
//some stuff
}
}

松耦合

工厂模式的另一个优点是松耦合。
比如在一个大型项目里,你需要记录日志。不使用工厂模式,你需要实例化FileSystemLogger。
如:

1
2
3
4
5
6
7
8
9
10
11
public class FileSystemLogger {
...
public void writeLog(String s) {
//Implemation
}
}
...
public void someFunctionInClassXXX(some parameters){
FileSystemLogger logger= new FileSystemLogger(some paramters);
logger.writeLog("This is a log");
}

但你需要该成用数据库记录日志时,你需要改所有使用日志的方法。
如果你使用工厂模式:

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
28
29
30
31
32
33
34
35
//this is an abstraction of a Logger
public interface ILogger {
public void writeLog(String s);
}
public class FileSystemLogger implements ILogger {
...
public void writeLog(String s) {
//Implemation
}
}
public class DatabaseLogger implements ILogger {
...
public void writeLog(String s) {
//Implemation
}
}
public class FactoryLogger {
public static ILogger createLogger() {
//you can choose the logger you want
// as long as it's an ILogger
return new FileSystemLogger();
}
}
////////////////////some code using the factory
public class SomeClass {
public void someFunction() {
//if the logger implementation changes
//you have nothing to change in this code
ILogger logger = FactoryLogger.createLogger();
logger.writeLog("This is a log");
}
}

你只需要修改createLogger()方法,这对客户端是透明的。

封装

有时,使用工厂设计模式可以提高代码的可读性,同时,通过封装降低了代码的复杂度。

假设,你需要使用业务类Carcomparator比较两辆汽车。这个类需要连接数据库得到汽车的信息,同时需要连接文件系统得到比较算法。
不使用工厂模式:

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class DatabaseConnection {
DatabaseConnection(some parameters) {
// some stuff
}
...
}
public class FileSystemConnection {
FileSystemConnection(some parameters) {
// some stuff
}
...
}
public class CarComparator {
CarComparator(DatabaseConnection dbConn, FileSystemConnection fsConn) {
// some stuff
}
public int compare(String car1, String car2) {
// some stuff with objets dbConn and fsConn
}
}
...
public class CarBusinessXY {
public void someFunctionInTheCodeThatNeedsToCompareCars() {
DatabaseConnection db = new DatabaseConnection(some parameters);
FileSystemConnection fs = new FileSystemConnection(some parameters);
CarComparator carComparator = new CarComparator(db, fs);
carComparator.compare("Ford Mustang","Ferrari F40");
}
...
}
public class CarBusinessZY {
public void someOtherFunctionInTheCodeThatNeedsToCompareCars() {
DatabaseConnection db = new DatabaseConnection(some parameters);
FileSystemConnection fs = new FileSystemConnection(some parameters);
CarComparator carComparator = new CarComparator(db, fs);
carComparator.compare("chevrolet camaro 2015","lamborghini diablo");
}
...
}

你可以看出存在冗余的代码,如果修改了CarComparator的构造函数,业务类的代码也需要修改。
相反,使用工厂模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Factory {
public static CarComparator getCarComparator() {
DatabaseConnection db = new DatabaseConnection(some parameters);
FileSystemConnection fs = new FileSystemConnection(some parameters);
reutrn new CarComparator(db, fs);
}
}
//////////////////////////////some code using the factory
public class CarBusinessXY {
public void someFunctionInTheCodeThatNeedsToCompareCars() {
CarComparator carComparator = Factory.getCarComparator();
carComparator.compare("Ford Mustang","Ferrari F40");
}
...
}
...
public class CarBusinessZY {
public void someOtherFunctionInTheCodeThatNeedsToCompareCars() {
CarComparator carComparator = Factory.getCarComparator();
carComparator.compare("chevrolet camaro 2015","lamborghini diablo");
}
...
}

  • 减少了代码和冗余
  • 有工厂负责创建,业务代码之需要获得创建的对象,专注于业务逻辑。

消除歧义

假设,有一个类用于多个不同的构造函数。怎么保证你没有使用错误的构造函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Example{
//constructor one
public Example(double a, float b) {
//...
}
//constructor two
public Example(double a) {
//...
}
//constructor three
public Example(float a, double b) {
//...
}
}

也许,你可以借助于IDE辨别使用哪个构造函数,但是,你怎么实现相同参数的构造函数?
使用模式就可以:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Complex {
public static Complex fromCartesian(double real, double imag) {
return new Complex(real, imag);
}
public static Complex fromPolar(double rho, double theta) {
return new Complex(rho * Math.cos(theta), rho * Math.sin(theta));
}
private Complex(double a, double b) {
//...
}
}

工厂模式

上面详细说明了工厂模式的优缺点。下面说明不同的设计模式。

静态工厂方法

引用Effective Java的作者Joshua Bloch

“A class can provide a public static factory method, which is simply a static method that returns an instance of the class.”

简言之,一个类提供一个静态方法,用于返回实例对象。

UML
static-factory

example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class MyClass {
Integer a;
Integer b;
MyClass(int a, int b){
this.a=a;
this.b=b;
};
public static MyClass getInstance(int a, int b){
return new MyClass(a, b);
}
public static void main(String[] args){
//instanciation with a constructor
MyClass a = new MyClass(1, 2);
//instanciation with a static factory method
MyClass b = MyClass.getInstance(1, 2);
}
}

更深入一步,如果静态工厂方法可以实例化其他类。

“Interfaces can’t have static methods, so by convention, static factory methods for an interface named Type are put in a noninstantiable class (Item 4) named Types.”

static

静态工厂方法返回一个抽象接口,可以通过接受参数选择返回具体的实例对象。

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
28
29
30
/////////////////////////the products
public interface Car {
public void drive();
}
public class Mustang implements Car{
public void drive() {
// some stuff
}
...
}
public class Ferrari implements Car{
public void drive() {
// some stuff
}
...
}
///////////////////////// the factory
public abstract class CarFactory{
public static Car getCar() {
// choose which car you want
}
}
...
/////////////////////////some code using the factory
public static void someFunctionInTheCode(){
Car myCar = CarFactory.getCar();
myCar.drive();
}

a static factory method is not the same as the Factory Method pattern from Design Patterns [Gamma95, p. 107]. The static factory method described in
this item has no direct equivalent in Design Patterns.”

真实的例子

logging frameworks

Java日志框架slf4j, logback, log4j 使用了一个抽象类LoggerFactory。

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Example{
public void example() {
//we're using the static factory method to get our logger
Logger logger = LoggerFactory.getLogger(Example.class);
logger.info("This is an example.");
}
}

Java String class

1
2
int i = 12;
String integerAsString = String.valueOf(i);

简单工厂

简单工厂算不上一种模式,简单工厂是一种工具:

  • 创建对象实例
  • 不使工厂方法模式
  • 也不是抽象工厂模式

factory

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
28
29
30
31
32
33
34
35
/////////////////////////the products
public interface Car {
public void drive();
}
public class Mustang implements Car{
public void drive() {
// some stuff
}
...
}
public class Ferrari implements Car{
public void drive() {
// some stuff
}
...
}
/////////////////////////The factory
public class CarFactory{
//this class is instantiable
public CarFactory(){
//some stuff
}
public Car getCar() {
// choose which car you want
}
}
...
/////////////////////////some code using the factory
public static void someFunctionInTheCode(){
CarFactory carFactory = new CarFactory();
Car myCar = carFactory.getCar();
myCar.drive();
}

工厂模式

“Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses”

factory-pattern

为什么使用工厂模式代替简单工厂
当需要不同的工厂的时候,比如,SportCarFactory, VintageCarFactory, LuxeCarFactory, CheapCarFactory…开发人员可以轻松的更换不同的工厂。

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/////////////////////////the products
public interface Car {
public void drive();
}
public class Mustang implements Car{
public void drive() {
// some stuff
}
...
}
public class Ferrari implements Car{
public void drive() {
// some stuff
}
...
}
///////////////////////// the factory
//the definition of the interface
public interface CarFactory{
public Car getCar() {}
}
//the real factory with an implementation of the getCar() factory method
public class ConcreteCarFactory implements CarFactory{
//this class is instantiable
public CarFactory(){
//some stuff
}
public Car getCar() {
// choose which car you want
return new Ferrari();
}
}
...
/////////////////////////some code using the factory
public static void someFunctionInTheCode(){
CarFactory carFactory = new ConcreteCarFactory();
Car myCar = carFactory.getCar();
myCar.drive();
}

真实的例子

Java Collection
Iterable 接口返回Iterator接口。
你不需要知道你使用的具体事什么类型的集合,HashSet or LinkedList,它们都可以使用工厂方法iterator()。具体的实现在子类中完成。

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
28
//here is a simplified definition of an iterator from the java source code
public interface Iterator<E> {
boolean hasNext();
E next();
void remove();
}
//here comes the factory interface!
public interface Iterable<T> {
Iterator<T> iterator();
}
//here is a simplified definition of ArrayList from the java source code
//you can see that this class is a concrete factory that implements
//a factory method iterator()
//Note : in the real Java source code, ArrayList is derived from
//AbstractList which is the one that implements the factory method pattern
public class ArrayList<E> {
//the iterator() returns a subtype and an "anonymous" Iterator<E>
public Iterator<E> iterator()
{
return new Iterator<E>()
{
//implementation of the methods hasNext(), next() and remove()
}
}
...
}

1
2
3
4
5
6
7
8
9
10
11
12
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Example {
public static void main(String[] ars){
//instantiation of the (concrete factory) ArrayList
List<Integer> myArrayList = new ArrayList<>();
//calling the factory method iterator() of ArrayList
Iterator<Integer> myIterator = myArrayList.iterator();
}
}

Spring Bean Factory
ApplicationContext实现了BeanFactory接口,其中有一个工厂方法getBean()返回Object类型的对象。

1
2
3
4
5
6
7
8
9
10
public class Example{
public static void main(String[] args) {
//creation of the BeanFactory
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
//creation totaly different type of objets with the factory
MyType1 objectType1 = context.getBean("myType1");
MyType2 objectType2 = context.getBean("myType2");
}
}

抽象工厂

“Provide an interface for creating families of related or dependent objects without specifying their concrete classes”

抽象工厂可以看作工厂模式的一般化,包含了多个抽象工厂方法
abstract-factory

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/////////////////////////the different products
public interface Wheel{
public void turn();
}
public class RaceCarWheel implements Wheel{
public void turn(){
// some stuff
}
...
}
public interface Engine{
public void work();
}
public class PowerfulEngine implements Engine{
public void work(){
// some stuff
}
...
}
/////////////////////////the factory
public interface CarFactory{
public Engine getEngine();
public Wheel getWheel();
}
public class SportCarFactory implements CarFactory{
public Engine getEngine(){
return new PowerfulEngine();
}
public Wheel getWheel(){
return new RaceCarWheel();
}
}
/////////////////////////some code using the factory
public class SomeClass {
public void someFunctionInTheCode(){
CarFactory carFactory = new SportCarFactory();
Wheel myWheel= carFactory.getWheel();
Engine myEngine = carFactory.getEngine();
}
}

真实的例子:
很多DAO框架使用抽象工厂模式,如Spring data CrudRepository

1
2
3
4
createObject(…) or persistObject(…)
updateObject(…) or saveObject(…)
deleteObject(…) or removeObject(…)
readObject(…) or findObject(…)v

from Coding Geek:
Design Pattern: factory patterns

© 2017 Hello World All Rights Reserved. 本站访客数人次 本站总访问量
Theme by hiero