【第四章】行为型模式

观察者模式

定义:定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都得到通知并被自动更新。

角色:

Subject(目标 AllyControlCenter)可为接口或则抽象类

ConcreteSubject(具体目标)

Observer(观察者)可为接口或则抽象类

ConcreteObserver(具体观察者)

类图:

代码:

目标:

public abstract class AllyControlCenter {
​
    // 战队名称
    protected String allyName; 
    
    // 定义一个集合用于存储战具体观察者,(关联观察者)
    protected List<IObserver> players = new ArrayList<IObserver>(); 
​
    public void SetAllyName(String allyName) {
        this.allyName = allyName;
    }
​
    public String GetAllyName() {
        return this.allyName;
    }
​
    // 注册方法
    public void Join(IObserver obs) {
        System.out.println(obs.getName() + " 加入 " + this.allyName);
        players.add(obs);
    }
​
    // 注销方法
    public void Quit(IObserver obs) {
        System.out.println(obs.getName() + " 退出 " + this.allyName);
        players.remove(obs);
    }
​
    // 声明抽象通知方法
    public abstract void NotifyObserver(String name);
    
    public abstract void NotifyObserver1(String name);
​
}

具体目标:

public class ConcreteAllyControlCenter extends AllyControlCenter{
​
    // 重写通知方法
    @Override
    public void NotifyObserver(String name) {
        System.out.println(this.allyName + "紧急通知,队友 " + name + " 遭遇老6攻击而倒地!救救我!救救我!");
        // 遍历观察者集合,调用每一个盟友(自己除外)的支援方法
        for (Object obs : players) {
            if (!((IObserver) obs).getName().equals(name)) {
                ((IObserver) obs).Help();
            }
        }
    }
    
    // 重写通知方法
    @Override
    public void NotifyObserver1(String name) {
        System.out.println(this.allyName + "恭喜,队友 " + name + " 坚持与努力,成功登顶战神!");
        for (Object obs : players) {
            if (!((IObserver) obs).getName().equals(name)) {
                ((IObserver) obs).Seccess();
            }
        }
    }
​
    //构造方法
    public ConcreteAllyControlCenter(String allyName) {
        System.out.println(allyName + "战队组建成功!");
        System.out.println("---------------冲战神---------------");
        this.allyName = allyName;
    }
}

观察者:

public abstract class IObserver {
​
    protected String name;
    
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    // 声明支援盟友方法
    public abstract void Help(); 
​
    // 声明遭受攻击方法
    public abstract void BeAttacked(AllyControlCenter acc); 
    
    // 声明吃鸡方法
    public abstract void ChiJi(AllyControlCenter acc); 
    
    // 声明冲分成功方法
    public abstract void Seccess(); 
}

具体观察者:

public class Player extends IObserver{
​
    public Player(String name) {
        this.name = name;
    }
​
     //支援盟友方法的实现
    @Override
    public void Help() {
        System.out.println("坚持住," + this.name + "正开车来救你!");
    }
​
    
     //遭受攻击方法的实现,当遭受攻击时将调用战队控制中心类的通知方法
    @Override
    public void BeAttacked(AllyControlCenter acc) { //依赖目标类
        System.out.println(this.name + " 需要支援! ");
        acc.NotifyObserver(name); //调用目标类方法的通知方法
    }
​
    
     //冲分成功
    @Override
    public void Seccess() {
        System.out.println( this.name + " 发来贺电!");  
    }
​
    //成功恰鸡
    @Override
    public void ChiJi(AllyControlCenter acc) {
        System.out.println( this.name + " 吃鸡!");
        acc.NotifyObserver1(name);
        
    }
​
}

Client:

public class Client {
​
    public static void main(String[] args) {
        // 定义观察目标对象
        AllyControlCenter acc; //目标类
        acc = new ConcreteAllyControlCenter(" 吃鸡小分队 "); //具体目标类
​
        // 定义四个观察者对象
        IObserver player1, player2, player3, player4;
​
        player1 = new Player(" 199000214 ");
        acc.Join(player1);//目标类方法
​
        player2 = new Player(" 苟分不打架 ");
        acc.Join(player2);
​
        player3 = new Player(" 先打队友,别补我 ");
        acc.Join(player3);
​
        player4 = new Player(" 求求ya ");
        acc.Join(player4);
​
        // 某成员遭受攻击(观察者重写的方法)
        player3.BeAttacked(acc);
        
        //某成员成功吃鸡
        player1.ChiJi(acc);
    }
}

结果:

吃鸡小分队 战队组建成功!

---------------冲战神---------------

199000214 加入 吃鸡小分队

苟分不打架 加入 吃鸡小分队

先打队友,别补我 加入 吃鸡小分队

求求ya 加入 吃鸡小分队

先打队友,别补我 需要支援!

吃鸡小分队 紧急通知,队友 先打队友,别补我 遭遇老6攻击而倒地!救救我!救救我!

坚持住, 199000214 正开车来救你!

坚持住, 苟分不打架 正开车来救你! 坚持住,

求求ya 正开车来救你!

199000214 吃鸡!

吃鸡小分队 恭喜,队友 199000214 坚持与努力,成功登顶战神!

苟分不打架 发来贺电!

先打队友,别补我 发来贺电!

求求ya 发来贺电!

优点:

可以实现表示层和数据逻辑层的分离

在观察目标和观察者之间建立一个抽象的耦合

支持广播通信

符合开闭原则

缺点:

(1)将所有的观察者都通知到会花费很多时间

(2)如果存在循环依赖时可能导致系统崩溃

(3)没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而只是知道观察目标发生了变化

适用环境:

(1)一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立的对象中使它们可以各自独立地改变和复用 (2)一个对象的改变将导致一个或多个其他对象发生改变,且并不知道具体有多少对象将发生改变,也不知道这些对象是谁 (3)需要在系统中创建一个触发链

命令模式

定义: 将一个请求封装为一个对象,从而让你可以用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销的操作。

角色:

Command(抽象命令类)

XxxCommand(具体命令类) 关联 XxxClass

FunctionButton(调用者 ) 关联 Command

XxxClass(接收者)

类图:

代码:

抽象命令类

public abstract class Command {
​
    public abstract void Execute();
}

具体命令类

// 退出命令
public class ExitCommand extends Command{
​
    private SystemExitClass seObj; //关联接收者
​
    public ExitCommand(){ //构造方法中注入(关联关系)
        seObj = new SystemExitClass();
    }
​
    public void Execute(){
        seObj.Exit(); //接收者方法
    }
}
// 帮助命令
public class HelpCommand extends Command {
​
    private DisplayHelpClass hcObj;
​
    public HelpCommand()
    {
        hcObj = new DisplayHelpClass();
    }
​
    public void Execute()
    {
        hcObj.Display();
    }
}

调用者

public class FunctionButton {
​
    private Command command;
​
        //set注入
       public void setCommand(Command command) {
            this.command = command;
        }
        //业务方法,调用命令类的方法
       public void Click(){
            System.out.println("单击功能键, 正在执行功能...!");
            command.Execute();   
        }
}

接收者

//执行退出命令的功能
public class SystemExitClass {
​
    public void Exit(){
        System.out.println("功能执行完毕:已退出系统!");
    }
}
//执行帮助命令的功能
public class DisplayHelpClass {
​
    public void Display() {
        System.out.println("功能执行完毕:显示帮助文档!");
    }
}

Client

public class Client {
​
    public static void command(String flog) throws Exception {
        FunctionButton fb = new FunctionButton();
        
        Command command1 = new HelpCommand();
        Command command2 = new ExitCommand();
        //设置命令对象
        if (flog.equals("1")) {
              fb.setCommand(command1);
              fb.Click();
        }else if (flog.equals("2")) {
             fb.setCommand(command2);
                fb.Click();
        }else {
            throw new Exception("输入指令有误,请重新输入!");
        }
    }
    
    public static void main(String[] args) {
        
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入功能--->");
        System.out.println("显示帮助文档请输入 1;退出系统请输入 2");
        String str = sc.next();
        try {
            command(str);
        } catch (Exception e) {
            e.printStackTrace();
        }  
    }
}

结果:

请输入功能---> 显示帮助文档请输入 1;退出系统请输入 2 1 //键盘输入 单击功能键, 正在执行功能...! 功能执行完毕:显示帮助文档!

优点:

(1)降低了系统的耦合度 (2)新的命令可以很容易地加入到系统中,符合开闭原则 (3)为请求的撤销(Undo)和恢复(Redo)操作提供了一种设计和实现方案

缺点:

(1)使用命令模式可能会导致某些系统有过多的具体命令类(针对每一个对请求接收者的调用操作都需要设计一个具体命令类)

适用环境

(1)系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互

(2)系统需要在不同的时间指定请求、将请求排队和执行请求

(3)系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作

(4)系统需要将一组操作组合在一起形成宏命令

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值