1. 简介
描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。
行为型模式包括:模板方法模式、策略模式、命令模式、责任链模式、状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式、解释器模式。
2. 行为型模式分类
(1) 模板方法模式
说明:将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
优点
它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
它在父类中提取了公共的部分代码,便于代码复用。
部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。
缺点
对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
抽象类源码
package com.design;
public abstract class AbstractBankBusiness {
public void work() {
takeNum();
checkInfo();
changeMoney();
}
protected abstract void checkInfo();
protected abstract void changeMoney();
public void takeNum() {
System.out.println("进行银行取号排队!!!");
}
}
具体子类源码
package com.design;
public class BankSaveMoney extends AbstractBankBusiness {
@Override
public void checkInfo() {
System.out.println("验证用户的基本资料是否齐全!");
}
@Override
public void changeMoney() {
System.out.println("存钱业务进行了!");
}
}
模板方法执行源码
package com.design;
public class TemplateMethodTest {
public static void main(String[] args) {
AbstractBankBusiness abstractBankBusiness = new BankSaveMoney();
abstractBankBusiness.work();
}
}
(2) 策略模式
说明:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。
抽象策略类源码
package com.design;
public interface Strategy {
void compute();
}
具体策略类源码
package com.design;
public class StrategyA implements Strategy {
@Override
public void compute() {
System.out.println("策略A具体实现算法!");
}
}
package com.design;
public class StrategyB implements Strategy {
@Override
public void compute() {
System.out.println("策略B具体实现!");
}
}
环境类源码
package com.design;
public class Context {
private Strategy strategy;
public Strategy getStrategy() {
return strategy;
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
public void compute() {
strategy.compute();
}
}
策略执行源码
package com.design;
public class StrategyTest {
public static void main(String[] args) {
Context context = new Context();
context.setStrategy(new StrategyA());
context.compute();
context.setStrategy(new StrategyB());
context.compute();
}
}
(3) 命令模式
说明:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。方便将命令对象进行储存、传递、调用、增加与管理。
优点
降低系统的耦合度。命令模式能将调用操作的对象与实现该操作的对象解耦。
增加或删除命令非常方便。采用命令模式增加与删除命令不会影响其他类,它满足“开闭原则”,对扩展比较灵活。
可以实现宏命令。命令模式可以与组合模式结合,将多个命令装配成一个组合命令,即宏命令。
方便实现 Undo 和 Redo 操作。命令模式可以与后面介绍的备忘录模式结合,实现命令的撤销与恢复。
缺点:
可能产生大量具体命令类。因为计对每一个具体操作都需要设计一个具体命令类,这将增加系统的复杂性。
抽象命令类角色源码
package com.design;
public interface Command {
void execute();
}
具体命令角色源码
package com.design;
public class CommandA implements Command {
private Receiver receiver;
public CommandA() {
this.receiver = new Receiver();
}
@Override
public void execute() {
receiver.action();
}
}
实现者/接收者角色源码
package com.design;
public class Receiver {
public void action() {
System.out.println("接收到命令,执行该操作... ");
}
}
调用者/请求者角色源码
package com.design;
public class Invoker {
private Command command;
public Invoker(Command command) {
this.command = command;
}
public void setCommand(Command command) {
this.command = command;
}
public void cell() {
command.execute();
}
}
命令执行源码
package com.design;
public class CommandTest {
public static void main(String[] args) {
Command command = new CommandA();
Invoker invoker = new Invoker(command);
invoker.cell();
}
}
(4) 责任链模式
说明:将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止。
优点
降低了对象之间的耦合度。该模式使得一个对象无须知道到底是哪一个对象处理其请求以及链的结构,发送者和接收者也无须拥有对方的明确信息。
增强了系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
增强了给对象指派职责的灵活性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者 if···else 语句。
责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
缺点
不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
抽象处理者角色源码
package com.design;
public abstract class Handler {
private Handler next;
public Handler getNext() {
return next;
}
public void setNext(Handler next) {
this.next = next;
}
public abstract void handleRequest(String info);
}
具体处理者角色源码
package com.design;
public class ConcreateHandler1 extends Handler {
@Override
public void handleRequest(String info) {
if("one".equals(info)) {
System.out.println("处理器1进行了处理!");
} else {
if(getNext() == null) {
System.out.println("没有处理器处理该请求!");
} else {
getNext().handleRequest(info);
}
}
}
}
package com.design;
public class ConcreateHandler2 extends Handler {
@Override
public void handleRequest(String info) {
if("two".equals(info)) {
System.out.println("处理器2处理了该请求!");
} else {
if(getNext() == null) {
System.out.println("没有处理器处理该请求!");
} else {
getNext().handleRequest(info);
}
}
}
}
客户类角色源码
package com.design;
public class HandlerTest {
public static void main(String[] args) {
Handler handler1 = new ConcreateHandler1();
Handler handler2 = new ConcreateHandler2();
handler1.setNext(handler2);
handler1.handleRequest("one");
handler1.handleRequest("two");
handler1.handleRequest("three");
}
}
(5) 状态模式
说明:对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
优点
状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”。
减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。
有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。
缺点
状态模式的使用必然会增加系统的类与对象的个数。
状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。
环境角色源码
package com.design;
public class StateContext {
private State state;
public StateContext(){
state = new ConcreateStateA();
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void handle() {
state.Handle(this);
}
}
抽象状态角色源码
package com.design;
public abstract class State {
public abstract void Handle(StateContext context);
}
具体状态角色源码
package com.design;
public class ConcreateStateA extends State {
@Override
public void Handle(StateContext context) {
System.out.println("状态A被执行...");
context.setState(new ConcreateStateB());
}
}
package com.design;
public class ConcreateStateB extends State {
@Override
public void Handle(StateContext context) {
System.out.println("状态B被执行...");
context.setState(new ConcreateStateA());
}
}
状态执行源码
package com.design;
public class StateTest {
public static void main(String[] args) {
StateContext stateContext = new StateContext();
stateContext.handle();
stateContext.handle();
stateContext.handle();
stateContext.handle();
}
}
(6) 观察者模式
说明:多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
优点
降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。
目标与观察者之间建立了一套触发机制。
缺点
目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。
当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。
抽象主题角色源码
package com.design;
import java.util.ArrayList;
import java.util.List;
public abstract class ObserverSubject {
protected List<Observer> list = new ArrayList<>();
public void add(Observer observer) {
list.add(observer);
}
public void remove(Observer observer) {
list.remove(observer);
}
public abstract void notifyObservers();
}
具体主题角色源码
package com.design;
public class ConcreateObserverSubject extends ObserverSubject {
@Override
public void notifyObservers() {
System.out.println("开始通知观察者。。。");
for(Observer observer : list) {
observer.response();
}
}
}
抽象观察者角色源码
package com.design;
public interface Observer {
void response();
}
具体观察者角色源码
package com.design;
public class ConcreateObserver1 implements Observer {
@Override
public void response() {
System.out.println("观察者1进行了回复...");
}
}
package com.design;
public class ConcreateObserver2 implements Observer {
@Override
public void response() {
System.out.println("观察者2进行了回复...");
}
}
观察者执行源码
package com.design;
public class ObserverTest {
public static void main(String[] args) {
Observer observer1 = new ConcreateObserver1();
Observer observer2 = new ConcreateObserver2();
ObserverSubject observerSubject = new ConcreateObserverSubject();
observerSubject.add(observer1);
observerSubject.add(observer2);
observerSubject.notifyObservers();
observerSubject.remove(observer2);
observerSubject.notifyObservers();
}
}
(7) 中介者模式
说明:定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。
优点
降低了对象之间的耦合性,使得对象易于独立地被复用。
将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展。
缺点:
当同事类太多时,中介者的职责将很大,它会变得复杂而庞大,以至于系统难以维护。
抽象中介者角色源码
package com.design;
import java.util.ArrayList;
import java.util.List;
public abstract class Mediator {
protected List<Colleague> colleagueList = new ArrayList<>();
public abstract void register(Colleague colleague);
public abstract void relay(Colleague colleague);
}
具体中介者角色源码
package com.design;
public class ConcreateMediator extends Mediator {
@Override
public void register(Colleague colleague) {
if(!colleagueList.contains(colleague)) {
colleagueList.add(colleague);
colleague.setMediator(this);
}
}
@Override
public void relay(Colleague colleague) {
for(Colleague colleague1 : colleagueList) {
if(!colleague.equals(colleague1)) {
colleague1.receive();
}
}
}
}
抽象同事类角色源码
package com.design;
public abstract class Colleague {
protected Mediator mediator;
public void setMediator(Mediator mediator) {
this.mediator = mediator;
}
public abstract void send();
public abstract void receive();
}
具体同事类角色源码
package com.design;
public class ConcreateColleague1 extends Colleague {
@Override
public void send() {
System.out.println("同事1 发送了消息 。。。");
mediator.relay(this);
}
@Override
public void receive() {
System.out.println("同事1 收到了消息...");
}
}
package com.design;
public class ConcreateColleague2 extends Colleague {
@Override
public void send() {
System.out.println("同事2 发送了消息 。。。");
mediator.relay(this);
}
@Override
public void receive() {
System.out.println("同事2 收到了消息...");
}
}
中介者执行源码
package com.design;
public class MediatorTest {
public static void main(String[] args) {
Mediator mediator = new ConcreateMediator();
Colleague colleague1 = new ConcreateColleague1();
Colleague colleague2 = new ConcreateColleague2();
mediator.register(colleague1);
mediator.register(colleague2);
colleague1.send();
colleague2.send();
}
}
网友评论