工厂模式属于创建型模式。 工厂模式有四种类型:
工厂方法模式
抽象工厂模式
静态工厂方法
简单工厂模式
不使用设计模式
当我一个人在家写代码,我不使用设计模式。
小规模的项目,不需要经常修改的项目,我不使用设计模式。
使用设计模式需要权衡它的优势 和可读性、可理解性 。
工厂模式的目的是常见对象,对于简单的对象,我们可以直接使用构造器创建。
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 );
}
}
何时需要工厂模式 控制实例对象数量 当企业应用想要限制实例的数量。如何保证只有一个(几个)实例对象。如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();
}
}
...
public class ClassYYY {
...
public static void someFunctionInClassYYY () {
Singleton instance = Singleton.getInstance();
}
}
松耦合 工厂模式的另一个优点是松耦合。 比如在一个大型项目里,你需要记录日志。不使用工厂模式,你需要实例化FileSystemLogger。 如:1
2
3
4
5
6
7
8
9
10
11
public class FileSystemLogger {
...
public void writeLog (String s) {
}
}
...
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) {
}
...
}
public class FileSystemConnection {
FileSystemConnection(some parameters) {
}
...
}
public class CarComparator {
CarComparator(DatabaseConnection dbConn, FileSystemConnection fsConn) {
}
public int compare (String car1, String car2) {
}
}
...
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
example1
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) {
MyClass a = new MyClass(1 , 2 );
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.”
静态工厂方法返回一个抽象接口,可以通过接受参数选择返回具体的实例对象。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
public interface Car {
public void drive () ;
}
public class Mustang implements Car {
public void drive () {
}
...
}
public class Ferrari implements Car {
public void drive () {
}
...
}
public abstract class CarFactory {
public static Car getCar () {
}
}
...
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 inthis 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 () {
Logger logger = LoggerFactory.getLogger(Example.class);
logger.info("This is an example." );
}
}
Java String class1
2
int i = 12 ;
String integerAsString = String.valueOf(i);
简单工厂 简单工厂算不上一种模式,简单工厂是一种工具:
创建对象实例
不使工厂方法模式
也不是抽象工厂模式
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
public interface Car {
public void drive () ;
}
public class Mustang implements Car {
public void drive () {
}
...
}
public class Ferrari implements Car {
public void drive () {
}
...
}
public class CarFactory {
public CarFactory () {
}
public Car getCar () {
}
}
...
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”
为什么使用工厂模式代替简单工厂 当需要不同的工厂的时候,比如,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
public interface Car {
public void drive () ;
}
public class Mustang implements Car {
public void drive () {
}
...
}
public class Ferrari implements Car {
public void drive () {
}
...
}
public interface CarFactory {
public Car getCar () {}
}
public class ConcreteCarFactory implements CarFactory {
public CarFactory () {
}
public Car getCar () {
return new Ferrari();
}
}
...
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
public interface Iterator <E > {
boolean hasNext () ;
E next () ;
void remove () ;
}
public interface Iterable <T > {
Iterator<T> iterator () ;
}
public class ArrayList <E > {
public Iterator<E> iterator ()
{
return new Iterator<E>()
{
}
}
...
}
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) {
List<Integer> myArrayList = new 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) {
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml" );
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”
抽象工厂可以看作工厂模式的一般化,包含了多个抽象工厂方法 。
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
public interface Wheel {
public void turn () ;
}
public class RaceCarWheel implements Wheel {
public void turn () {
}
...
}
public interface Engine {
public void work () ;
}
public class PowerfulEngine implements Engine {
public void work () {
}
...
}
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();
}
}
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