设计模式-单例,原型与构建器 创建型模式 创建型模式处理对象的初始化和克服构造函数的限制。
Singleton,
Builder,
Prototype,
Abstract Factory,
Factory pattern.
其他
other type of factories (like the static one),
pool pattern,
lazy initialization,
dependency injection,
service locator,
单例模式 我很少使用单例,因为它使代码很难进行单元测试 ,同时紧密耦合 。 我更倾向于使用工厂模式创建单例。
Ensure a class only has one instance, and provide a global point of access to it”
单例模式必须满足:
example1
2
3
4
5
6
7
8
9
10
11
12
public class SimpleSingleton {
private static final SimpleSingleton INSTANCE = new SimpleSingleton();
private SimpleSingleton () { }
public static SimpleSingleton getInstance () {
return INSTANCE;
}
}
如果实例对象不使非常耗费内存,建议使用这种方法。(饿汉模式) 在多线程环境下(懒汉模式):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class TouchySingleton {
private static volatile TouchySingleton instance;
private TouchySingleton () {
}
public static TouchySingleton getInstance () {
if (instance == null ) {
synchronized (TouchySingleton.class) {
if (instance == null ) {
instance = new TouchySingleton();
}
}
}
return instance;
}
}
什么时候使用单例
只需要一个资源的时候(database connection, socket connection…)
对于无状态的类,避免多个实例对象浪费内存。
业务需要
你不应该使用单例作为共享变量,因为高耦合 你不应该使用单例:
隐藏了类之间的依赖关系,而不是暴露出接口。
违反了类设计的单一职责,单例控制了自己的创建和生命周期。同时又包含具体的功能。
高耦合
单元测试不友好,是代码难以预测。
使用单例代替单例模式 Spring框架的singleton并不是单例模式,而仅仅是单个实例。 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
46
47
48
49
50
51
52
53
54
public interface DatabaseConnection {
public void executeQuerry (String sql) ;
}
public class MysqlDatabaseConnection implements DatabaseConnection {
public MysqlDatabaseConnection () {
}
public void executeQuerry (String sql) {
}
}
public class PersonBusiness {
DatabaseConnection connection;
PersonBusiness(DatabaseConnection connection){
this .connection = connection;
}
public void deletePerson (int id) {
connection.executeQuerry("delete person where id=" +id);
}
}
public class Factory {
private static MysqlDatabaseConnection databaseConnection = new MysqlDatabaseConnection();
public static MysqlDatabaseConnection getUniqueMysqlDatabaseConnection () {
return databaseConnection;
}
public static PersonBusiness createPersonBusiness () {
return new PersonBusiness(databaseConnection);
}
}
真实的例子
“Every Java application has a single instance of class Runtime that allows the application to interface with the environment in which the application is running. The current runtime can be obtained from the getRuntime method.”
java.lang.Runtime
java.awt.Toolkit
原型模式 原型模式通过拷贝对象实例 取代通过构造函数创建实例对象。
“Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.”
简言之,如果你不能使用构造函数创建对象,可以通过复制已经存在的实例对象创建。
UML
什么时候使用原型模式
当系统不依赖于对象创建的细节。
运行时动态创建。
避免类的复杂的依赖关系。(现在可以通过依赖注入解决)
复制比创建容易的时候。
example 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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public interface Prototype {
Prototype duplicate () ;
}
public class CarComparator implements Prototype {
private int priceWeigth;
private int speedWeigth;
private int fuelConsumptionWeigth;
public CarComparator (DatabaseConnection connect) {
}
private CarComparator (int priceWeigth,int speedWeigth,int fuelConsumptionWeigth) {
this .priceWeigth=priceWeigth;
this .speedWeigth=speedWeigth;
this .fuelConsumptionWeigth=fuelConsumptionWeigth;
}
@Override
public Prototype duplicate () {
return new CarComparator(priceWeigth, speedWeigth, fuelConsumptionWeigth);
}
int compareCars (Car first, Car second) {
}
public void setPriceWeigth (int priceWeigth) {
this .priceWeigth = priceWeigth;
}
public void setSpeedWeigth (int speedWeigth) {
this .speedWeigth = speedWeigth;
}
public void setFuelConsumptionWeigth (int fuelConsumptionWeigth) {
this .fuelConsumptionWeigth = fuelConsumptionWeigth;
}
public class CarComparatorFactory {
CarComparator carComparator;
public BusinessClass (DatabaseConnection connect) {
carComparator = new CarComparator(connect);
}
public CarComparator getCarComparator () {
return carComparator.duplicate();
}
}
真实的例子 Java interface Cloneable 提供一个clone()
1
2
3
4
5
6
7
8
9
10
11
ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 0 ; i < 10 ; i++) {
list.add(i);
}
System.out.println("content of the list " +list);
ArrayList<Integer> duplicatedSet = (ArrayList<Integer>) list.clone();
System.out.println("content of the duplicated list " +duplicatedSet);
构建器模式 构建器模式有助于分解复杂的代码。目的是避免创建大量的相似构造函数(只有部分参数不同)
“Separate the construction of a complex object from its representation so that the same construction process can create different representations.”
比如: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
public class Person {
private int age;
private int weigth;
private int height;
private int id;
private String name;
public Person () {
}
public Person (int age) {
this ();
this .age = age;
}
public Person (int age, int weigth) {
this (age);
this .weigth = weigth;
}
public Person (int age, int weigth, int height) {
this (age, weigth);
this .height= height;
}
public Person (int age, int weigth, int height,int id) {
this (age, weigth, height);
this .id = id;
}
public Person (int age, int weigth, int height,int id,String name) {
this (age, weigth, height, id);
this .name = name;
}
}
1
2
3
Person person1 = new Person (45, 45, 160, 1);
Person person2 = new Person (45, 170, 150);
这样的代码非常冗长,难以阅读,很难使用。如果参数有120个,你是否愿意写120个构造函数?即使使用工厂模式,也需要120个工厂方法。 这就是构建器模式的优点。它模拟了其他语言(Python)的可选参数 特性。
example1
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public class Person {
private final int id;
private int weigth;
private int height;
private int age;
private String name;
public Person (PersonBuilder builder) {
age = builder.age;
weigth = builder.weigth;
height = builder.height;
id = builder.id;
name = builder.name;
}
}
public class PersonBuilder {
final int id;
int height;
int age;
int weigth;
String name = "" ;
public PersonBuilder (int id) {
this .id = id;
}
public PersonBuilder age (int val) {
age = val;
return this ;
}
public PersonBuilder weigth (int val) {
weigth = val;
return this ;
}
public PersonBuilder height (int val) {
height = val;
return this ;
}
public PersonBuilder name (String val) {
name = val;
return this ;
}
public Person build () {
return new Person(this );
}
}
public class SomeClass {
public void someMethod (int id) {
PersonBuilder pBuilder = new PersonBuilder(id);
Person robert = pBuilder.name("Robert" ).age(18 ).weigth(80 ).build();
}
public void someMethodBis (int id) {
PersonBuilder pBuilder = new PersonBuilder(id);
Person jennifer = pBuilder.height(170 ).name("Jennifer" ).build();
}
}
另一个隐藏的技能:构建器模式可以创建不可变的对象 。因为可以不提供setter方法,就没有办法通过构造函数修改对象的属性。
UML
真实的例子 StringBuilder1
2
3
4
StringBuilder sBuilder = new StringBuilder();
String example = sBuilder.append("this" ).append(" is" )
.append(" an" ).append(" example" ).toString();
System.out.println(example);