基础编程学习快乐每一天
首页
留言
Siddim.com
当前位置:
首页
>
编程知识库
>
后端开发知识
>
设计模式是什么鬼(模板方法)
设计模式是什么鬼(模板方法)
阅读
1
2018-08-21
点击下方阅读原文,查看更多关于设计模式的文章
面向对象,是对事物属性与行为的封装,方法,指的就是行为。模板方法,显而易见是说某个方法充当了模板的作用,其充分利用了抽象类虚实结合的特性,虚部抽象预留,实部固定延续,以达到将某种固有行为延续至子类的目的。反观接口,则达不到这种目的。要搞明白模板方法,首先我们从接口与抽象类的区别切入,这也是面试官经常会问到的问题。
汽车上的接口最常见的就是这几个了,点烟器,
USB
,
AUX
等等,很明显这些都是接口,它们都预留了某种标准,暴露在系统外部,并与外设对接。就拿点烟器接口来说吧,它原本是专门用于给点烟器供电的,后来由于这个接口在汽车上的通用性,于是衍生出了各种外部设备,只要是符合这个标准
size
的,带正负极簧片的,直流
12V
的,那就可以使用,比如导航、行车记录仪、吸尘器什么的,以及其他各种车载电子设备。
public
%
20interface
%
20CigarLighterInterface
%
20
%
7B
//%
E7
%
82
%
B9
%
E7
%
83
%
9F
%
E5
%
99
%
A8
%
E6
%
8E
%
A5
%
E5
%
8F
%
A3
%
0A
%
20
%
20
%
20
%
20
//%
E4
%
BE
%
9B
%
E7
%
94
%
B5
%
E6
%
96
%
B9
%
E6
%
B3
%
95
%
EF
%
BC
%
8C16V
%
E7
%
9B
%
B4
%
E6
%
B5
%
81
%
E7
%
94
%
B5
%
0A
%
20
%
20
%
20
%
20public
%
20void
%
20electrifyDC16V
();%
0A
%
7D
%
0A
1public
%
20class
%
20GPS
%
20implements
%
20CigarLighterInterface
%
20
%
7B
%
0A2
%
20
%
20
%
20
%
20
//%
E5
%
AF
%
BC
%
E8
%
88
%
AA
%
E7
%
9A
%
84
%
E5
%
AE
%
9E
%
E7
%
8E
%
B0
%
0A3
%
20
%
20
%
20
%
20
@
Override
%
0A4
%
20
%
20
%
20
%
20public
%
20void
%
20electrifyDC16V
()%
20
%
7B
%
0A5
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20System
.
out
.
println
(%
22
%
E8
%
BF
%
9E
%
E6
%
8E
%
A5
%
E5
%
8D
%
AB
%
E6
%
98
%
9F
%
22
);%
0A6
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20System
.
out
.
println
(%
22
%
E5
%
AE
%
9A
%
E4
%
BD
%
8D
%
E3
%
80
%
82
%
E3
%
80
%
82
%
E3
%
80
%
82
%
22
);%
0A7
%
20
%
20
%
20
%
20
%
7D
%
0A8
%
0A9
%
7D
%
0A
%
201public
%
20class
%
20CigarLighter
%
20implements
%
20CigarLighterInterface
%
20
%
7B
%
0A
%
202
%
20
%
20
%
20
%
20
//%
E7
%
82
%
B9
%
E7
%
83
%
9F
%
E5
%
99
%
A8
%
E7
%
9A
%
84
%
E5
%
AE
%
9E
%
E7
%
8E
%
B0
%
0A
%
203
%
20
%
20
%
20
%
20
@
Override
%
0A
%
204
%
20
%
20
%
20
%
20public
%
20void
%
20electrifyDC16V
()%
20
%
7B
%
0A
%
205
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20int
%
20time
%
20
=%
201000
;%
0A
%
206
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20while
(--
time
&
gt
;
0
)%
7B
%
0A
%
207
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20System
.
out
.
println
(%
22
%
E5
%
8A
%
A0
%
E7
%
83
%
AD
%
E7
%
94
%
B5
%
E7
%
82
%
89
%
E4
%
B8
%
9D
%
22
);%
0A
%
208
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
7D
%
0A
%
209
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20System
.
out
.
println
(%
22
%
E7
%
82
%
B9
%
E7
%
83
%
9F
%
E5
%
99
%
A8
%
E5
%
BC
%
B9
%
E5
%
87
%
BA
%
22
);%
0A10
%
20
%
20
%
20
%
20
%
7D
%
0A11
%
0A12
%
7D
%
0A
对于点烟器接口来说,它根本不在乎也不知道对接的外设是什么鬼,它只是定义了一种规范,一种标准,只要符合的都可以对接。再比如
USB
接口的应用更加广泛,外设更是应有尽有,具体例子可以参考文章《设计模式是什么鬼(初探)》。
以上我们可以体会到接口的抽象是淋漓尽致的,实现是空无的,也就是说其方法都是无实现的。然而这样在某些场景下会存在一些问题,例如有时候我们在父类中只需抽象出一些方法,并且同时也有一些实体方法,以供子类直接继承,这怎么办?答案就是抽象类。举个例子,哺乳动物类,我们人类就是哺乳动物。
什么?鲸鱼是哺乳类?是的,凡是喂奶的都是哺乳类,不要以为会游泳的都是鱼,会飞的都是鸟,蝙蝠同样是哺乳类,只不过是老鼠中的飞行员而已。
既然如此这哺乳动物肯定是都能喂奶了,但是到底是跑还是游,或是飞呢还真不好说,但至少可以确认它们都是可以移动的。言归正传,我们开始定义哺乳动物抽象类。
%
201public
%
20abstract
%
20class
%
20Mammal
%
20
%
7B
%
0A
%
202
%
0A
%
203
%
20
%
20
%
20
%
20
//%
E6
%
97
%
A2
%
E7
%
84
%
B6
%
E6
%
98
%
AF
%
E5
%
93
%
BA
%
E4
%
B9
%
B3
%
E5
%
8A
%
A8
%
E7
%
89
%
A9
%
E5
%
BD
%
93
%
E7
%
84
%
B6
%
E4
%
BC
%
9A
%
E5
%
96
%
82
%
E5
%
A5
%
B6
%
E4
%
BA
%
86
%
EF
%
BC
%
8C
%
E4
%
BD
%
86
%
E8
%
BF
%
99
%
E9
%
87
%
8C
%
E7
%
BA
%
A6
%
E6
%
9D
%
9F
%
E4
%
B8
%
BA
%
E5
%
8F
%
AA
%
E8
%
83
%
BD
%
E6
%
AF
%
8D
%
E7
%
9A
%
84
%
E5
%
96
%
82
%
E5
%
A5
%
B6
%
0A
%
204
%
20
%
20
%
20
%
20protected
%
20final
%
20void
%
20feedMilk
()%
7B
%
0A
%
205
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20if
(
female
)%
7B
//%
E5
%
A6
%
82
%
E6
%
9E
%
9C
%
E6
%
98
%
AF
%
E6
%
AF
%
8D
%
E7
%
9A
%
84
%
E2
%
80
%
A6
%
E2
%
80
%
A6
%
0A
%
206
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20System
.
out
.
println
(%
22
%
E5
%
96
%
82
%
E5
%
A5
%
B6
%
22
);%
0A
%
207
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
7Delse
%
7B
//%
E5
%
A6
%
82
%
E6
%
9E
%
9C
%
E6
%
98
%
AF
%
E5
%
85
%
AC
%
E7
%
9A
%
84
%
E2
%
80
%
A6
%
E2
%
80
%
A6
%
E6
%
88
%
96
%
E8
%
80
%
85
%
E5
%
8F
%
AF
%
E4
%
BB
%
A5
%
E6
%
8A
%
9B
%
E4
%
B8
%
AA
%
E5
%
BC
%
82
%
E5
%
B8
%
B8
%
E5
%
87
%
BA
%
E5
%
8E
%
BB
%
E3
%
80
%
82
%
0A
%
208
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20System
.
out
.
println
(%
22
%
E5
%
85
%
AC
%
E7
%
9A
%
84
%
E4
%
B8
%
8D
%
E4
%
BC
%
9A
%
22
);%
0A
%
209
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
7D
%
0A10
%
20
%
20
%
20
%
20
%
7D
%
0A11
%
0A12
%
20
%
20
%
20
%
20
//%
E5
%
93
%
BA
%
E4
%
B9
%
B3
%
E5
%
8A
%
A8
%
E7
%
89
%
A9
%
E5
%
BD
%
93
%
E7
%
84
%
B6
%
E5
%
8F
%
AF
%
E4
%
BB
%
A5
%
E7
%
A7
%
BB
%
E5
%
8A
%
A8
%
EF
%
BC
%
8C
%
E4
%
BD
%
86
%
E5
%
85
%
B7
%
E4
%
BD
%
93
%
E6
%
80
%
8E
%
E4
%
B9
%
88
%
E7
%
A7
%
BB
%
E5
%
8A
%
A8
%
E8
%
BF
%
98
%
E4
%
B8
%
8D
%
E7
%
9F
%
A5
%
E9
%
81
%
93
%
E3
%
80
%
82
%
0A13
%
20
%
20
%
20
%
20public
%
20abstract
%
20void
%
20move
();%
0A14
%
7D
%
0A
这里我们省略了
female
属性,其作用是为了控制喂奶行为,大家可以自行添加。可以看到的是,抽象类不同于接口,其自身是可以有具体实现的,也就是说抽象类是虚实结合的,虚部抽象行为,实部遗传给子类,虚虚实实,飘忽不定。
OK
,我们看下人、鲸、蝠的子类实现。
public
%
20class
%
20Human
%
20extends
%
20Mammal
%
20
%
7B
%
0A
%
0A
%
20
%
20
%
20
%
20
@
Override
%
0A
%
20
%
20
%
20
%
20public
%
20void
%
20move
()%
20
%
7B
%
0A
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20System
.
out
.
println
(%
22
%
E4
%
B8
%
A4
%
E6
%
9D
%
A1
%
E8
%
85
%
BF
%
E8
%
B5
%
B0
%
E8
%
B7
%
AF
%
E2
%
80
%
A6
%
E2
%
80
%
A6
%
22
);%
0A
%
20
%
20
%
20
%
20
%
7D
%
0A
%
0A
%
7D
%
0A
public
%
20class
%
20Whale
%
20extends
%
20Mammal
%
20
%
7B
%
0A
%
0A
%
20
%
20
%
20
%
20
@
Override
%
0A
%
20
%
20
%
20
%
20public
%
20void
%
20move
()%
20
%
7B
%
0A
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20System
.
out
.
println
(%
22
%
E6
%
B8
%
B8
%
E6
%
B3
%
B3
%
E2
%
80
%
A6
%
E2
%
80
%
A6
%
22
);%
0A
%
20
%
20
%
20
%
20
%
7D
%
0A
%
0A
%
7D
%
0A
public
%
20class
%
20Bat
%
20extends
%
20Mammal
%
20
%
7B
%
0A
%
0A
%
20
%
20
%
20
%
20
@
Override
%
0A
%
20
%
20
%
20
%
20public
%
20void
%
20move
()%
20
%
7B
%
0A
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20System
.
out
.
println
(%
22
%
E7
%
94
%
A8
%
E7
%
BF
%
85
%
E8
%
86
%
80
%
E9
%
A3
%
9E
%
E2
%
80
%
A6
%
E2
%
80
%
A6
%
22
);%
0A
%
20
%
20
%
20
%
20
%
7D
%
0A
%
0A
%
7D
%
0A
可以看到子类的各路实现都是自己独有的行为方式,而喂奶那个行为是不需要自己实现的,它是属于抽象哺乳类的共有行为,哺乳子类不能进行任何干涉。这便是接口与抽象的最大区别了,接口是虚的,抽象类可以有虚有实,接口不在乎实现类是什么,抽象类会延续其基因给子类。
其实到这里我们已经说了一大半了,理解了以上部分,剩下的部分就非常简单了,利用抽象类的这个特性,便有了“模板方法”。举例说明,我们做软件项目管理,按瀑布式简单来讲分为:需求分析、设计、编码、测试、发布,先不管是用何种方式去实现各个细节,我们就抽象成这五个步骤。
public
%
20abstract
%
20class
%
20PM
%
20
%
7B
%
0A
%
20
%
20
%
20
%
20protected
%
20abstract
%
20void
%
20analyze
();//%
E9
%
9C
%
80
%
E6
%
B1
%
82
%
E5
%
88
%
86
%
E6
%
9E
%
90
%
0A
%
20
%
20
%
20
%
20protected
%
20abstract
%
20void
%
20design
();//%
E8
%
AE
%
BE
%
E8
%
AE
%
A1
%
0A
%
20
%
20
%
20
%
20protected
%
20abstract
%
20void
%
20develop
();//%
E5
%
BC
%
80
%
E5
%
8F
%
91
%
0A
%
20
%
20
%
20
%
20protected
%
20abstract
%
20boolean
%
20test
();//%
E6
%
B5
%
8B
%
E8
%
AF
%
95
%
0A
%
20
%
20
%
20
%
20protected
%
20abstract
%
20void
%
20release
();//%
E5
%
8F
%
91
%
E5
%
B8
%
83
%
0A
%
7D
%
0A
那么问题来了,有个程序员在需求不明确或者设计不完善的情况下,一上来二话不说直接写代码,这样就会造成资源的浪费,后期改动太大还会影响项目进度。那么项目经理这时就应该规范一下这个任务流程,这里我们加入
kickoff
()方法实现。
%
201public
%
20abstract
%
20class
%
20PM
%
20
%
7B
%
0A
%
202
%
20
%
20
%
20
%
20protected
%
20abstract
%
20void
%
20analyze
();//%
E9
%
9C
%
80
%
E6
%
B1
%
82
%
E5
%
88
%
86
%
E6
%
9E
%
90
%
0A
%
203
%
20
%
20
%
20
%
20protected
%
20abstract
%
20void
%
20design
();//%
E8
%
AE
%
BE
%
E8
%
AE
%
A1
%
0A
%
204
%
20
%
20
%
20
%
20protected
%
20abstract
%
20void
%
20develop
();//%
E5
%
BC
%
80
%
E5
%
8F
%
91
%
0A
%
205
%
20
%
20
%
20
%
20protected
%
20abstract
%
20boolean
%
20test
();//%
E6
%
B5
%
8B
%
E8
%
AF
%
95
%
0A
%
206
%
20
%
20
%
20
%
20protected
%
20abstract
%
20void
%
20release
();//%
E5
%
8F
%
91
%
E5
%
B8
%
83
%
0A
%
207
%
0A
%
208
%
20
%
20
%
20
%
20protected
%
20final
%
20void
%
20kickoff
()%
7B
%
0A
%
209
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20analyze
();%
0A10
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20design
();%
0A11
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20develop
();%
0A12
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20test
();%
0A13
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20release
();%
0A14
%
20
%
20
%
20
%
20
%
7D
%
0A15
%
7D
%
0A
这样就限制了整个项目周期的任务流程,注意这里要用
final
声明此方法子类不可以重写,只能乖乖的继承下去用。至于其他的抽象方法,子类可以自由发挥,比如测试方法
test
(),子类可以用人工测试,自动化测试,我们不
care
,我们是站在项目管理的抽象高度,只把控流程进度。这里甚至我们还可以加入一些逻辑如下。
%
201public
%
20abstract
%
20class
%
20PM
%
20
%
7B
%
0A
%
202
%
20
%
20
%
20
%
20protected
%
20abstract
%
20void
%
20analyze
();//%
E9
%
9C
%
80
%
E6
%
B1
%
82
%
E5
%
88
%
86
%
E6
%
9E
%
90
%
0A
%
203
%
20
%
20
%
20
%
20protected
%
20abstract
%
20void
%
20design
();//%
E8
%
AE
%
BE
%
E8
%
AE
%
A1
%
0A
%
204
%
20
%
20
%
20
%
20protected
%
20abstract
%
20void
%
20develop
();//%
E5
%
BC
%
80
%
E5
%
8F
%
91
%
0A
%
205
%
20
%
20
%
20
%
20protected
%
20abstract
%
20boolean
%
20test
();//%
E6
%
B5
%
8B
%
E8
%
AF
%
95
%
0A
%
206
%
20
%
20
%
20
%
20protected
%
20abstract
%
20void
%
20release
();//%
E5
%
8F
%
91
%
E5
%
B8
%
83
%
0A
%
207
%
0A
%
208
%
20
%
20
%
20
%
20protected
%
20final
%
20void
%
20kickoff
()%
7B
%
0A
%
209
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20analyze
();%
0A10
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20design
();%
0A11
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20do
%
20
%
7B
%
0A12
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20develop
();%
0A13
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
7D
%
20while
%
20
(!
test
());//%
E5
%
A6
%
82
%
E6
%
9E
%
9C
%
E6
%
B5
%
8B
%
E8
%
AF
%
95
%
E5
%
A4
%
B1
%
E8
%
B4
%
A5
%
EF
%
BC
%
8C
%
E5
%
88
%
99
%
E7
%
BB
%
A7
%
E7
%
BB
%
AD
%
E5
%
BC
%
80
%
E5
%
8F
%
91
%
E6
%
94
%
B9Bug
%
E3
%
80
%
82
%
0A14
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20release
();%
0A15
%
20
%
20
%
20
%
20
%
7D
%
0A16
%
7D
%
0A
以下子类只需实现抽象方法,而不用实现固有的模板方法
kickoff
(),因为它已经被父类
PM
实现了,并且子类也不能进行重写。
1public
%
20class
%
20AutoTestPM
%
20extends
%
20PM
%
7B
%
0A2
%
0A3
%
20
%
20
%
20
%
20
@
Override
%
0A4
%
20
%
20
%
20
%
20protected
%
20void
%
20analyze
()%
20
%
7B
%
0A5
%
20
%
20
%
20
%
20
%
20
%
20
%
20
%
20System
.
out
.
println
(%
22
%
E8
%
BF
%
9B
%
E8
%
A1
%
8C
%
E4
%
B8
%
9A
%
E5
%
8A
%
A1
%
E6
%
B2
%
9F
%
E9
%
80
%
9A
%
EF
%
BC
%
8C
%
E9
%
9C
%
80
%
E6
%
B1
%
82
%
E5
%
88
%
86
%
E6
%
9E
%
90
%
22
);%
20
%
20
%
20
%
20
%
20
%
0A6
%
20
%
20
%
20
%
20
%
7D
%
0A7
%
0A8
%
20
%
20
%
20
%
20
//
design
();
develop
();
test
();
release
();%
E5
%
AE
%
9E
%
E7
%
8E
%
B0
%
E7
%
9C
%
81
%
E7
%
95
%
A5
%
0A9
%
7D
%
0A
至此,我们的模板方法就完成了,抽象类
PM
中的实方法
kickoff
()中,以某种逻辑编排调用了其他各个抽象方法,提供了一种固定模式的行为方式或是指导方针,以此达到虚实结合、柔中带刚、刚柔并济,灵活中不失规范的目的。
当然大部分情况我们使用接口会多于抽象类,因为接口灵活啊,抽象类不允许多继承啊等等,其实我们还是要看应用场景,在某种无规矩不成方圆,或者规范比较明确,的情况下抽象类的应用是有必要的,世间万物没有最好的,只有最合适的。
看完本文有收获?请转发分享给更多人
以上数据来源于网络,如有侵权,请联系删除。
上一篇:
面试官:线上服务平均响应时间太长,怎么排查?
下一篇:
SQL数据库面试题以及答案(50例题)
评论
(0)
提交
类别
基础编程学习
HTML
PHP
Python
编程知识库
后端开发知识
热门文章
Java并发中的同步容器与并发容器,你了解多少?
Innodb中的事务隔离级别和锁的关系,难倒一半面试者!
SpringBoot + minio实现分片上传、秒传、续传
面试官:你知道消息队列如何保证数据不丢失吗?
JAVA知识 Java8新特性
面试官:谈谈为什么要限流,有哪些限流方案?
说说动态代理与静态代理区别
面试官:思考Tomcat 类加载器为什么要违背双亲委派模型?
boot-admin 基于SpringBoot的后台权限管理系统,可作为脚手架,用于快速搭建项目
SpringBoot+Vue+App+硬件实现智能家居系统项目