java设计模式之行为型模式(11种)

行为型模式

行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。

行为型模式分为类行为模式和对象型模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或者聚合关系比继承关系耦合度低,满足合成复用原则 ,所以对象行为模式比类行为模式具有更大的灵活性。

分为:模板方法模式、策略模式、命令模式、职责链模式、状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式、解释器模式。(除了模板方法模式和解释器模式是类行为型模式,其他的全部属于对象行为型模式。)

模板方法模式



抽象类:定义模板方法和抽象方法。为防止恶意操作,一般模板方法都加上 final 关键词。

java 复制代码
public abstract class AbstractClass {
    // 模板方法定义
    public final void cookProcess() {
        pourOil();
        heatOil();
        pourVegetable();
        pourSauce();
        fry();
    }
    // 第一步:倒油是一样的,直接实现
    public void pourOil() {
        System.out.println("倒油");
    }
    // 第二步:热油是一样的,直接实现
    public void heatOil() {
        System.out.println("热油");
    }
    // 第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心),抽象方法
    public abstract void pourVegetable();
    // 第四步:倒调味料是不一样,抽象方法
    public abstract void pourSauce();
    // 第五步:翻炒是一样的,直接实现
    public void fry() {
        System.out.println("炒啊炒啊炒到熟啊");
    }
}

具体子类:实现模板方法中的抽象方法和钩子方法

java 复制代码
/**
 * 炒包菜类
 */
public class ConcreteClass_BaoCai extends AbstractClass {
    public void pourVegetable() {
        System.out.println("下锅的蔬菜是包菜");
    }
    public void pourSauce() {
        System.out.println("下锅的酱料是辣椒");
    }
}

/**
 * 炒菜心类
 */
public class ConcreteClass_CaiXin extends AbstractClass {
    public void pourVegetable() {
        System.out.println("下锅的蔬菜是菜心");
    }
    public void pourSauce() {
        System.out.println("下锅的酱料是蒜蓉");
    }
}

测试类

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 炒包菜
        // 创建对象
        ConcreteClass_BaoCai baoCai = new ConcreteClass_BaoCai();
        // 调用炒菜的功能
        baoCai.cookProcess();
    }
}

JDK源码

InputStream 类中使用了模板方法模式。在 InputStream 类中定义了多个 read() 方法,如下:

java 复制代码
public abstract class InputStream implements Closeable {
    // 抽象方法,要求子类必须重写
    public abstract int read() throws IOException;

    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }

    public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        int c = read(); // 调用了无参的read方法,该方法是每次读取一个字节数据
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read(); // 调用了无参的read方法,该方法是每次读取一个字节数据
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }
}

无参的 read() 方法是抽象方法,要求子类必须实现。而 read(byte b[]) 方法调用了 read(byte b[], int off, int len) 方法,所以在此处重点看的方法是带三个参数的方法。在该方法中,可以看到调用了无参的抽象的 read() 方法。

策略模式


抽象策略类:百货公司所有促销活动共同的接口。

java 复制代码
public interface Strategy {
    void show();
}

具体策略角色:每个节日具体的促销活动。

java 复制代码
/**
 * 为春节准备的促销活动A
 */
public class StrategyA implements Strategy {
    public void show() {
        System.out.println("买一送一");
    }
}
/**
 * 为中秋准备的促销活动B
 */
public class StrategyB implements Strategy {
    public void show() {
        System.out.println("满200元减50元");
    }
}
/**
 * 为圣诞准备的促销活动C
 */
public class StrategyC implements Strategy {
    public void show() {
        System.out.println("满1000元加一元换购任意200元以下商品");
    }
}

环境角色:用于连接上下文,即把促销活动推销给客户,这里可以理解为销售员。

java 复制代码
@Data
@AllA
public class SalesMan {
    // 聚合策略类对象
    private Strategy strategy;
    public SalesMan(Strategy strategy) {
        this.strategy = strategy;
    }
    // 由促销员展示促销活动给用户
    public void salesManShow() {
        strategy.show();
    }
}

测试类:

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 春节来了,使用春节促销活动
        SalesMan salesMan = new SalesMan(new StrategyA());
        // 展示促销活动
        salesMan.salesManShow();
        // 中秋节到了,使用中秋节的促销活动
        salesMan.setStrategy(new StrategyB());
        // 展示促销活动
        salesMan.salesManShow();
        // 圣诞节到了,使用圣诞节的促销活动
        salesMan.setStrategy(new StrategyC());
        // 展示促销活动
        salesMan.salesManShow();
    }
}




上面在调用 Arrays 的 sort 方法时,第二个参数传递的是 Comparator 接口的子实现类对象。所以 Comparator 充当的是抽象策略角色,而具体的子实现类充当的是具体策略角色。环境角色类 Arrays 应该持有抽象策略的引用来调用。那么,Arrays 类的 sort 方法到底有没有使用 Comparator 子实现类中的 compare() 方法吗?让我们继续查看 TimSort 类的 sort() 方法,代码如下:

java 复制代码
class TimSort<T> {
    static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
                         T[] work, int workBase, int workLen) {
        assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;

        int nRemaining  = hi - lo;
        if (nRemaining < 2)
            return;  // Arrays of size 0 and 1 are always sorted

        // If array is small, do a "mini-TimSort" with no merges
        if (nRemaining < MIN_MERGE) {
            int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
            binarySort(a, lo, hi, lo + initRunLen, c);
            return;
        }
        ...
    }   
        
    private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,Comparator<? super T> c) {
        assert lo < hi;
        int runHi = lo + 1;
        if (runHi == hi)
            return 1;

        // Find end of run, and reverse range if descending
        if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
                runHi++;
            reverseRange(a, lo, runHi);
        } else {                              // Ascending
            while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
                runHi++;
        }

        return runHi - lo;
    }
}

上面的代码中最终会跑到 countRunAndMakeAscending() 这个方法中。可以看见,只用了 compare 方法,所以在调用 Arrays.sort 方法只传具体 compare 重写方法的类对象就行,这也是 Comparator 接口中必须要子类实现的一个方法。

命令模式

将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分隔开,这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储,传递、调用、增加与管理。

抽象命令类:

java 复制代码
public interface Command {
    void execute();
}

具体命令类:

java 复制代码
public class OrderCommand implements Command {
    // 持有接收者对象
    private SeniorChef receiver;
    private Order order;

    public OrderCommand(SeniorChef receiver, Order order) {
        this.receiver = receiver;
        this.order = order;
    }

    public void execute() {
        System.out.println(order.getDiningTable() + "桌的订单:");
        Map<String, Integer> foodDir = order.getFoodDir();
        Set<String> keys = foodDir.keySet();
        for (String foodName : keys) {
            receiver.makeFood(foodName, foodDir.get(foodName));
        }
        System.out.println(order.getDiningTable() + "桌的饭准备完毕!!!");
    }
}

/**
 * 订单类
 */
@Data
public class Order {
    // 餐桌号码
    private int diningTable;
    // 所下的餐品及份数
    private Map<String,Integer> foodDir = new HashMap<>();
}

接收者:资深大厨

java 复制代码
public class SeniorChef {
    public void makeFood(String name,int num) {
        System.out.println(num + "份" + name);
    }
}

请求者:服务员

java 复制代码
public class Waiter {
    // 持有多个命令对象
    private List<Command> commands = new ArrayList<>();
    public void setCommand(Command cmd) {
        // 将cmd对象存储到list集合中
        commands.add(cmd);
    }
    // 发起命令功能: 喊 订单来了
    public void orderUp() {
        System.out.println("美女服务员:大厨,新订单来了。。。。");
        for (Command command : commands) {
           if(command != null) {
               command.execute();
           }
        }
    }
}

测试类:

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 创建第一个订单对象
        Order order1 = new Order();
        order1.setDiningTable(1);
        order1.setFood("西红柿鸡蛋面",1);
        order1.setFood("小杯可乐",2);

        // 创建第二个订单对象
        Order order2 = new Order();
        order2.setDiningTable(2);
        order2.setFood("尖椒肉丝盖饭",1);
        order2.setFood("小杯雪碧",1);

        // 创建厨师对象
        SeniorChef receiver = new SeniorChef();
        // 创建命令对象
        OrderCommand cmd1 = new OrderCommand(receiver, order1);
        OrderCommand cmd2 = new OrderCommand(receiver, order2);

        // 创建调用者(服务员对象)
        Waiter invoker = new Waiter();
        invoker.setCommand(cmd1);
        invoker.setCommand(cmd2);

        // 让服务员发起命令
        invoker.orderUp();
    }
}

JDK源码

Runable 是一个典型命令模式,Runnable 担当命令的角色,Thread 充当的是调用者,start 方法就是其执行方法

java 复制代码
// 命令接口(抽象命令角色)
public interface Runnable {
	public abstract void run();
}

// 调用者
public class Thread implements Runnable {
    private Runnable target;
    
    public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
            }
        }
    }
    
    private native void start0();
}
java 复制代码
/**
 * jdk Runnable 命令模式
 * TurnOffThread:属于具体命令
 */
public class TurnOffThread implements Runnable{
     private Receiver receiver;
    
     public TurnOffThread(Receiver receiver) {
     	this.receiver = receiver;
     }
     public void run() {
     	receiver.turnOFF();
     }
}
java 复制代码
/**
 * 测试类
 */
public class Demo {
     public static void main(String[] args) {
         Receiver receiver = new Receiver();
         TurnOffThread turnOffThread = new TurnOffThread(receiver);
         Thread thread = new Thread(turnOffThread);
         thread.start();
     }
}

职责链模式



请假条类:

java 复制代码
@Getter
public class LeaveRequest {
    // 姓名
    private String name;
    // 请假天数
    private int num;
    // 请假内容
    private String content;

    public LeaveRequest(String name, int num, String content) {
        this.name = name;
        this.num = num;
        this.content = content;
    }
}

抽象处理者:

java 复制代码
public abstract class Handler {
    protected final static int NUM_ONE = 1;
    protected final static int NUM_THREE = 3;
    protected final static int NUM_SEVEN = 7;
    // 该领导处理的请求天数区间
    private int numStart;
    private int numEnd;
    // 声明后续者(声明上级领导)
    private Handler nextHandler;

    public Handler(int numStart) {
        this.numStart = numStart;
    }

    public Handler(int numStart, int numEnd) {
        this.numStart = numStart;
        this.numEnd = numEnd;
    }

    // 设置上级领导对象
    public void setNextHandler(Handler nextHandler) {
        this.nextHandler = nextHandler;
    }

    // 各级领导处理请求条的方法
    protected abstract void handleLeave(LeaveRequest leave);

    // 提交请求条
    public final void submit(LeaveRequest leave) {
        // 该领导进行审批
        this.handleLeave(leave);
        if (this.nextHandler != null && leave.getNum() > this.numEnd) {
            // 提交给上级领导进行审批
            this.nextHandler.submit(leave);
        } else {
            System.out.println("流程结束!");
        }
    }
}

具体处理者:小组长、部门经理、总经理

java 复制代码
/**
 * 小组长类,处理1天的假条
 */
public class GroupLeader extends Handler {

    public GroupLeader() {
        super(0, Handler.NUM_ONE);
    }

    protected void handleLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("小组长审批:同意");
    }
}

/**
 * 部门经理类,处理1~3天的假条
 */
public class Manager extends Handler {

    public Manager() {
        super(Handler.NUM_ONE, Handler.NUM_THREE);
    }

    protected void handleLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("部门经理审批:同意");
    }
}

/**
 * 经理类,处理3-7天的假条
 */
public class GeneralManager extends Handler {

    public GeneralManager() {
        super(Handler.NUM_THREE, Handler.NUM_SEVEN);
    }

    protected void handleLeave(LeaveRequest leave) {
        System.out.println(leave.getName() + "请假" + leave.getNum() + "天," + leave.getContent() + "。");
        System.out.println("总经理审批:同意");
    }
}

测试类:

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 创建一个请假条对象
        LeaveRequest leave = new LeaveRequest("小明", 7, "身体不适");
        // 创建各级领导对象
        GroupLeader groupLeader = new GroupLeader(); // 小组长
        Manager manager = new Manager(); // 部门经理
        GeneralManager generalManager = new GeneralManager(); // 总经理
        // 设置处理者链
        groupLeader.setNextHandler(manager);
        manager.setNextHandler(generalManager);
        // 小明提交请假申请
        groupLeader.submit(leave);
    }
}



模拟实现具体过滤器:

java 复制代码
public class FirstFilter implements Filter {
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        System.out.println("过滤器1 前置处理");
        // 先执行所有request再倒序执行所有response
        chain.doFilter(request, response);
        System.out.println("过滤器1 后置处理");
    }
}

public class SecondFilter  implements Filter {
    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        System.out.println("过滤器2 前置处理");
        // 先执行所有request再倒序执行所有response
        chain.doFilter(request, response);
        System.out.println("过滤器2 后置处理");
    }
}

模拟实现过滤器链 FilterChain:

java 复制代码
public class FilterChain {
    private List<Filter> filters = new ArrayList<>();
    private int index = 0;
    // 链式调用
    public FilterChain addFilter(Filter filter) {
        this.filters.add(filter);
        return this;
    }
  	// 过滤操作
    public void doFilter(Request request, Response response) {
        if (index == filters.size()) {
            return;
        }
        Filter filter = filters.get(index);
        index++;
        filter.doFilter(request, response, this);
    }
}

测试类

java 复制代码
public class Client {
    public static void main(String[] args) {
        Request  req = null;
        Response res = null ;

        FilterChain filterChain = new FilterChain();
        filterChain.addFilter(new FirstFilter()).addFilter(new SecondFilter());
        filterChain.doFilter(req,res);
    }
}

状态模式

java 复制代码
/**
 * 电梯接口
 */
public interface ILift {
    // 定义四个电梯状态的常量
    int OPENING_STATE = 1;
    int CLOSING_STATE = 2;
    int RUNNING_STATE = 3;
    int STOPPING_STATE = 4;
    // 设置电梯状态的功能
    void setState(int state);
    // 电梯操作功能
    void open();
    void close();
    void run();
    void stop();
}
java 复制代码
/**
 * 电梯类(ILift的子实现类)
 */
public class Lift implements ILift {
    // 声明一个记录当前电梯的状态
    private int state;

    public void setState(int state) {
        this.state = state;
    }

    public void open() {
        switch (state) {
            case OPENING_STATE:
                // 什么事都不做
                break;
            case CLOSING_STATE:
                System.out.println("电梯打开了...");
                // 设置当前电梯状态为开启状态
                setState(OPENING_STATE);
                break;
            case STOPPING_STATE:
                System.out.println("电梯打开了...");
                // 设置当前电梯状态为开启状态
                setState(OPENING_STATE);
                break;
            case RUNNING_STATE:
                // 什么事都不做
                break;
        }
    }

    public void close() {
        switch (this.state) {
            case OPENING_STATE:
                System.out.println("电梯关门了。。。");//只有开门状态可以关闭电梯门,可以对应电梯状态表来看
                this.setState(CLOSING_STATE);//关门之后电梯就是关闭状态了
                break;
            case CLOSING_STATE:
                //do nothing //已经是关门状态,不能关门
                break;
            case RUNNING_STATE:
                //do nothing //运行时电梯门是关着的,不能关门
                break;
            case STOPPING_STATE:
                //do nothing //停止时电梯也是关着的,不能关门
                break;
        }
    }

    public void run() {
        switch (this.state) {
            case OPENING_STATE://电梯不能开着门就走
                //do nothing
                break;
            case CLOSING_STATE://门关了,可以运行了
                System.out.println("电梯开始运行了。。。");
                this.setState(RUNNING_STATE);//现在是运行状态
                break;
            case RUNNING_STATE:
                //do nothing 已经是运行状态了
                break;
            case STOPPING_STATE:
                System.out.println("电梯开始运行了。。。");
                this.setState(RUNNING_STATE);
                break;
        }
    }

    public void stop() {
        switch (this.state) {
            case OPENING_STATE: //开门的电梯已经是是停止的了(正常情况下)
                //do nothing
                break;
            case CLOSING_STATE://关门时才可以停止
                System.out.println("电梯停止了。。。");
                this.setState(STOPPING_STATE);
                break;
            case RUNNING_STATE://运行时当然可以停止了
                System.out.println("电梯停止了。。。");
                this.setState(STOPPING_STATE);
                break;
            case STOPPING_STATE:
                //do nothing
                break;
        }
    }
}
java 复制代码
public class Client {
    public static void main(String[] args) {
        // 创建电梯对象
        Lift lift = new Lift();
        // 设置当前电梯的状态
        lift.setState(ILift.RUNNING_STATE);
        // 打开
        lift.open();
        lift.close();
        lift.run();
        lift.stop();
    }
}

对有状态的对象,把复杂的"判断逻辑"提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。


抽象状态类:

java 复制代码
public abstract class LiftState {
    // 声明环境角色类变量
    protected Context context;
    public void setContext(Context context) {
        this.context = context;
    }
    // 电梯开启操作
    public abstract void open();
    // 电梯关闭操作
    public abstract void close();
    // 电梯运行操作
    public abstract void run();
    // 电梯停止操作
    public abstract void stop();
}

具体状态类:电梯开门状态、电梯运行状态 、电梯停止状态、电梯关门状态

java 复制代码
/**
 * 电梯开启状态类
 */
public class OpeningState extends LiftState {
    // 当前状态要执行的方法
    public void open() {
        System.out.println("电梯开启。。。");
    }
    public void close() {
        // 修改状态
        super.context.setLiftState(Context.CLOSING_STATE);
        // 修改环境
        super.context.close();
    }
    public void run() {}
    public void stop() {}
}

/**
 * 电梯关闭状态类
 */
public class ClosingState extends LiftState {
    // 当前状态要执行的方法
    public void close() {
        System.out.println("电梯门关闭...");
    }
    // 关闭 -> 开启
    public void open() {
        super.context.setLiftState(Context.OPENING_STATE);
        super.context.open();
    }
    // 关闭 -> 运行
    public void run() {
        super.context.setLiftState(Context.RUNNING_STATE);
        super.context.run();
    }
    // 关闭 -> 停止
    public void stop() {
        super.context.setLiftState(Context.STOPPING_STATE);
        super.context.stop();
    }
}

/**
 * 电梯运行状态类
 */
public class RunningState extends LiftState {
    // 当前状态要执行的方法
    public void run() {
        System.out.println("电梯正在运行...");
    }
    // 运行时无法开门
    @Override
    public void open() {}
    // 运行时门是关的
    @Override
    public void close() {}
    // 运行 -> 停止
    @Override
    public void stop() {
        super.context.setLiftState(Context.STOPPING_STATE);
        super.context.stop();
    }
}

/**
 * 电梯停止状态类
 */
public class StoppingState extends LiftState {
    // 当前状态要执行的方法
    public void stop() {
        System.out.println("电梯停止了...");
    }
    // 停止 -> 开门(委托给ClosingState子类执行)
    public void open() {
        super.context.setLiftState(Context.OPENING_STATE);
        super.context.getLiftState().open();
    }
    // 停止 -> 关门(委托给ClosingState子类执行)
    public void close() {
        super.context.setLiftState(Context.CLOSING_STATE);
        super.context.getLiftState().close();
    }
    // 停止 -> 运行(委托给ClosingState子类执行)
    public void run() {
        super.context.setLiftState(Context.RUNNING_STATE);
        super.context.getLiftState().run();
    }
}

环境角色类:

java 复制代码
public class Context {
    // 定义对应状态对象的常量
    public final static OpeningState OPENING_STATE = new OpeningState();
    public final static ClosingState CLOSING_STATE = new ClosingState();
    public final static RunningState RUNNING_STATE = new RunningState();
    public final static StoppingState STOPPING_STATE = new StoppingState();

    // 定义一个当前电梯状态变量
    private LiftState liftState;
    public LiftState getLiftState() {
        return liftState;
    }

    // 设置当前状态对象
    public void setLiftState(LiftState liftState) {
        this.liftState = liftState;
        // 设置当前状态对象中的Context对象
        this.liftState.setContext(this);
    }

    public void open() {
        this.liftState.open();
    }

    public void close() {
        this.liftState.close();
    }

    public void run() {
        this.liftState.run();
    }

    public void stop() {
        this.liftState.stop();
    }
}

测试类

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 创建环境角色对象
        Context context = new Context();
        // 设置当前电梯装填
        context.setLiftState(new ClosingState());
        context.open();
        context.run();
        context.close();
        context.stop();
    }
}

观察者模式


抽象观察者:

java 复制代码
public interface Observer {
    void update(String message);
}

具体观察者:微信用户,实现了更新的方法

java 复制代码
public class WeiXinUser implements Observer {
    private String name;
    public WeiXinUser(String name) {
        this.name = name;
    }
    public void update(String message) {
        System.out.println(name + "-" + message);
    }
}

抽象主题角色:

java 复制代码
public interface Subject {
    // 添加订阅者(添加观察者对象)
    void attach(Observer observer);
    // 删除订阅者
    void detach(Observer observer);
    // 通知订阅者更新消息
    void notify(String message);
}

具体主题角色:微信公众号,里面存储了订阅该公众号的微信用户,并实现了抽象主题中的方法

java 复制代码
public class SubscriptionSubject implements Subject {
    // 定义一个集合,用来存储多个观察者对象
    private List<Observer> weiXinUserList = new ArrayList<>();

    public void attach(Observer observer) {
        weiXinUserList.add(observer);
    }

    public void detach(Observer observer) {
        weiXinUserList.remove(observer);
    }

    public void notify(String message) {
        for (Observer observer : weiXinUserList) {
            // 调用观察者对象中的update方法
            observer.update(message);
        }
    }
}

测试类:

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 1,创建公众号对象
        SubscriptionSubject subject = new SubscriptionSubject();
        // 2,订阅公众号
        subject.attach(new WeiXinUser("孙悟空"));
        subject.attach(new WeiXinUser("猪悟能"));
        subject.attach(new WeiXinUser("沙悟净"));
        // 3,公众号更新,发出消息给订阅者(观察者对象)
        subject.notify("传智黑马的专栏更新了!");
    }
}


警察抓小偷也可以使用观察者模式来实现,警察是观察者,小偷是被观察者

小偷是一个被观察者,所以需要继承 Observable 类:

java 复制代码
@Data
public class Thief extends Observable {
    private String name;

    public Thief(String name) {
        this.name = name;
    }

    public void steal() {
        System.out.println("小偷:我偷东西了,有没有人来抓我!!!");
        super.setChanged(); // changed  = true
        super.notifyObservers();
    }
}

警察是一个观察者,所以需要让其实现 Observer 接口:

java 复制代码
@Data
public class Policemen implements Observer {

    private String name;

    public Policemen(String name) {
        this.name = name;
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("警察:" + ((Thief) o).getName() + ",我已经盯你很久了!!!");
    }
}

客户端:

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 创建小偷对象
        Thief t = new Thief("隔壁老王");
        // 创建警察对象
        Policemen p = new Policemen("小李");
        // 让警察盯着小偷
        t.addObserver(p);
        // 小偷偷东西
        t.steal();
    }
}

中介者模式



抽象中介者类:

java 复制代码
public abstract class Mediator {
    public abstract void contact(String message, Person person);
}

抽象同事类:

java 复制代码
@AllArgsConstructor
public abstract class Person {
    protected String name;
    protected Mediator mediator;
}

具体同事类:房主、房客

java 复制代码
/**
 * 具体的同事角色类 - 房主
 */
public class HouseOwner extends Person {
    public HouseOwner(String name, Mediator mediator) {
        super(name, mediator);
    }
    // 和中介联系(沟通)
    public void contact(String message) {
        mediator.contact(message,this);
    }
    // 获取信息
    public void getMessage(String message) {
        System.out.println("房主" + name + "获取到的信息是:" + message);
    }
}

/**
 * 具体的同事角色类 - 房客
 */
public class Tenant extends Person {
    public Tenant(String name, Mediator mediator) {
        super(name, mediator);
    }
    // 和中介联系(沟通)
    public void contact(String message) {
        mediator.contact(message,this);
    }
    // 获取信息
    public void getMessage(String message) {
        System.out.println("租房者" + name + "获取到的信息是:" + message);
    }
}

具体中介者角色:中介机构

java 复制代码
@Data
public class MediatorStructure extends Mediator {
    // 聚合房主和房客对象
    private HouseOwner houseOwner;
    private Tenant tenant;

    public void contact(String message, Person person) {
        if (person == houseOwner) {
            tenant.getMessage(message);
        } else {
            houseOwner.getMessage(message);
        }
    }
}

测试类:

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 中介者对象
        MediatorStructure mediator = new MediatorStructure();
        // 租房者对象
        Tenant tenant = new Tenant("李四", mediator);
        // 房主对象
        HouseOwner houseOwner = new HouseOwner("张三", mediator);

        // 中介者要知道具体的房主和租房者
        mediator.setTenant(tenant);
        mediator.setHouseOwner(houseOwner);

        tenant.contact("我要租三室的房子!!!");
        houseOwner.contact("我这里有三室的房子,你要租吗?");
    }
}


迭代器模式


实体类:

java 复制代码
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private String name;
    private String number;
}

抽象迭代器角色:拥有 hasNext 和 next 方法

java 复制代码
public interface StudentIterator {
    // 判断是否还有元素
    boolean hasNext();
    // 获取下一个元素
    Student next();
}

具体迭代器角色:重写抽象方法

java 复制代码
public class StudentIteratorImpl implements StudentIterator {
    private final List<Student> list;
    private int position = 0; // 记录遍历时的位置

    public StudentIteratorImpl(List<Student> list) {
        this.list = list;
    }

    public boolean hasNext() {
        return position < list.size();
    }

    public Student next() {
        // 从集合中获取指定位置的元素
        return list.get(position++);
    }
}

抽象聚合角色:包含添加元素,删除元素,获取迭代器对象的方法

java 复制代码
public interface StudentAggregate {
    // 添加学生功能
    void addStudent(Student stu);
    // 删除学生功能
    void removeStudent(Student stu);
    // 获取迭代器对象功能
    StudentIterator getStudentIterator();
}

具体聚合角色:重写抽象方法

java 复制代码
public class StudentAggregateImpl implements StudentAggregate {
    private List<Student> list = new ArrayList<>();

    public void addStudent(Student stu) {
        list.add(stu);
    }

    public void removeStudent(Student stu) {
        list.remove(stu);
    }

    // 获取迭代器对象
    public StudentIterator getStudentIterator() {
        return new StudentIteratorImpl(list);
    }
}

测试类

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 创建聚合对象
        StudentAggregateImpl aggregate = new StudentAggregateImpl();
        // 添加元素
        aggregate.addStudent(new Student("张三", "001"));
        aggregate.addStudent(new Student("李四", "002"));
        aggregate.addStudent(new Student("王五", "003"));
        aggregate.addStudent(new Student("赵六", "004"));

        // 遍历聚合对象
        // 1,获取迭代器对象
        StudentIterator iterator = aggregate.getStudentIterator();
        // 2,遍历
        while (iterator.hasNext()) {
            // 3,获取元素
            Student student = iterator.next();
            System.out.println(student);
        }
    }
}


ArrayList具体实现

java 复制代码
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    
    public Iterator<E> iterator() {
        return new Itr();
    }
    
    private class Itr implements Iterator<E> {
        int cursor;       // 下一个要返回元素的索引
        int lastRet = -1; // 上一个返回元素的索引
        int expectedModCount = modCount;

        Itr() {}
		
        //判断是否还有元素
        public boolean hasNext() {
            return cursor != size;
        }

        //获取下一个元素
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
        ...
}

访问者模式



抽象访问者类:给宠喂食

java 复制代码
public interface Person {
    // 喂食宠物猫
    void feed(Cat cat);
    // 喂食宠物狗
    void feed(Dog dog);
}

具体访问者角色:主人、其他人,都实现 Person 接口

java 复制代码
/**
 * 具体访问者角色类(自己)
 */
public class Owner implements Person {
    public void feed(Cat cat) {
        System.out.println("主人喂食猫");
    }
    public void feed(Dog dog) {
        System.out.println("主人喂食狗");
    }
}
/**
 *  具体访问者角色类(其他人)
 */
public class Someone implements Person {
    public void feed(Cat cat) {
        System.out.println("其他人喂食猫");
    }
    public void feed(Dog dog) {
        System.out.println("其他人喂食狗");
    }
}

抽象元素角色:被喂食的动物抽象类

java 复制代码
public interface Animal {
    // 接受访问者访问的功能
    void accept(Person person);
}

具体元素角色:狗、猫

java 复制代码
/**
 * 具体元素角色类(宠物狗)
 */
public class Dog implements Animal {
    public void accept(Person person) {
        person.feed(this); // 访问者给宠物狗喂食
        System.out.println("好好吃,汪汪汪。。。");
    }
}
/**
 * 具体元素角色类(宠物猫)
 */
public class Cat implements Animal {
    public void accept(Person person) {
        person.feed(this); // 访问者给宠物猫喂食
        System.out.println("好好吃,喵喵喵。。。");
    }
}

对象结构角色:此案例中是主人的家

java 复制代码
public class Home {
    // 声明一个集合对象,用来存储元素对象
    private List<Animal> nodeList = new ArrayList<>();
    // 添加元素功能
    public void add(Animal animal) {
        nodeList.add(animal);
    }
    public void action(Person person) {
        // 遍历集合,获取每一个元素,让访问者访问每一个元素
        for (Animal animal : nodeList) {
            animal.accept(person);
        }
    }
}

测试类

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 创建Home对象
        Home home = new Home();
        // 添加元素到Home对象中
        home.add(new Dog());
        home.add(new Cat());

        // 创建主人对象
        Owner owner = new Owner();
        // 让主人喂食所有的宠物
        home.action(owner);
    }
}


动态分派:通过方法的重写支持动态分派

java 复制代码
public class Animal {
    public void execute() {
        System.out.println("Animal");
    }
}

public class Dog extends Animal {
    @Override
    public void execute() {
        System.out.println("dog");
    }
}

public class Cat extends Animal {
     @Override
    public void execute() {
        System.out.println("cat");
    }
}

public class Client {
   	public static void main(String[] args) {
        Animal a = new Animal();
        a.execute();
      
        Animal d = new Dog();
        d.execute();
        
        Animal c = new Cat();
        c.execute();
    }
}

Java 编译器在编译时期并不总是知道哪些代码会被执行,因为编译器仅仅知道对象的静态类型,而不知道对象的真实类型;而方法的调用则是根据对象的真实类型,而不是静态类型。

静态分派:通过方法的重载支持静态分派

java 复制代码
public class Animal {}

public class Dog extends Animal {}

public class Cat extends Animal {}

public class Execute {
    public void execute(Animal a) {
        System.out.println("Animal");
    }
    public void execute(Dog d) {
        System.out.println("dog");
    }
    public void execute(Cat c) {
        System.out.println("cat");
    }
}

public class Client {
    public static void main(String[] args) {
        Animal a = new Animal();
        Animal a1 = new Dog();
        Animal a2 = new Cat();
				// 静态分派根据静态类型决定
        Execute exe = new Execute();
        exe.execute(a);
        exe.execute(a1);
        exe.execute(a2);
    }
}


java 复制代码
public class Animal {
    public void accept(Execute exe) {
        // 2.传递了this给Execute,根据静态类型进行方法重载实现静态分派
        exe.execute(this);
    }
}

public class Dog extends Animal {
    public void accept(Execute exe) {
        exe.execute(this);
    }
}

public class Cat extends Animal {
    public void accept(Execute exe) {
        exe.execute(this);
    }
}

public class Execute {
    public void execute(Animal a) {
        System.out.println("animal");
    }
    public void execute(Dog d) {
        System.out.println("dog");
    }
    public void execute(Cat c) {
        System.out.println("cat");
    }
}

public class Client {
    public static void main(String[] args) {
        Animal a = new Animal();
        Animal d = new Dog();
        Animal c = new Cat();

        Execute exe = new Execute();
      	// 1.exe传递给Animal类型的变量调用,方法重写实现动态分派
        a.accept(exe);
        d.accept(exe);
        c.accept(exe);
    }
}

备忘录模式



发起人角色:游戏角色

java 复制代码
/**
 * 游戏角色类(属于发起人角色)
 */
@Data
public class GameRole {
    private int vit; // 生命力
    private int atk; // 攻击力
    private int def; // 防御力
    // 初始化内部状态
    public void initState() {
        this.vit = 100;
        this.atk = 100;
        this.def = 100;
    }
    // 战斗
    public void fight() {
        this.vit = 0;
        this.atk = 0;
        this.def = 0;
    }
    // 保存角色状态功能
    public RoleStateMemento saveState() {
        return new RoleStateMemento(vit, atk, def);
    }
    // 恢复角色状态
    public void recoverState(RoleStateMemento roleStateMemento) {
        // 将备忘录对象中存储的状态赋值给当前对象的成员
        this.vit = roleStateMemento.getVit();
        this.atk = roleStateMemento.getAtk();
        this.def = roleStateMemento.getDef();
    }
    // 展示状态功能
    public void stateDisplay() {
        System.out.println("角色生命力:" + vit);
        System.out.println("角色攻击力:" + atk);
        System.out.println("角色防御力:" + def);
    }
}

备忘录角色:用于存储发起人的内部状态,因此拥有属性和发起人一样

java 复制代码
@Data
@AllArgsConstructor
public class RoleStateMemento {
    private int vit; // 生命力
    private int atk; // 攻击力
    private int def; // 防御力
}

管理者角色:用于管理备忘录角色

java 复制代码
@Data
public class RoleStateCaretaker {
    private RoleStateMemento roleStateMemento;
}

测试类:

java 复制代码
public class Client {
    public static void main(String[] args) {
        System.out.println("---------------大战boss前-----------------");
        // 创建游戏角色对象
        GameRole gameRole = new GameRole();
        gameRole.initState(); // 初始化状态操作
        gameRole.stateDisplay();
        // 将该游戏角色内部状态进行备份
        // 创建管理者对象
        RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();
        roleStateCaretaker.setRoleStateMemento(gameRole.saveState());

        System.out.println("---------------大战boss后-----------------");
        // 损耗严重
        gameRole.fight();
        gameRole.stateDisplay();

        System.out.println("---------------恢复之前的状态-----------------");
        gameRole.recoverState(roleStateCaretaker.getRoleStateMemento());
        gameRole.stateDisplay();
    }
}



备忘录接口:对外提供窄接口,标识接口,没有任何方法

java 复制代码
public interface Memento {
}

发起人角色:游戏角色,在内部定义备忘录内部类 RoleStateMemento(私有),对自己提供宽接口,但外部无法访问

java 复制代码
@Data
public class GameRole {
    private int vit; // 生命力
    private int atk; // 攻击力
    private int def; // 防御力
    // 初始化内部状态
    public void initState() {
        this.vit = 100;
        this.atk = 100;
        this.def = 100;
    }
    // 战斗
    public void fight() {
        this.vit = 0;
        this.atk = 0;
        this.def = 0;
    }
    // 保存角色状态功能
    public Memento saveState() {
        return new RoleStateMemento(vit, atk, def);
    }
    // 恢复角色状态
    public void recoverState(Memento memento) {
        RoleStateMemento roleStateMemento = (RoleStateMemento) memento;
        // 将备忘录对象中存储的状态赋值给当前对象的成员
        this.vit = roleStateMemento.getVit();
        this.atk = roleStateMemento.getAtk();
        this.def = roleStateMemento.getDef();
    }
    // 展示状态功能
    public void stateDisplay() {
        System.out.println("角色生命力:" + vit);
        System.out.println("角色攻击力:" + atk);
        System.out.println("角色防御力:" + def);
    }
    // 对发起者宽接口,对其他类窄接口
    @Data
    @AllArgsConstructor
    private static class RoleStateMemento implements Memento {
        private int vit; // 生命力
        private int atk; // 攻击力
        private int def; // 防御力
    }
}

管理者角色:这个类聚合的是 Memento 接口,只是个标识接口,因此该角色无法更改备忘录的内容

java 复制代码
@Data
public class RoleStateCaretaker {
    private Memento memento;
}

测试类:

java 复制代码
public class Client {
    public static void main(String[] args) {
        System.out.println("---------------大战boos前-----------------");
        // 创建游戏角色对象
        GameRole gameRole = new GameRole();
        gameRole.initState(); // 初始化状态操作
        gameRole.stateDisplay();
        // 将该游戏角色内部状态进行备份
        // 创建管理者对象
        RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker();
        roleStateCaretaker.setMemento(gameRole.saveState());

        System.out.println("---------------大战boos后-----------------");
        // 损耗严重
        gameRole.fight();
        gameRole.stateDisplay();

        System.out.println("---------------恢复之前的状态-----------------");
        gameRole.recoverState(roleStateCaretaker.getMemento());
        gameRole.stateDisplay();
    }
}

解释器模式


抽象表达式:

java 复制代码
public abstract class AbstractExpression {
    public abstract int interpret(Context context);
}

终结符表达式:变量表达式

java 复制代码
@AllArgsConstructor
public class Variable extends AbstractExpression {
    // 声明存储变量名的成员变量
    private String name;

    public int interpret(Context context) {
        // 直接返回变量的值
        return context.getValue(this);
    }

    @Override
    public String toString() {
        return name;
    }
}

非终结表达式:加法表达式、减法表达式

java 复制代码
/**
 * 加法表达式类
 */
@AllArgsConstructor
public class Plus extends AbstractExpression {
    // +号左边的表达式
    private AbstractExpression left;
    // +号右边的表达式
    private AbstractExpression right;
    @Override
    public int interpret(Context context) {
        // 将左边表达式的结果和右边表达式的结果进行相加
        return left.interpret(context) + right.interpret(context);
    }
    @Override
    public String toString() {
        return "(" + left.toString() + " + " + right.toString() + ")";
    }
}
/**
 * 减法表达式类
 */
@AllArgsConstructor
public class Minus extends AbstractExpression {
    // -号左边的表达式
    private AbstractExpression left;
    // -号右边的表达式
    private AbstractExpression right;
    @Override
    public int interpret(Context context) {
        // 将左边表达式的结果和右边表达式的结果进行相减
        return left.interpret(context) - right.interpret(context);
    }
    @Override
    public String toString() {
        return "(" + left.toString() + " - " + right.toString() + ")";
    }
}

环境角色类:

java 复制代码
public class Context {
    // 定义一个map集合,用来存储变量及对应的值
    private Map<Variable, Integer> map = new HashMap<>();
    // 添加变量的功能
    public void assign(Variable var, Integer value) {
        map.put(var, value);
    }
    // 根据变量获取对应的值
    public int getValue(Variable var) {
        return map.get(var);
    }
}

测试类:

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 创建环境对象
        Context context = new Context();
        // 创建多个变量对象
        Variable a = new Variable("a");
        Variable b = new Variable("b");
        Variable c = new Variable("c");
        Variable d = new Variable("d");

        // 将变量存储到环境对象中
        context.assign(a, 1);
        context.assign(b, 2);
        context.assign(c, 3);
        context.assign(d, 4);

        // 获取抽象语法树 a + b - c + d
        AbstractExpression expression = new Plus(a, new Minus(new Minus(b, c), d));

        //  解释(计算)
        int result = expression.interpret(context);
        System.out.println(expression + " = " + result);
    }
}


相关推荐
哪 吒2 小时前
最简单的设计模式,抽象工厂模式,是否属于过度设计?
设计模式·抽象工厂模式
Theodore_10222 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
冰帝海岸3 小时前
01-spring security认证笔记
java·笔记·spring
世间万物皆对象4 小时前
Spring Boot核心概念:日志管理
java·spring boot·单元测试
没书读了4 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
----云烟----4 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024064 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
小二·4 小时前
java基础面试题笔记(基础篇)
java·笔记·python
开心工作室_kaic5 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it5 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎