目录
1.模板方法模式
2.策略模式
3.命令模式
4.职责链模式
一、模板方法模式(Template Method)
定义操作中的算法骨架,将某些步骤延迟到子类中实现。这样,新的子类可以在不改变一个算法结构的前提下重新定义该算法的某些特定步骤。即:处理步骤父类中定义好,具体实现延迟到子类中定义。
核心角色:
- (1)抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。定义如下:
1、模板方法:定义算法骨架,按某个顺序调用其包含的基本方法。
2、基本方法:是整个方法的一个步骤,包含有:
抽象方法:在抽象类中声明,由具体类实现。
具体方法:在抽象类中已经实现,可以在子类中继承或重写它
钩子方法:在抽象类已经实现,包括判断逻辑方法和需要子类重写的空方法两种。
- (2)具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,是一个顶级逻辑的一个组成步骤。
优点:
- (1)封装了不变部分在父类中实现,变的部分在子类中实现,便于子类的继续扩展。
- (2)在父类中提取了公共部分代码,便于代码的复用。
- (3)部分方法是在子类实现的,子类可以扩展增加相应的功能,符号开闭原则。
缺点:
- (1)对每一个不同的实现都需要定义子类,导致类的数量增加,设计也更抽象。
- (2)父类的抽象方法由子类实现,子类执行的结构会影响父类的结果,导致了一种反向的控制结构,提高了代码阅读的难度。
public class textTemplateMethod {
public static void main(String[] args) {
// TODO Auto-generated method stub
//模拟一个排队打饭的场景。
//前面两个步骤:排队、打饭、是每一个人都要做的。可以建立为模板
//吃饭和各自洗盘子。是扩展完成的
AbstractClass tm = new ConcreteClass();
tm.TemplateMethod();
}
}
//抽象类
abstract class AbstractClass{
public void TemplateMethod() { //模板方法
SpecificMethod();
abstractMethod1();
abstractMethod2();
}
public void SpecificMethod() { //具体方法
System.out.println("排队");
System.out.println("打饭");
}
public abstract void abstractMethod1(); //抽象方法1
public abstract void abstractMethod2(); //抽象方法1
}
//具体子类
class ConcreteClass extends AbstractClass{
@Override
public void abstractMethod1() {
System.out.println("各自找位置吃饭");
}
@Override
public void abstractMethod2() {
System.out.println("各自洗各自的盘子");
}
}
二、策略模式(Strategy)
定义了一系列的算法,并将每个算封装起来成为一个算法族。允许用户从算法族中任选一个算法解决某问题,且算法的变化不会影响使用算法的客户,使算法的责任和算法的实现分隔开,并委派给不同的对象对这些算法进行管理。
核心角色:
- (1)抽象策略类(Strategy):定义一个公共接口,不同的算法以不同的方法区实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。
- (2)具体策略类(Concrete Strategy):实现了抽象策略定义的接口。提供具体的算法实现。
- (3)环境类(Context):只有一个策略类的引用,最终给客户端调用。
优点:
- (1)多重条件语句不易维护,使用策略模式可以避免使用多重条件语句。
- (2)可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的策略。
- (3)提供了对开闭原则的完美支持,不修改原代码的情况下,灵活增加新算法。
- (4)将算法的使用放在环境中,算法的实现移到具体的策略中。实现了二者分离。
缺点:
- (1)客户端必须理解所有的策略算法区别,以便适时选择恰当的算法类。
- (2)策略模式造成很多策略类。
public class textTemplateMethod {
public static void main(String[] args) {
// TODO Auto-generated method stub
//模拟一个做菜。像龙虾的做法有很多。举椒盐、清蒸的方法。
Context cf = new Context();//创建厨房
Strategy lx = new ConcreteStrategyA();//椒盐龙虾做法
cf.setStrategy(lx);//厨房做菜
cf.strategyMethod();//炒出来的菜
}
}
//抽象策略类 (龙虾加工类)
interface Strategy{
public void strategyMethod();//策略方法 (做菜的方法)
}
//具体策略类A
class ConcreteStrategyA implements Strategy{
@Override
public void strategyMethod() {
System.out.println("椒盐龙虾");
}
}
//具体策略类B
class ConcreteStrategyB implements Strategy{
@Override
public void strategyMethod() {
System.out.println("清蒸龙虾");
}
}
//环境类 (厨房)
class Context{
private Strategy strategy;
public Strategy getStrategy() {
return strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void strategyMethod() {
strategy.strategyMethod(); //做菜
}
}
三、命令模式(Command)
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分离开。两者通过命令来沟通。方便将命令对象进行存储、传递、调用、增加与管理。
核心角色:
- (1)抽象命令类角色(Command):声明执行命令的接口,拥有执行命令的抽象方法execute().
- (2)具体命令角色(Concrete Command):实现抽象命令类,拥有接收者对象,并且调用接收者的功能来完成命令要执行的操作。
- (3)实现者/接收者角色(Receiver):执行命令功能的相关操作,是具体命令对象业务的真正实现者。
- (4)调用者/请求者角色(Invoker):是请求的发送者,通过拥有很多的命令对象和访问命令对象来执行相关的请求,它不直接访问接收者。
优点:
- (1)降低了系统的耦合度。能将调用操作的对象与实现该操作的对象解耦。
- (2)增加或删除命令非常方便。增加和删除不会影响其他类,满足开原则。
- (3)可以实现宏命令。可以与组合模式结合,将多个命令装配成一组命令(宏命令)
- (4)方便实现Undo、Redo操作。与备忘录模式结合,实现命令的撤销和恢复。
缺点:
- (1)可能产生大量具体命令类。每一个具体操作都需要设计一个具体命令类。增加了系统复杂性。
public class textCommand {
public static void main(String[] args) {
// TODO Auto-generated method stub
//模拟客户去餐厅吃饭。客户向服务员下达命令,然后。服务员向厨师下达命令,最后上菜
//这里与吃肠粉为例
Command command = new ConcreteCommand();//先是客户点了肠粉
Invoker fuy = new Invoker(command);//向服务员下达命令
fuy.call(); //厨师做出肠粉
}
}
//调用者 (服务员)
class Invoker{
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void setCommand(Command command) {
this.command = command;
}
public void call() {
command.exectue();//调用者执行命令
}
}
//抽象命令 (早餐)
interface Command{
public abstract void exectue();
}
//具体命令 (肠粉)
class ConcreteCommand implements Command{
private Receiver receiver;
ConcreteCommand(){
receiver = new Receiver(); //创建做肠粉的厨师
}
@Override
public void exectue() {
receiver.action();
}
}
//接收者 (做肠粉的厨师)
class Receiver{
public void action() {//接收者方法
System.out.println("做肠粉");
}
}
四、职责链模式(Chain of Responsibility)
能够处理同一类请求的对象连成一条链,所提交的请求沿着链传递链上的对象逐个判断是否有能力处理该请求,如果能则处理。反之,把请求传递给下一个对象。
核心角色:
- (1)抽象处理者角色(Handler):定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
- (2)具体处理者角色(Concrete Handler):实现抽象处理者的方法,判断能否处理本次请求。如果能则处理。反之,将请求转给它的后继者。
- (3)客户类角色(Client):创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
优点:
- (1)降低了对象之间的耦合度。发送者和接收者无须拥有对方的明确信息。
- (2)增强了系统的可扩展性。可以根据需要增加需要处理的类,满足开闭原则。
- (3)增强了给对象指派职责的灵活性。当工作流程发生变化时,可以动态地改变链内的成员或调动他们的次序,也可以动态地新增或者删除责任。
- (4)职责链简化了对象之间的连接。每个对象只要保持指向后继的引用。避免了if…else
- (5)责任分担。每个类只需要处理自己该处理的工作。符合单一职责原则。
缺点:
- (1)不能保证每一个请求一定被处理。可能一直传到末端都不能处理。
- (2)对比较长的职责链,请求的处理可能涉及过个对象,系统性能将受一定的影响。
- (3)职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性。
public class textCommand {
public static void main(String[] args) {
// TODO Auto-generated method stub
//模拟一个请假的情况,
//如果请假是两天以内的,班主任可以批假。超过了两天,7天以内,就要系主任批假
Handler bzr = new ConcreteHandlerA();//班主任
Handler xzr = new ConcreteHandlerB();//系主任
bzr.setNext(xzr);//班主任到系主任
bzr.handleRequest(5);//5天,班主任处理不了。推给系主任处理
}
}
//抽象者处理者
abstract class Handler{
private Handler next;
public Handler getNext() {
return next;
}
public void setNext(Handler next) {
this.next = next;
}
public abstract void handleRequest(int request);
}
//具体处理者A
class ConcreteHandlerA extends Handler{
@Override
public void handleRequest(int request) {
if(request <= 2) {
System.out.println("班主任批准你请<"+request+">天假");
}else {
if(getNext() != null) { //推给下一个继后者
getNext().handleRequest(request);
}else {
System.out.println("请假的天数太多,不能批假,请找主任。");
}
}
}
}
//具体处理者B
class ConcreteHandlerB extends Handler{
@Override
public void handleRequest(int request) {
if(request <= 7) {
System.out.println("系主任批准你请<"+request+">天假");
}else {
if(getNext() != null) { //推给下一个继后者
getNext().handleRequest(request);
}else {
System.out.println("请假的天数太多,不能批假");
}
}
}
}