甲乙小朋友的房子

甲乙小朋友很笨,但甲乙小朋友不会放弃

0%

对象创建的各种模式

工厂模式是一种“对象创建”模式。它是为了在面向接口编程时,避免new object时对具体class的紧耦合的产物。典型的对象创建模式有工厂方法Factory Method, 抽象工厂Abstract Factory, Prototype, Builder.

工厂方法 Factory Method

要点是,通过method返回new的具体对象。

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
// 这是抽象类
public abstract class Product
{
// ...
}

// 这是具体类
public class ProductA extends Product
{
// ...
}

// 这是工厂类
public class Creator
{
public static Product CreateProduct(string parameter)
{
// 选择合适的Product进行返回
if (parameter == "A")
{
return new ProductA();
}
else
{
// return new ProductB() etc...
}

}
}

// 使用
public class Program
{
public static void main(string[] args)
{
// 完全没有出现具体的ProductA class
Product myProduct = Creator.CreateProduct("A");
}
}

其实就是在使用时,不要直接new 具体的ProductA or B。那这样有什么好处呢?这个回答工厂模式的本质是什么写的不错,一般在创建过程比较复杂时使用。那什么是复杂的创建过程呢?有几个例子:

eg1:创建的对象在一个pool里,不是每次都要重新new一个全新的。比如连接池对象,线程池对象。

eg2:具体class的作者希望隐藏对象真实的的类型。

eg3:对象创建时,在不同参数下返回不同的对象。

eg4,5:对象创建时有很多参数,或者有复杂的依赖关系。简化超长构造函数。

eg6:你知道怎么创建一个对象,但是无法把控创建的时机。你需要把“如何创建”的代码塞给“负责什么时候创建”的代码。后者在适当的时机,就回调创建的函数。

eg7:构造函数不能throw exception,但是工厂方法可以呀。

读到这里,我相信聪明的你肯定已经学会了什么是工厂方法。接下来我们了解抽象工厂。

抽象工厂 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
46
47
// 这是抽象类
public abstract class Product
{
// ...
}

// 这是具体类
public class ProductA extends Product
{
// ...
}

// 这是【抽象工厂】类
public abstract class AbstractCreator
{
// abstract的,非static的
public abstract Product CreateProduct(string parameter);
}

public class Creator extends AbstractCreator
{
public Product CreateProduct(string parameter)
{
// 选择合适的Product进行返回
if (parameter == "A")
{
return new ProductA();
}
else
{
// return new ProductB() etc...
}

}
}

// 使用
public class Program
{
public static void main(string[] args)
{
// 先造一个creator
AbstractCreator aCreator = new Creator();
// 完全没有出现具体的ProductA class
Product myProduct = aCreator.CreateProduct("A");
}
}

也就是说,它只是把简单的工厂方法中的工厂Creator进行了进一步的抽象。那这样有什么好处呢?

当我们突然想换个工厂,改动就少很多了!

原型模式 Prototype Pattern

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。

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 class Main implements Cloneable
{
// ....

// 这是重点!!! clone !!!
@Override
public Main clone()
{
Mail = null;
try
{
mail = (Main)super.clone();
}
catch (CloneNotSupportedException e) // 如果没有实现Cloneable的对象,就会抛这个
{
e.printStackTrace();
}

return mail;
}
}

// 使用
public class Client
{
private static int MAX_COUNT = 600; // 发送账单的数量
public static void main(string[] args)
{
Mail mail = new Mail();

for (int i = 0; i < MAX_COUNT; ++i)
{
// clone 一个Mail
Mail cloneMail = mail.clone();
// 修改细节数据
cloneMail.setReiver("...");
// 发送。即使sendMail是多线程的,
sendMail(cloneMail);
}
}
}

好处

  • 性能优良 原型模式是在内存二进制流的拷贝, 要比直接new一个对象性能好很多, 特别是要在一 个循环体内产生大量的对象时, 原型模式可以更好地体现其优点。
  • 逃避构造函数的约束 这既是它的优点也是缺点, 直接在内存中拷贝, 构造函数是不会执行的。 优点就是减少了约束, 缺点也是减少了约束, 需要大家在实际应用时考虑。

使用场景

  • 资源优化场景 类初始化需要消化非常多的资源, 这个资源包括数据、 硬件资源等。

  • 性能和安全要求的场景 通过new产生一个对象需要非常繁琐的数据准备或访问权限, 则可以使用原型模式。

  • 一个对象多个修改者的场景 一个对象需要提供给其他对象访问, 而且各个调用者可能都需要修改其值时, 可以考虑 使用原型模式拷贝多个对象供调用者使用。

在实际项目中, 原型模式很少单独出现, 一般是和工厂方法模式一起出现, 通过clone的 方法创建一个对象, 然后由工厂方法提供给调用者。 原型模式已经与Java融为一体, 大家可 以随手拿来使用。

建造者模式

秒懂设计模式之建造者模式

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
// 目标类
public class Computer {
private String cpu;//必须
private String ram;//必须
private int usbCount;//可选
private String keyboard;//可选
private String display;//可选

public Computer(String cpu, String ram) {
this.cpu = cpu;
this.ram = ram;
}
public void setUsbCount(int usbCount) {
this.usbCount = usbCount;
}
public void setKeyboard(String keyboard) {
this.keyboard = keyboard;
}
public void setDisplay(String display) {
this.display = display;
}
@Override
public String toString() {
return "Computer{" +
"cpu='" + cpu + '\'' +
", ram='" + ram + '\'' +
", usbCount=" + usbCount +
", keyboard='" + keyboard + '\'' +
", display='" + display + '\'' +
'}';
}
}

// 抽象构建者
public abstract class ComputerBuilder {
public abstract void setUsbCount();
public abstract void setKeyboard();
public abstract void setDisplay();

public abstract Computer getComputer();
}

// 苹果电脑构建者类
public class MacComputerBuilder extends ComputerBuilder {
private Computer computer;
public MacComputerBuilder(String cpu, String ram) {
computer = new Computer(cpu, ram);
}
@Override
public void setUsbCount() {
computer.setUsbCount(2);
}
@Override
public void setKeyboard() {
computer.setKeyboard("苹果键盘");
}
@Override
public void setDisplay() {
computer.setDisplay("苹果显示器");
}
@Override
public Computer getComputer() {
return computer;
}
}

//联想电脑构建者类
public class LenovoComputerBuilder extends ComputerBuilder {
private Computer computer;
public LenovoComputerBuilder(String cpu, String ram) {
computer=new Computer(cpu,ram);
}
@Override
public void setUsbCount() {
computer.setUsbCount(4);
}
@Override
public void setKeyboard() {
computer.setKeyboard("联想键盘");
}
@Override
public void setDisplay() {
computer.setDisplay("联想显示器");
}
@Override
public Computer getComputer() {
return computer;
}
}

// 指导者类(Director)
public class ComputerDirector {
public void makeComputer(ComputerBuilder builder){
builder.setUsbCount();
builder.setDisplay();
builder.setKeyboard();
}
}

// 使用
public static void main(String[] args) {
// 生成director
ComputerDirector director=new ComputerDirector();

// director指导build mac
ComputerBuilder builder=new MacComputerBuilder("I5处理器","三星125");//2
director.makeComputer(builder);//3
Computer macComputer=builder.getComputer();//4
System.out.println("mac computer:"+macComputer.toString());

// director指导build lenovo
ComputerBuilder lenovoBuilder=new LenovoComputerBuilder("I7处理器","海力士222");
director.makeComputer(lenovoBuilder);
Computer lenovoComputer=lenovoBuilder.getComputer();
System.out.println("lenovo computer:"+lenovoComputer.toString());
}