上一篇《Java 设计模式之工厂方法模式与抽象工厂模式》介绍了三种工厂模式,分别是工厂方法模式,简单工厂方法模式,抽象工厂模式,文中详细根据实际场景介绍了三种模式的定义,实践,最后总结了三种方式的区别,以及各个模式的适用场景。这一篇博文咱们来学习下模板方法模式和建造者模式。java
2.1 模板方法模式的定义和实践算法
定义:Define the skeleton of an algorithm in an operation.deferring some steps to subclasses.Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.设计模式
翻译:定义一个操做中的算法框架,从而延迟子类中的一些步骤。使得子类能够不改变算法结构的状况下就能够从新定义该算法的某些特定的步骤。bash
其实根据上面定义,咱们很快就能够想到,这个模式的定义不就是继承吗?对,没错,模板方法模式最简单的实现就是继承。咱们先用代码来实现一个模板方法模式。相信你们都吃过泡面吧,咱们来用模板方法模式来泡个面吧。框架
public abstract class AbstractTemplate {
/**
* 烧开水*/
public abstract void boilWater();
/**煮面条*/
public abstract void cookNoodles();
/**放调料*/
public abstract void putCondiment();
/**定义煮面的模板,先烧水,再放面条,最后放调料*/
public void finish(){
boilWater();
cookNoodles();
putCondiment();
System.out.println("煮完啦,开吃咯!");
}
}
/**煮方便面模板实现类*/
public class InstantNoodlesTemplate extends AbstractTemplate{
@Override
public void boilWater() {
System.out.println("烧开水啦!");
}
@Override
public void cookNoodles() {
System.out.println("放入方便面啦!");
}
@Override
public void putCondiment() {
System.out.println("能够放调料啦!");
}
}
/**客户端场景类*/
public class Client {
public static void main(String[] args) {
AbstractTemplate template=new InstantNoodlesTemplate();
template.finish();
}
}
复制代码
上面的的finish()
方法就是定义了一个算法框架,定义了煮面条先要烧开水,而后放面条,最后放调料的算法步骤。而后各个子类实现如何烧水,放什么面条,放什么调料这样的具体实现。这就是模板方法模式,仅仅经过继承就实现了。就是这么简单,下面咱们来看看和模板方法模式相识的另一个模式,建造者模式。ide
2.21 建造者模式的定义和实践函数
定义:Separate the construction of a complex object from its representation so that the same construction process can create different representations.post
翻译:将一个复杂对象的构建与他的表现分离,使得一样的构建过程能够建立不一样的表示。学习
这里化重点,复杂对象的构建和表现分离,这里用在上面煮面的场景中就是说,煮面的算法和定义是分离的,也就是说由各个具体的面条品种决定如何去煮面条,如何去放调料等等这些具体的算法步骤。咱们来用代码实现下:ui
//抽象煮苗条类
public abstract class AbstractNoodlesMode {
private List<String> stepOrders = new ArrayList<>();
/**
* 烧开水
*/
public abstract void boilWater();
/**
* 煮面条
*/
public abstract void cookNoodles();
/**
* 放调料
*/
public abstract void putCondiment();
/**
* 煮面条其余步骤
*/
public abstract void doOther();
/**
* 根据传入的工序进行加工煮面
*/
final public void finish() {
for (String stepOrder : this.stepOrders) {
switch (stepOrder) {
case "boilWater":
boilWater();
break;
case "cookNoodles":
cookNoodles();
break;
case "putCondiment":
putCondiment();
break;
case "doOther":
doOther();
break;
default:
System.out.println("没法识别的烹饪指令");
break;
}
}
}
final public void setStepOrders(List<String> stepOrders) {
this.stepOrders = stepOrders;
}
}
/**方便面的实现类,因为只须要烧水,煮面,放调料就好了,other方法就为空*/
public class InstantNoodles extends AbstractNoodlesMode {
@Override
public void boilWater() {
System.out.println("煮开水");
}
@Override
public void cookNoodles() {
System.out.println("放入方便面");
}
@Override
public void putCondiment() {
System.out.println("放入调料");
}
@Override
public void doOther() {
}
}
/**意大利面条实现类*/
public class Spaghetti extends AbstractNoodlesMode {
@Override
public void boilWater() {
System.out.println("煮开水");
}
@Override
public void cookNoodles() {
System.out.println("放入意大利面");
}
@Override
public void putCondiment() {
System.out.println("放入番茄酱");
}
@Override
public void doOther() {
System.out.println("放入火腿,早餐肉");
}
}
/**抽象建造者类*/
public abstract class AbstractBuilder {
/**定义煮面条工序*/
public abstract AbstractBuilder cookNoodles();
/**完成面条*/
public abstract AbstractNoodlesMode build();
}
/**泡面建造者实现类*/
public class InstantNoodlesBuilder extends AbstractBuilder {
private AbstractNoodlesMode noodles=new InstantNoodles();
@Override
public AbstractBuilder cookNoodles() {
List<String> steps=new ArrayList<>();
//烧水
steps.add("boilWater");
//放面条
steps.add("cookNoodles");
//放调料
steps.add("putCondiment");
this.noodles.setStepOrders(steps);
return this;
}
@Override
public AbstractNoodlesMode build() {
return this.noodles;
}
}
/*意大利面条建造者实现类**/
public class SpaghettiBuilder extends AbstractBuilder {
private AbstractNoodlesMode noodle = new Spaghetti();
@Override
public AbstractBuilder cookNoodles() {
List<String> steps = new ArrayList<>();
//烧水
steps.add("boilWater");
//放面条
steps.add("cookNoodles");
//放调料
steps.add("putCondiment");
//放火腿,放早餐肉
steps.add("doOther");
this.noodle.setStepOrders(steps);
return this;
}
@Override
public AbstractNoodlesMode build() {
return this.noodle;
}
}
/**客户端场景类*/
public class Client {
public static void main(String[] args) {
AbstractBuilder instantNoodleBuilder = new InstantNoodlesBuilder();
AbstractBuilder spaghettiBuilder = new SpaghettiBuilder();
AbstractNoodlesMode instantNoodle = instantNoodleBuilder.cookNoodles().build();
instantNoodle.finish();
System.out.println("--------------------");
AbstractNoodlesMode spaghe = spaghettiBuilder.cookNoodles().build();
spaghe.finish();
}
}
复制代码
咱们运行下结果以下:
上述代码咱们整理成一个类图以下:
上面类图我省去了面条实现类,可是这也不影响整个建造者模式的理解。这里有同窗确定会问,这个建造者模式虽然比模板方法模式复杂点,可是感受他们很类似啊,有点弄混的感受啊。对,没错,他们确实很相识。可是咱们只要记住一点就能很好的区分他们。
咱们只要记住这一点就能很好的区分模板方法模式和建造者模式,同时也就知道了何时采用模板方法模式,何时采用建造者模式。
3.1 模板方法模式的使用场景
1.多个子类有公有的方法,而且逻辑基本同样时。
2.有重要核心的复杂算法,并且须要不少的复用性时,能够把该算法用模板方法模式实现。
3.代码重构升级时,模板方法模式是很经常使用的模式,通常为了保证向下兼容,因此采用模板方法模式,在模板方法内会设置钩子函数,根据不一样的版本和不一样的状况执行不一样的算法。
3.2 建造者模式的使用场景
1.相同的方法,不一样的执行顺序,产生不一样的事件结果时,能够采用建造者模式
2.多个部件或零件,均可以装配到一个对象中,可是产生的结果又不相同。
4.1模板方法模式
优势:
缺点:
4.2建造者模式
优势:
缺点:
模板方法模式和建造者模式都是属于创造性模式,两个模式代码很类似,很容易弄混,咱们只要记住他们的核心区别就能够知道何时该用模板方法模式,何时该用建造者模式。这里再说一遍他们的主要区别: 模板方法模式定义了核心算法,也就是组装工序,而建造者模式没有定义建造的顺序和构造多少零件,最后的核心工序以及使用零件实现彻底由子类去决定。
详细细心的读者确定以及发现了个人建造模式中的实现出现了instantNoodleBuilder.cookNoodles().build()
这样A.B.C
的代码,以前在咱们的设计模式开篇咱们谈到了迪米特法则,迪米特法则有举例说不要出现A.B.C
的状况,这里说明下迪米特法则的要求实际上是不要出现依赖非朋友类的状况,其实其实是不要出现A.getB.getC
的状况,而这里其实每次返回的都是this
,因此都是依赖的本身,并无出现非朋友类,因此这样的写法没有违法迪米特法则。
《设计模式之禅》