原型模式定义
原型模式(Prototype Pattern)它属于创建型模式。原型模式主要作用于用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。
原型模式由来
数据库需要付出高代价的初始化过程才能被创建(类的实例化),那么每次都去重复性的创建无疑对系统性能有影响,那么这个时候可以缓存该对象,在下一个需要使用到它的时候就返回它的克隆,以减少对数据库的调用。
原型模式结构
-
AbstractPrototype:抽象原型角色
规定了具体原型对象必须实现的接口
-
ConcretePrototype:具体原型角色
实现抽象原型类的 clone() 方法,它是可被复制的对象。
案例分析
骑上我心爱的小摩托~~~,哈,扯远了。一辆雅迪(yadea)电动车,有名称、颜色、制动系统、轮毂、轮胎、座椅等元件构建组件而成,我们先用一种最简单的方式来实现。
方案一:初始设计
1、定义雅迪类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Yadea {
// 名称
final String name;
// 颜色
String color;
// 制动
final String brake;
// 座椅
final String seat;
// 更多属性....
Yadea(this.name, this.color, this.brake, this.seat);
}
2、使用
1
2
3
4
5
6
7
8
9
10
11
void main(List<String> args) {
// 红色的雅迪
Yadea yadeaRed = Yadea("小毛驴", "红色", "手动", "沙发");
print("雅迪的名字 ${yadeaRed.name}, 颜色是 ${yadeaRed.color}, 制动系统是 ${yadeaRed.brake}, 座椅是 ${yadeaRed.seat}");
// 粉色的雅迪
Yadea yadeaPink = Yadea("小毛驴", "粉色", "手动", "沙发");
print("雅迪的名字 ${yadeaPink.name}, 颜色是 ${yadeaPink.color}, 制动系统是 ${yadeaPink.brake}, 座椅是 ${yadeaPink.seat}");
}
3、运行结果
1
2
3
4
Connecting to VM Service at http://127.0.0.1:63303/bm2yRuPLcNA=/
雅迪的名字 小毛驴, 颜色是 红色, 制动系统是 手动, 座椅是 沙发
雅迪的名字 小毛驴, 颜色是 粉色, 制动系统是 手动, 座椅是 沙发
Exited
4、完整代码
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
void main(List<String> args) {
// 红色的雅迪
Yadea yadeaRed = Yadea("小毛驴", "红色", "手动", "沙发");
print("雅迪的名字 ${yadeaRed.name}, 颜色是 ${yadeaRed.color}, 制动系统是 ${yadeaRed.brake}, 座椅是 ${yadeaRed.seat}");
// 粉色的雅迪
Yadea yadeaPink = Yadea("小毛驴", "粉色", "手动", "沙发");
print("雅迪的名字 ${yadeaPink.name}, 颜色是 ${yadeaPink.color}, 制动系统是 ${yadeaPink.brake}, 座椅是 ${yadeaPink.seat}");
}
class Yadea {
// 名称
final String name;
// 颜色
final String color;
// 制动
final String brake;
// 座椅
final String seat;
// 更多属性....
Yadea(this.name, this.color, this.brake, this.seat);
}
5、分析
我们从上面的案例中发现,雅迪的其他属性都一样,就只是颜色不一样,对象的创建过程确把每个属性都重新赋值一遍,如果属性有二三十个的时候,那对象的创建过程就显得尤为复杂,我们来看下如何优化。
方案二:原型模式
1、创建原型角色
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Yadea {
// 名称
final String name;
// 颜色
String color;
// 制动
final String brake;
// 座椅
final String seat;
// 更多属性....
Yadea(this.name, this.color, this.brake, this.seat);
}
2、具体原型角色
1
2
3
class YadeaClone extends Yadea {
YadeaClone(Yadea yadea) : super(yadea.name, yadea.color, yadea.brake, yadea.seat);
}
3、使用
1
2
3
4
5
6
7
8
9
10
11
void main(List<String> args) {
// 原型
Yadea yadea = Yadea("小毛驴", "红色", "手动", "沙发");
print("雅迪的名字 ${yadea.name}, 颜色是 ${yadea.color}, 制动系统是 ${yadea.brake}, 座椅是 ${yadea.seat}");
// 快速克隆
YadeaClone yadeaClone = YadeaClone(yadea);
yadeaClone.color = "粉色";
print("雅迪的名字 ${yadeaClone.name}, 颜色是 ${yadeaClone.color}, 制动系统是 ${yadeaClone.brake}, 座椅是 ${yadeaClone.seat}");
}
4、运行结果
1
2
3
4
Connecting to VM Service at http://127.0.0.1:63303/bm2yRuPLcNA=/
雅迪的名字 小毛驴, 颜色是 红色, 制动系统是 手动, 座椅是 沙发
雅迪的名字 小毛驴, 颜色是 粉色, 制动系统是 手动, 座椅是 沙发
Exited
5、完整代码
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
void main(List<String> args) {
// 原型
Yadea yadea = Yadea("小毛驴", "红色", "手动", "沙发");
print("雅迪的名字 ${yadea.name}, 颜色是 ${yadea.color}, 制动系统是 ${yadea.brake}, 座椅是 ${yadea.seat}");
// 快速克隆
YadeaClone yadeaClone = YadeaClone(yadea);
yadeaClone.color = "粉色";
print("雅迪的名字 ${yadeaClone.name}, 颜色是 ${yadeaClone.color}, 制动系统是 ${yadeaClone.brake}, 座椅是 ${yadeaClone.seat}");
}
class Yadea {
// 名称
final String name;
// 颜色
String color;
// 制动
final String brake;
// 座椅
final String seat;
// 更多属性....
Yadea(this.name, this.color, this.brake, this.seat);
}
class YadeaClone extends Yadea {
YadeaClone(Yadea yadea) : super(yadea.name, yadea.color, yadea.brake, yadea.seat);
}
6、分析
我们使用具体原型角色的方式,利用父类的构造方法进行快速克隆对象。这样是的创建过程极其简单。
总结
原型模式优点
- 快速复制对象
- 简化创建对象的过程
原型模式缺点
- 需要单独为一个类配置克隆方法
- 克隆方法位于类内部,如果类结构被改造,那么就需要修改代码,违背开闭原则