• 设计模式读书笔记3


    前两篇博客分别介绍了设计模式中的建造型模式和结构型模式,这次就来讲讲行为型模式。建造型模式和结构型模式分别规范了对象的构造与对象间的组合,而行为型模式的意义在于提供了对象间的通信方式。下面来看几种常见的行为型模式。

    责任链模型,目的是使请求发送者与接受者解耦,通俗的说,就是将多个可能的请求接受者放在一条链表上(责任链),而发送者完全不关心接受者的内部实现,甚至不关心到底是哪个对象响应了自己的请求,它只需要将自己的请求抛出,或者说发送请求到责任链上,责任链上的一系列对象便会判断是否对请求进行处理。这个模式适用于对同一请求可能会有多个对象进行处理的情况,具体使用哪个对象在运行时判断。下面看一份源码,实现了三种类型的日志记录器,通过判断请求级别是否相同来决定是否进行记录。

    public abstract class AbstractLogger {
       public static int INFO = 1;
       public static int DEBUG = 2;
       public static int ERROR = 3;
    
       protected int level;
    
       protected AbstractLogger nextLogger;
    
       public void setNextLogger(AbstractLogger nextLogger){
          this.nextLogger = nextLogger;
       }
    
       public void logMessage(int level, String message){
          if(this.level == level){
             write(message);
          }
          if(nextLogger !=null){
             nextLogger.logMessage(level, message);
          }
       }
    
       abstract protected void write(String message);
        
    }
    public class ConsoleLogger extends AbstractLogger {
    
       public ConsoleLogger(int level){
          this.level = level;
       }
    
       @Override
       protected void write(String message) {        
          System.out.println("Standard Console::Logger: " + message);
       }
    }
    
    public class ErrorLogger extends AbstractLogger {
    
       public ErrorLogger(int level){
          this.level = level;
       }
    
       @Override
       protected void write(String message) {        
          System.out.println("Error Console::Logger: " + message);
       }
    }
    
    public class FileLogger extends AbstractLogger {
    
       public FileLogger(int level){
          this.level = level;
       }
    
       @Override
       protected void write(String message) {        
          System.out.println("File::Logger: " + message);
       }
    }

     通过以上的数据结构便可以将三种日志记录器设置在一条链表上,对第一个结点使用 logMessage 函数就是把请求发送到责任链上,每个接受对象判断是否进行处理。

    命令模式是另一种让行为请求者和行为实现者解耦的方式,实现方式是将请求以命令的形式包裹在对象中,并传给调用对象。命令模式的核心在于实现三个角色:命令真正执行者、命令、调用者,将这三者分别实现后大大降低了行为请求与实现的耦合度,且可以很方便地添加新命令。例如要实现股票的买卖请求:

    public interface Order {
       void execute();
    }
    public class Stock {
        
       private String name = "ABC";
       private int quantity = 10;
    
       public void buy(){
          System.out.println("Stock [ Name: "+name+", 
             Quantity: " + quantity +" ] bought");
       }
       public void sell(){
          System.out.println("Stock [ Name: "+name+", 
             Quantity: " + quantity +" ] sold");
       }
    }
    public class BuyStock implements Order {
       private Stock abcStock;
    
       public BuyStock(Stock abcStock){
          this.abcStock = abcStock;
       }
    
       public void execute() {
          abcStock.buy();
       }
    }
    public class SellStock implements Order {
       private Stock abcStock;
    
       public SellStock(Stock abcStock){
          this.abcStock = abcStock;
       }
    
       public void execute() {
          abcStock.sell();
       }
    }
    public class Broker {
       private List<Order> orderList = new ArrayList<Order>(); 
    
       public void takeOrder(Order order){
          orderList.add(order);        
       }
    
       public void placeOrders(){
          for (Order order : orderList) {
             order.execute();
          }
          orderList.clear();
       }
    }
    public class CommandPatternDemo {
       public static void main(String[] args) {
          Stock abcStock = new Stock();
    
          BuyStock buyStockOrder = new BuyStock(abcStock);
          SellStock sellStockOrder = new SellStock(abcStock);
    
          Broker broker = new Broker();
          broker.takeOrder(buyStockOrder);
          broker.takeOrder(sellStockOrder);
    
          broker.placeOrders();
       }
    }

    上述代码中, Stock 类是命名的真正执行者,而 BuyStock 类和 SellStock 类分别实现了 Order 接口,承担了命令的角色, Broker 类是命令调用者,客户需要执行什么操作,只需将命令对象添加到调用者对象并让其执行即可。

    接着看看迭代器模式,即遍历一个聚合对象的方式,Java中的每个集合类都有非常成熟的迭代器来进行遍历操作,这里就给出自定义对象的迭代器模式。

    public interface Iterator {
       public boolean hasNext();
       public Object next();
    }
    public interface Container {
       public Iterator getIterator();
    }
    public class NameRepository implements Container {
       public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};
    
       @Override
       public Iterator getIterator() {
          return new NameIterator();
       }
    
       private class NameIterator implements Iterator {
    
          int index;
    
          @Override
          public boolean hasNext() {
             if(index < names.length){
                return true;
             }
             return false;
          }
    
          @Override
          public Object next() {
             if(this.hasNext()){
                return names[index++];
             }
             return null;
          }        
       }
    }

    这里用到了 java 中 private 内部类,仅在所属外部类中可见。一个迭代器类需要实现 hasNext 函数判断是否还有下一元素,以及 next 函数返回下一元素,而使用迭代器的集合类需要实现 getIterator 函数得到该集合的迭代器。这样一个迭代器模式就完成了。

    再来看备忘录模式,其保存一个对象当前的状态以便以后恢复对象,就像游戏中的恢复存档以及数据库的事务管理等,给用户提供了一种可以恢复状态的机制。一种好的备忘录模式需要实现信息封装,使得用户不需要关心状态的保存细节。Java中可建立三个类来实现备忘录模式:状态类(保存状态信息)、状态创建类(用于创建一个状态)、状态保存类(建立一个集合保存过往的状态)。示例代码如下:

    public class Memento {
       private String state;
    
       public Memento(String state){
          this.state = state;
       }
    
       public String getState(){
          return state;
       }    
    }
    public class Originator {
       private String state;
    
       public void setState(String state){
          this.state = state;
       }
    
       public String getState(){
          return state;
       }
    
       public Memento saveStateToMemento(){
          return new Memento(state);
       }
    
       public void getStateFromMemento(Memento Memento){
          state = Memento.getState();
       }
    }
    public class CareTaker {
       private List<Memento> mementoList = new ArrayList<Memento>();
    
       public void add(Memento state){
          mementoList.add(state);
       }
    
       public Memento get(int index){
          return mementoList.get(index);
       }
    }

    以上便是三种类的定义,需要保存状态时调用 Originator 类的 saveStateToMemento 函数并 add 到 CareTaker 对象的 ArrayList 中。

    接着看看模板模式,一种经常出现的设计模式,很多经常使用它的人甚至不觉得这算是一种“高大上”的设计模式。模板模式使用一个抽象类(模板)定义了执行它的方法的方式,它的子类可以按需要重写方法实现,说白了,就是规范了抽象类该怎么使用。其优点是可在不变部分的基础上进行扩展 ,且提取了公共代码,便于维护。示例代码:

    public abstract class Game {
       abstract void initialize();
       abstract void startPlay();
       abstract void endPlay();
    
       public final void play(){
    
          initialize();
    
          startPlay();
    
          endPlay();
       }
    }
    public class Football extends Game {
    
       @Override
       void endPlay() {
          System.out.println("Football Game Finished!");
       }
    
       @Override
       void initialize() {
          System.out.println("Football Game Initialized! Start playing.");
       }
    
       @Override
       void startPlay() {
          System.out.println("Football Game Started. Enjoy the game!");
       }
    }

    这里要强调的是模板类 play 函数前的 final 修饰符,该修饰符的含义是此函数不能被重写,保证了抽象类中不变的部分不可改变,防止子类恶意修改,这也是定义模板时的重要原则,即公共不可变部分用 final 修饰。这一点在我以前的编程经验中是从未想到过的,可见该设计模式具有很重要的意义。

    下面说说界面编程中经常出现的观察者模式,该模式描述的是对象间的一对多关系,即当一个对象被修改时,则会自动通知它的依赖对象。这一模式在GUI编程中经常出现,比如Qt的信号槽机制,Android中的Rxjava库。该模式提供的是一般性触发机制的方案。下面给出被观察者的源码(“一对多”关系中的“一”):

    public class Subject {
        
       private List<Observer> observers 
          = new ArrayList<Observer>();
       private int state;
    
       public int getState() {
          return state;
       }
    
       public void setState(int state) {
          this.state = state;
          notifyAllObservers();
       }
    
       public void attach(Observer observer){
          observers.add(observer);        
       }
    
       public void notifyAllObservers(){
          for (Observer observer : observers) {
             observer.update();
          }
       }     
    }

    给出了 attach 函数和 notifyAllObservers 函数后,观察者模式的原理就一目了然了,剩下的工作就是对不同的观察者实现 update 函数。

    最后再看一种经典的设计模式:MVC模式,即Model-View-Controller(模型-视图-控制器) 模式。这种模式经常在各个场合被提起,其意义在于很好地实现了应用程序各模块之间的解耦。Model代表存取数据的对象,View表示数据可视化对象,Controller负责Model和View之间的交互,使得数据与显示之间完全分离,这对于应用程序开发具有很大的意义。由于该模式十分常见,在此不给出示例源码。

    其他行为型模式比如空对象模式、状态模式、中介者模式等留到以后有机会再分析。总结一下行为型设计模式的核心思想:通过封装和解耦来实现对象间通信需求。

  • 相关阅读:
    继承人人前端笔试题
    【转】ASP.NET应用程序生命周期趣谈
    C#中正则表达式的高级应用
    使用C#导入导出数据到Excel
    Server.Transfer详细解释
    防止刷新重复post提交
    程序只运行一次的方法
    注释很全的抽象工厂(没用简单工厂优化)
    利用反射动态调用类成员C#
    编程经历的一些思考
  • 原文地址:https://www.cnblogs.com/tilmto-Jerry/p/8921279.html
Copyright © 2020-2023  润新知