基础编程学习快乐每一天
首页
留言
Siddim.com
当前位置:
首页
>
编程知识库
>
后端开发知识
>
设计模式是什么鬼(原型)
设计模式是什么鬼(原型)
阅读
1
2018-07-24
点击下方阅读原文,查看更多关于设计模式的文章
原型(
Prototype
)是什么意思?工业生产中通常是指在量产之前研发出的概念实现,如果可行性满足即可参照原型进行量产。有人说了,那不就是印章?其实这并不怎么贴切,印章并不是最终实例,我更愿意称其为“类”!
呃……僵尸脸花泽类经世名言:想哭的时候就道理,这样眼泪就不会流出来了。(尼玛,都流脑子里了吧!)
言归正传,大家一定见过这种印章吧,就是皮带轮可以转动,可随意调整成自己需要的文字,其实跟我们的四大发明活字印刷同出一辙,我们填完表格签好字,行政人员拿这个往上一盖,一个日期便出现在落款出。
其实当行政人员调整好了文字,照纸上盖下去那一刹那,其实就类似于实例化的过程了,
new
Stamp
();每个盖出的印都可以不一样,例如我们更换了日期,那么每天都有不同日期的实例了,那有人意识到了,同一天的那些实例们,其实是完全一模一样的实例拷贝,那这就比较麻烦,每个文档都要用章子(类)去盖(实例化)一下。
好了,让我们忘掉盖章实例化模式吧。通常我们都是怎样做协议书的呢?搞一个
Word
文档吧,写好后复制给别人修改就好了。
注意了,行政人员要新建一个
word
文档了,这个过程其实是在实例化,我们暂且叫它“零号”文件,那当写好了文档后,把这个文件复制给其他公司员工去填写,那么这个零号文件我们就称之为“原型”。
想必我们已经搞明白了,原型模式,实际上是从原型实例复制克隆出新实例,而绝不是从类去实例化,这个过程的区别一定要搞清楚!
OK
,那开始我们的实战部分。
假设我们要做一个打飞机游戏,游戏设定位纵版移动,单打。
既然是单打,那我们的主角飞机当然只有一架,于是我们写一个单例模式(设计模式是什么鬼(单例)),此处我们省略主角代码。那么敌机呢?当然有很多架了,好,为了说明问题我们去繁就简,先写一个敌机类。
%
201public
%
20class
%
20EnemyPlane
%
20
%
7B
%
0A
%
202
%
20
%
20
%
20
%
20private
%
20int
%
20x
;//%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
E6
%
A8
%
AA
%
E5
%
9D
%
90
%
E6
%
A0
%
87
%
0A
%
203
%
20
%
20
%
20
%
20private
%
20int
%
20y
%
20
=%
200
;//%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
E7
%
BA
%
B5
%
E5
%
9D
%
90
%
E6
%
A0
%
87
%
0A
%
204
%
0A
%
205
%
20
%
20
%
20
%
20public
%
20EnemyPlane
(
int
%
20x
)%
20
%
7B
//%
E6
%
9E
%
84
%
E9
%
80
%
A0
%
E5
%
99
%
A8
%
0A
%
206
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20this
.
x
%
20
=%
20x
;%
0A
%
207
%
20
%
20
%
20
%
20
%
7D
%
0A
%
208
%
0A
%
209
%
20
%
20
%
20
%
20public
%
20int
%
20getX
()%
20
%
7B
%
0A10
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20return
%
20x
;%
0A11
%
20
%
20
%
20
%
20
%
7D
%
0A12
%
0A13
%
20
%
20
%
20
%
20public
%
20int
%
20getY
()%
20
%
7B
%
0A14
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20return
%
20y
;%
0A15
%
20
%
20
%
20
%
20
%
7D
%
0A16
%
0A17
%
20
%
20
%
20
%
20public
%
20void
%
20fly
()%
7B
//%
E8
%
AE
%
A9
%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
E9
%
A3
%
9E
%
0A18
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20y
;//%
E6
%
AF
%
8F
%
E8
%
B0
%
83
%
E7
%
94
%
A8
%
E4
%
B8
%
80
%
E6
%
AC
%
A1
%
EF
%
BC
%
8C
%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
E9
%
A3
%
9E
%
E8
%
A1
%
8C
%
E6
%
97
%
B6
%
E7
%
BA
%
B5
%
E5
%
9D
%
90
%
E6
%
A0
%
87
%
EF
%
BC
%
8B1
%
0A19
%
20
%
20
%
20
%
20
%
7D
%
0A20
%
7D
%
0A
代码第
5
行,初始化只接收
x
坐标,因为敌机一开始是从顶部出来所以纵坐标
y
必然是
0
。此类只提供
getter
而没有
setter
,也就是说只能在初始化时确定敌机的横坐标
x
,后续是不需要更改坐标了,只要连续调用第
17
行的
fly
方法即可让飞机跟雨点一样往下砸。
好了,我们开始绘制敌机动画了,先实例化出
50
架吧。
%
201public
%
20class
%
20Client
%
20
%
7B
%
0A
%
202
%
20
%
20
%
20
%
20public
%
20static
%
20void
%
20main
(
String
%
5B
%
5D
%
20args
)%
20
%
7B
%
0A
%
203
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20List
&
lt
;
EnemyPlane
&
gt
;%
20enemyPlanes
%
20
=%
20new
%
20ArrayList
&
lt
;
EnemyPlane
&
gt
;();%
0A
%
204
%
0A
%
205
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20for
%
20
(
int
%
20i
%
20
=%
200
;%
20i
%
20
&
lt
;%
2050
;%
20i
)%
20
%
7B
%
0A
%
206
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
//%
E6
%
AD
%
A4
%
E5
%
A4
%
84
%
E9
%
9A
%
8F
%
E6
%
9C
%
BA
%
E4
%
BD
%
8D
%
E7
%
BD
%
AE
%
E4
%
BA
%
A7
%
E7
%
94
%
9F
%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
0A
%
207
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20EnemyPlane
%
20ep
%
20
=%
20new
%
20EnemyPlane
(
new
%
20Random
().
nextInt
(
200
));%
0A
%
208
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20enemyPlanes
.
add
(
ep
);%
0A
%
209
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
7D
%
0A10
%
0A11
%
20
%
20
%
20
%
20
%
7D
%
0A12
%
7D
%
0A
注意代码第
7
行,觉不觉得每个迭代都实例化
new
出一个对象存在性能问题呢?答案是肯定的,这个实例化的过程是得不偿失的,构造方法会被调用
50
次,
cpu
被极大浪费了,内存被极大浪费了,尤其对于游戏来说性能瓶颈绝对是大忌,这会造成用户体验问题,谁也不希望玩游戏会卡帧吧。
那到底什么时候去
new
?游戏场景初始化就
new
敌机(如以上代码)?这关会出现
500
个敌机那我们一次都
new
出来吧?浪费内存!那我们实时的去
new
,每到一个地方才
new
出来一个!浪费
CPU
!如果敌机线程过多造成
CPU
资源耗尽,每出一个敌机游戏会卡一下,试想一下这种极端情况下,游戏对象实例很多的话就是在作死。
解决方案到底是什么呢?好,原型模式
Prototype
!上代码!我们把上面的敌机类改造一下,让它支持原型拷贝。
%
201public
%
20class
%
20EnemyPlane
%
20implements
%
20Cloneable
%
7B
//%
E6
%
AD
%
A4
%
E5
%
A4
%
84
%
E5
%
AE
%
9E
%
E7
%
8E
%
B0
%
E5
%
85
%
8B
%
E9
%
9A
%
86
%
E6
%
8E
%
A5
%
E5
%
8F
%
A3
%
0A
%
202
%
20
%
20
%
20
%
20private
%
20int
%
20x
;//%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
E6
%
A8
%
AA
%
E5
%
9D
%
90
%
E6
%
A0
%
87
%
0A
%
203
%
20
%
20
%
20
%
20private
%
20int
%
20y
%
20
=%
200
;//%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
E7
%
BA
%
B5
%
E5
%
9D
%
90
%
E6
%
A0
%
87
%
0A
%
204
%
0A
%
205
%
20
%
20
%
20
%
20public
%
20EnemyPlane
(
int
%
20x
)%
20
%
7B
//%
E6
%
9E
%
84
%
E9
%
80
%
A0
%
E5
%
99
%
A8
%
0A
%
206
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20this
.
x
%
20
=%
20x
;%
0A
%
207
%
20
%
20
%
20
%
20
%
7D
%
0A
%
208
%
0A
%
209
%
20
%
20
%
20
%
20public
%
20int
%
20getX
()%
20
%
7B
%
0A10
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20return
%
20x
;%
0A11
%
20
%
20
%
20
%
20
%
7D
%
0A12
%
0A13
%
20
%
20
%
20
%
20public
%
20int
%
20getY
()%
20
%
7B
%
0A14
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20return
%
20y
;%
0A15
%
20
%
20
%
20
%
20
%
7D
%
0A16
%
0A17
%
20
%
20
%
20
%
20public
%
20void
%
20fly
()%
7B
//%
E8
%
AE
%
A9
%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
E9
%
A3
%
9E
%
0A18
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20y
;//%
E6
%
AF
%
8F
%
E8
%
B0
%
83
%
E7
%
94
%
A8
%
E4
%
B8
%
80
%
E6
%
AC
%
A1
%
EF
%
BC
%
8C
%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
E9
%
A3
%
9E
%
E8
%
A1
%
8C
%
E6
%
97
%
B6
%
E7
%
BA
%
B5
%
E5
%
9D
%
90
%
E6
%
A0
%
87
%
EF
%
BC
%
8B1
%
0A19
%
20
%
20
%
20
%
20
%
7D
%
0A20
%
0A21
%
20
%
20
%
20
%
20
//%
E6
%
AD
%
A4
%
E5
%
A4
%
84
%
E5
%
BC
%
80
%
E6
%
94
%
BEsetX
%
EF
%
BC
%
8C
%
E4
%
B8
%
BA
%
E4
%
BA
%
86
%
E8
%
AE
%
A9
%
E5
%
85
%
8B
%
E9
%
9A
%
86
%
E5
%
90
%
8E
%
E7
%
9A
%
84
%
E5
%
AE
%
9E
%
E4
%
BE
%
8B
%
E9
%
87
%
8D
%
E6
%
96
%
B0
%
E4
%
BF
%
AE
%
E6
%
94
%
B9x
%
E5
%
9D
%
90
%
E6
%
A0
%
87
%
0A22
%
20
%
20
%
20
%
20public
%
20void
%
20setX
(
int
%
20x
)%
20
%
7B
%
0A23
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20this
.
x
%
20
=%
20x
;%
0A24
%
20
%
20
%
20
%
20
%
7D
%
0A25
%
0A26
%
20
%
20
%
20
%
20
//%
E4
%
B8
%
BA
%
E4
%
BA
%
86
%
E4
%
BF
%
9D
%
E8
%
AF
%
81
%
E9
%
A3
%
9E
%
E6
%
9C
%
BA
%
E9
%
A3
%
9E
%
E8
%
A1
%
8C
%
E7
%
9A
%
84
%
E8
%
BF
%
9E
%
E8
%
B4
%
AF
%
E6
%
80
%
A7
%
0A27
%
20
%
20
%
20
%
20
//%
E8
%
BF
%
99
%
E9
%
87
%
8C
%
E6
%
88
%
91
%
E4
%
BB
%
AC
%
E5
%
85
%
B3
%
E9
%
97
%
ADsetY
%
E6
%
96
%
B9
%
E6
%
B3
%
95
%
EF
%
BC
%
8C
%
E4
%
B8
%
8D
%
E6
%
94
%
AF
%
E6
%
8C
%
81
%
E9
%
9A
%
8F
%
E6
%
84
%
8F
%
E6
%
9B
%
B4
%
E6
%
94
%
B9Y
%
E7
%
BA
%
B5
%
E5
%
9D
%
90
%
E6
%
A0
%
87
%
0A28
//%
20
%
20
%
20
%
20public
%
20void
%
20setY
(
int
%
20y
)%
20
%
7B
%
0A29
//%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20this
.
y
%
20
=%
20y
;%
0A30
//%
20
%
20
%
20
%
20
%
7D
%
0A31
%
0A32
%
20
%
20
%
20
%
20
//%
E9
%
87
%
8D
%
E5
%
86
%
99
%
E5
%
85
%
8B
%
E9
%
9A
%
86
%
E6
%
96
%
B9
%
E6
%
B3
%
95
%
0A33
%
20
%
20
%
20
%
20
@
Override
%
0A34
%
20
%
20
%
20
%
20public
%
20EnemyPlane
%
20clone
()%
20throws
%
20CloneNotSupportedException
%
20
%
7B
%
0A35
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20return
%
20
(
EnemyPlane
)
super
.
clone
();%
0A36
%
20
%
20
%
20
%
20
%
7D
%
0A37
%
7D
%
0A
注意看从第
21
行开始的修改,
setX
()方法为了保证克隆飞机的个性化,因为它们出现的位置是不同的。第
34
行的克隆方法重写我们调用了父类
Object
的克隆方法,这里
JVM
会进行内存操作直接拷贝原始数据流,简单粗暴,不会有其他更多的复杂操作(类加载,实例化,初始化等等),速度远远快于实例化操作。
OK
,我们看怎么克隆这些敌机,做一个造飞机的工厂吧。
%
201public
%
20class
%
20EnemyPlaneFactory
%
20
%
7B
%
0A
%
202
%
20
%
20
%
20
%
20
//%
E6
%
AD
%
A4
%
E5
%
A4
%
84
%
E7
%
94
%
A8
%
E7
%
97
%
B4
%
E6
%
B1
%
89
%
E6
%
A8
%
A1
%
E5
%
BC
%
8F
%
E9
%
80
%
A0
%
E4
%
B8
%
80
%
E4
%
B8
%
AA
%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
E5
%
8E
%
9F
%
E5
%
9E
%
8B
%
0A
%
203
%
20
%
20
%
20
%
20private
%
20static
%
20EnemyPlane
%
20protoType
%
20
=%
20new
%
20EnemyPlane
(
200
);%
0A
%
204
%
0A
%
205
%
20
%
20
%
20
%
20
//%
E8
%
8E
%
B7
%
E5
%
8F
%
96
%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
E5
%
85
%
8B
%
E9
%
9A
%
86
%
E5
%
AE
%
9E
%
E4
%
BE
%
8B
%
0A
%
206
%
20
%
20
%
20
%
20public
%
20static
%
20EnemyPlane
%
20getInstance
(
int
%
20x
)%
7B
%
0A
%
207
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20EnemyPlane
%
20clone
%
20
=%
20protoType
.
clone
();//%
E5
%
A4
%
8D
%
E5
%
88
%
B6
%
E5
%
8E
%
9F
%
E5
%
9E
%
8B
%
E6
%
9C
%
BA
%
0A
%
208
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20clone
.
setX
(
x
);//%
E9
%
87
%
8D
%
E6
%
96
%
B0
%
E8
%
AE
%
BE
%
E7
%
BD
%
AE
%
E5
%
85
%
8B
%
E9
%
9A
%
86
%
E6
%
9C
%
BA
%
E7
%
9A
%
84x
%
E5
%
9D
%
90
%
E6
%
A0
%
87
%
0A
%
209
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20return
%
20clone
;%
0A10
%
20
%
20
%
20
%
20
%
7D
%
0A11
%
7D
%
0A
此处我们省去抓异常,随后的事情就非常简单了,我们只需要很简单地调用
EnemyPlaneFactory
.
getInstance
(
int
x
)并声明
x
坐标位置,一架敌机很快地就做好了,并且我们保证是在敌机出现的时候再去克隆,确保不要一开局就全部克隆出来,如此一来,既保证了实时性节省了内存空间,又保证了敌机实例化的速度,游戏绝不会卡帧!至于此处代码中的懒汉原型还可以怎样优化那就要根据具体场景了,交给大家自由发挥吧,这里只说明主要问题。
最后,还要强调一点就是浅拷贝和深拷贝的问题。假如我们的敌机类里有一颗子弹
bullet
可以射击我们的主角,如下。
1public
%
20class
%
20EnemyPlane
%
20implements
%
20Cloneable
%
7B
%
0A2
%
20
%
20
%
20
%
20private
%
20Bullet
%
20bullet
%
20
=%
20new
%
20Bullet
();%
0A3
%
20
%
20
%
20
%
20private
%
20int
%
20x
;//%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
E6
%
A8
%
AA
%
E5
%
9D
%
90
%
E6
%
A0
%
87
%
0A4
%
20
%
20
%
20
%
20private
%
20int
%
20y
%
20
=%
200
;//%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
E7
%
BA
%
B5
%
E5
%
9D
%
90
%
E6
%
A0
%
87
%
0A5
%
0A6
%
20
%
20
%
20
%
20
//%
E4
%
B9
%
8B
%
E5
%
90
%
8E
%
E4
%
BB
%
A3
%
E7
%
A0
%
81
%
E7
%
9C
%
81
%
E7
%
95
%
A5
%
E2
%
80
%
A6
%
E2
%
80
%
A6
%
0A7
%
7D
%
0A
我们都知道
Java
中的变量分为原始类型和引用类型,所谓浅拷贝只是拷贝原始类型的指,比如坐标
x
,
y
的指会被拷贝到克隆对象中,对于对象
bullet
也会被拷贝,但是请注意拷贝的只是地址而已,那么多个地址其实真正指向的对象还是同一个
bullet
。
由于我们调用父类
Object
的
clone
方法进行的是浅拷贝,所以此处的
bullet
并没有被克隆成功,比如我们每架敌机必须携带的子弹是不同的实例,那么我们就必须进行深拷贝,于是我们的代码就得做这样的改动。
%
201public
%
20class
%
20EnemyPlane
%
20implements
%
20Cloneable
%
7B
%
0A
%
202
%
20
%
20
%
20
%
20private
%
20Bullet
%
20bullet
%
20
=%
20new
%
20Bullet
();%
0A
%
203
%
0A
%
204
%
20
%
20
%
20
%
20public
%
20void
%
20setBullet
(
Bullet
%
20bullet
)%
20
%
7B
%
0A
%
205
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20this
.
bullet
%
20
=%
20bullet
;%
0A
%
206
%
20
%
20
%
20
%
20
%
7D
%
0A
%
207
%
0A
%
208
%
20
%
20
%
20
%
20
@
Override
%
0A
%
209
%
20
%
20
%
20
%
20protected
%
20EnemyPlane
%
20clone
()%
20throws
%
20CloneNotSupportedException
%
20
%
7B
%
0A10
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20EnemyPlane
%
20clonePlane
%
20
=%
20
(
EnemyPlane
)%
20super
.
clone
();//%
E5
%
85
%
88
%
E5
%
85
%
8B
%
E9
%
9A
%
86
%
E5
%
87
%
BA
%
E6
%
95
%
8C
%
E6
%
9C
%
BA
%
EF
%
BC
%
8C
%
E5
%
85
%
B6
%
E4
%
B8
%
AD
%
E5
%
AD
%
90
%
E5
%
BC
%
B9
%
E8
%
BF
%
98
%
E6
%
9C
%
AA
%
E8
%
BF
%
9B
%
E8
%
A1
%
8C
%
E5
%
85
%
8B
%
E9
%
9A
%
86
%
E3
%
80
%
82
%
0A11
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20clonePlane
.
setBullet
(
this
.
bullet
.
clone
());//%
E5
%
AF
%
B9
%
E5
%
AD
%
90
%
E5
%
BC
%
B9
%
E8
%
BF
%
9B
%
E8
%
A1
%
8C
%
E6
%
B7
%
B1
%
E6
%
8B
%
B7
%
E8
%
B4
%
9D
%
0A12
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20return
%
20clonePlane
;%
0A13
%
20
%
20
%
20
%
20
%
7D
%
0A14
%
0A15
%
20
%
20
%
20
%
20
//%
E4
%
B9
%
8B
%
E5
%
90
%
8E
%
E4
%
BB
%
A3
%
E7
%
A0
%
81
%
E7
%
9C
%
81
%
E7
%
95
%
A5
%
E2
%
80
%
A6
%
E2
%
80
%
A6
%
0A16
%
7D
%
0A
相信大家看注释就能懂了,这里就不做过多解释,当然对于
Bullet
类也同样实现了克隆接口,代码不用再写了吧?相信大家都学会了举一反三。至此,我们的每个敌机携带的弹药也同样被克隆完毕了,再也不必担心游戏的流畅性了。
推荐大而全的【后端技术精选】
以上数据来源于网络,如有侵权,请联系删除。
上一篇:
华为OD(外包)社招技术二面,总结复盘
下一篇:
设计模式是什么鬼(适配器)
评论
(0)
提交
类别
基础编程学习
HTML
PHP
Python
编程知识库
后端开发知识
热门文章
Java并发中的同步容器与并发容器,你了解多少?
Innodb中的事务隔离级别和锁的关系,难倒一半面试者!
SpringBoot + minio实现分片上传、秒传、续传
面试官:你知道消息队列如何保证数据不丢失吗?
JAVA知识 Java8新特性
面试官:谈谈为什么要限流,有哪些限流方案?
说说动态代理与静态代理区别
面试官:思考Tomcat 类加载器为什么要违背双亲委派模型?
boot-admin 基于SpringBoot的后台权限管理系统,可作为脚手架,用于快速搭建项目
SpringBoot+Vue+App+硬件实现智能家居系统项目