Java笔记21

  • 行为型模式, 主要负责算法和对象间责任分配.
  • 通过使用对象组合, 行为型模型可以描述一组对象应该如何协作来完成一个整体对象.

责任链

  • 使得多个对象都有机会处理请求, 从而避免请求的发送者和接受者之间的耦合关系.
  • 将这些对象连成一条链, 并沿着这条链处理该请求, 知道有一个对象处理它位置
  • 责任链模式(Chain of Responsibility)是一种请求处理模式, 让多个处理器有机会处理该请求, 知道某个成功为止.
  • 责任链模式把多个处理器串成链, 让请求在链上传递.
public class HandlerChain {

  // 持有所有的handler
  private List<Handler> handlers = new ArrayList<>();
  
  public void addHandler(Handler handler) {
    this.handlers.add(handler);
  }

  public boolean process(Request request) {
    // 以此调用每个handler
    for (Handler handler : handlers) {
      Boolean r = handler.process(request);
      // 一旦出现结果, 便返回结果
      if (r != null) return r;
    }
    throw new RuntimeException();
  }
}
  • handler的添加顺序很重要
public class AHandler implements Handler {
    private Handler next;
    public void process(Request request) {
        if (!canProcess(request)) {
            // 手动交给下一个Handler处理:
            next.process(request);
        } else {
            ...
        }
    }
}
  • 可以让上一个处理器调用下一个处理器

  • 让每个处理器都处理Request的方法称为, 拦截器.

  • 目的不是找到某个handler处理掉request, 而是每个handler都做一些工作.

命令

  • 将一个请求封装成一个对象, 从而使你可以使用不同的参数, 对客户端的请求进行参数化.
  • 对请求排队或者记录请求日志, 以及支持可撤销的操作
  • 命令(Command)模式是指: 把请求封装成一个命令, 然后执行这个命令.

这就是命令模式的结构:

┌──────┐ ┌───────┐
│Client│─ ─ ─>│Command│
└──────┘ └───────┘
│ ┌──────────────┐
├─>│ CopyCommand │
│ ├──────────────┤
│ │editor.copy() │─ ┐
│ └──────────────┘
│ │ ┌────────────┐
│ ┌──────────────┐ ─>│ TextEditor │
└─>│ PasteCommand │ │ └────────────┘
├──────────────┤
│editor.paste()│─ ┘
└──────────────┘

解释器

  • 给定一个语言, 定义它的文法的一种表示, 并定义一个解释器, 这个解释器使用该表示来解释语言中的句子.
  • 解释器模式(Interpreter)是一种针对特定问题设计的解决方法.

  • 把正则表达式解析为语法树, 然后再匹配指定的字符串, 就需要一个解析器.

  • 当我们使用JDBC时, 执行的SQL语句虽然是字符串, 但最终需要数据库服务器的SQL解释器来把SQL"翻译"成数据库服务器能执行的代码, 这个执行引擎也非常复杂, 但对于使用者来说, 仅仅需要写出SQL字符即可.

  public static void main(String[] args) {
    log("[{}] start {} at {}", LocalTime.now().withNano(0), "engine", LocalDate.now());
  }
  static void log (String format, Object... args) {
    int len = format.length();
    int argIndex = 0;
    char last = '';
    StringBuilder sb = new StringBuilder(len + 20);
    for (int i = 0; i < len; i++) {
      char now = format.charAt(i);
      if (last == '{' && now == '}') {
        sb.deleteCharAt(sb.length() - 1);
        sb.append(args[argIndex]);
        argIndex++;
      } else {
        sb.append(now);
      }
      last = now;
    }
    System.out.println(sb.toString());
  }

迭代器

  • 提供一种方法顺序访问一个聚合对象中的各个元素, 而又不需要暴露该对象的内部表示
  • 迭代器(Iterator).

List<String> list = ...
for (Iterator<String> it = list.iterator(); it.hasNext(); ) {
    String s = it.next();
}

// 自我定义反向迭代器
public class ReverseArrayCollection<T> implements Iterable<T> {

  private  T[] array;

  @SafeVarargs
  public ReverseArrayCollection(T... objs) {
    this.array = Arrays.copyOfRange(objs, 0, objs.length);
  }

  @Override
  public Iterator<T> iterator() {
    return null;
  }

  class ReverseIterator implements Iterator<T> {

    // 索引位置
    private int index;

    public ReverseIterator() {
      // 初始化的时候, 让索引指向数组的末尾
      this.index = ReverseArrayCollection.this.array.length;
    }

    @Override
    public boolean hasNext() {
      // 索引>0, 可以继续向下移动
      return index > 0;
    }

    @Override
    public T next() {
      index--;
      return array[index];
    }

  }
}

中介

  • 用一个中介对象来封装一系列的对象交互. 中介者使各个对象不需要显式地相互引用, 从而让耦合松散, 而且可以独立地改变它们之间的交互
  • 中介者模式(Mediator), 又称为调停者模式, 目的是把多方会谈, 变成双方会谈, 从而实现多方的松耦合.

public class Main {
  public static void main(String[] args) {
    new OrderFrame("Hamburger", "Nugget", "Chip", "Coffee");
  }
}

/**
 * InnerMain
 */
class OrderFrame extends JFrame {
  /**
   *
   */
  private static final long serialVersionUID = 2665832664109930397L;

  public OrderFrame(String... names) {
    setTitle("Order");
    setSize(460, 200);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    Container c = getContentPane();
    c.setLayout(new FlowLayout(
      FlowLayout.LEADING, 20, 20
    ));
    c.add(new JLabel("Use Mediator Pattern"));

    List<JCheckBox> checkBoxList = addCheckBox(names);
    JButton selectAll = addButton("Select All");
    JButton selectNone = addButton("Select None");
    selectNone.setEnabled(false);
    JButton selectInverse = addButton("Inverse Select");

    new Mediator(checkBoxList, selectAll, selectNone, selectInverse);
    setVisible(true);
  }

  private List<JCheckBox> addCheckBox(String... names) {
    JPanel panel = new JPanel();
    panel.add(new JLabel("Menu: "));
    List<JCheckBox> list = new ArrayList<>();
    for (String name : names) {
      JCheckBox checkBox = new JCheckBox(name);
      list.add(checkBox);
      panel.add(checkBox);
    }
    getContentPane().add(panel);
    return list;
  }

  private JButton addButton(String label) {
    JButton button = new JButton(label);
    getContentPane().add(button);
    return button;
  }
}


public class Mediator {
  // 引入UI组件
  private List<JCheckBox> checkBoxList;
  private JButton selectAll;
  private JButton selectNone;
  private JButton selectInverse;

  public Mediator(List<JCheckBox> checkBoxList, JButton selectAll, JButton selectNone, JButton selectInverse) {
    this.checkBoxList = checkBoxList;
    this.selectAll = selectAll;
    this.selectNone = selectNone;
    this.selectInverse = selectInverse;

    // 绑定事件
    this.checkBoxList.forEach(checkBox -> {
      checkBox.addChangeListener(this::onCheckBoxChanged);
    });
    this.selectAll.addActionListener(this::onSelectAllClicked);
    this.selectNone.addActionListener(this::onSelectNoneClicked);
    this.selectInverse.addActionListener(this::onSelectInverseClicked);

  }

  // 当checkbox有变化时
  public void onCheckBoxChanged(ChangeEvent event) {
    boolean allChecked = true;
    boolean allUnchecked = true;
    for (JCheckBox checkBox: checkBoxList) {
      if (checkBox.isSelected()) {
        allUnchecked = false;
      } else {
        allChecked = false;
      }
    }
    selectAll.setEnabled(!allChecked);
    selectNone.setEnabled(!allUnchecked);
  }

  // 点击select all
  public void onSelectAllClicked(ActionEvent event) {
    checkBoxList.forEach(checkBox -> checkBox.setSelected(true));
    selectAll.setEnabled(false);
    selectNone.setEnabled(true);
  }

  // 当点击select none
  public void onSelectNoneClicked(ActionEvent event) {
    checkBoxList.forEach(checkBox -> checkBox.setSelected(false));
    selectAll.setEnabled(true);
    selectNone.setEnabled(false);
  }

  // 当点击select inverse
  public void onSelectInverseClicked(ActionEvent event) {
    checkBoxList.forEach(checkBox -> checkBox.setSelected(!checkBox.isSelected()));
    onCheckBoxChanged(null);
  }
}
  • 使用Mediator模式后, 我们可以得到以下好处

    • 各个UI组件互不引用, 这样就减少了组件之间的耦合关系
    • Mediator用于当一个组件发生状态变化时, 根据当前所有组件的状态决定更新某些组件.
    • 如果新增一个UI组件, 我们只需要修改Mediator更新状态的逻辑, 现有的其他UI组件不变化.
  • Mediator模式常用在有众多交互组件的UI上.

  • 为了简化UI程序, MVC模式以及MVVM模式都可以看作是Mediator模式的扩展.

  • 中介模式就是引入一个中介对象, 把多边关系变成多个双边关系

备忘录

在不破坏封闭性的前提下, 捕获一个对象的内部状态, 并在该对象之外保存这个状态.

  • 备忘录模式(Memento): 主要是用于捕获一个对象的内部状态, 以便在将来的某个时刻恢复此状态

  • 标准的备忘录有几中角色:

    • Memento: 存储的内部状态
    • Originator: 创建一个备忘录并设置其状态
    • Caretaker: 负责保存备忘录

观察者

定义对象间的一种一对多的依赖关系, 当一个对象的状态发生改变时, 所有依赖它的对象都得到通知并被自动更新

  • 观察者模式(Observer)又称为发布-订阅模式(Publish-Subscribe Pub/Sub). 是一种通知机制, 让发送通知的一方(被观察方)和接收通知的一方(观察者)能彼此分离, 互不影响
public class Store {

  private List<ProductObserver> observers = new ArrayList<>();
  private Map<String, Product> products = new HashMap<>();

  // 注册观察者
  public void addObsever(ProductObserver observer) {
    this.observers.add(observer);
  }

  // 取消注册
  public void removeObserver(ProductObserver observer) {
    this.observers.remove(observer);
  }

  public void addNewProduct(String name, double price) {
    Product p = new Product(name, prize);
    products.put(p.getName(), p);

    // 通知观察者
    observers.forEach(o -> o.onPublished(p));
  }

  public void setProductPrice(String name, double price) {
    Product p = products.get(name);
    p.setPrice(price);

    // 通知观察者
    observers.forEach(o -> o.onPriceChanged(p));
  }
}
  • 可以匿名注册观察者
    store.addObserver(new ProductObserver() {
      public void onPublised(Product product) {
        System.out.println("[Log] on product published: " + product); 
      }
      public void onPriceChanged(Product product) {
        System.out.println("[Log] on product price changed: " + product);
      }
    });
  • 也可以把被观察者抽象出接口
public interface  ProductObservable {
  void addObserver(ProductObserver observer);
  void removeObserver(ProductObserver observer);
}
  • 也可以用把通知变成一个Event对象, 从而不再有多种方法通知
interface ProductObserver {

  void onEvent(ProductEvent event);
}
  • 可以异步执行任务
    observers.forEach(o -> new Thread() {
      @Override
      public void run() {
        o.onPublished(p);
      }
    }.start());

状态

允许一个对下个在其内部状态改变时, 改变它的行为. 对象看起来似乎修改了它的类

  • 状态模式(State)经常用在带有状态的对象中.

  • 可以定一个enum就可以表示不同的状态. 但不同的状态需要对应不同的行为.

  • 状态模式的目的是为了让一搭串的if...else...的逻辑拆分到不同的状态类中, 使得将来增加状态比较容易.

  • 状态模式的核心思想在于状态转换

public class BotContent {
  // 默认离线状态
  private State state = new DisconnectedState();

  public String chat(String input) {
    if ("hello".equalsIgnoreCase(input)) {
      // 切换到在线状态
      state = new ConnectedState();
      return state.init();
    } else if ("bye".equalsIgnoreCase(input)) {
      // 离线状态
      state = new DisconnectedState();
      return state.init();
    }
    return state.reply(input);
  }
}

策略

策略定义一系列的算法, 把它们一个个封装起来, 并使它们可以相互替换. 本模式主要是算法, 可以独立与使用它的客户而变化.

  • 策略模式: Strategy, 是指, 定义一组算法, 并把其封装到一个对象中. 然后在运行的时候, 可以灵活的运行其中某一个算法.
  • 流程是确定的, 但是, 某些关键步骤的算法依赖调用方传入的策略.
        String[] array = {"apple", "Pear", "Banana", "orange"};
        // Arrays.sort(array, String::compareToIgnoreCase);
        Arrays.sort(array, String::compareTo);
        System.out.println(Arrays.toString(array));

模板方法

定于一个操作中的算法的骨架, 而将一些步骤延迟到子类中, 使得子类可以不改变一个算法的结构, 即可重定义该算法的某些特定步骤.

  • 模板方法(template method)是一个比较简单的模式. 它的思想主要是, 定义一个操作的一系列步骤, 对于某些暂时确定不了的步骤, 就留给子类去实现好了, 这样不同的子类就可以定义出不同的步骤.
  • 模板方法的核心在于定义一个"骨架".
public abstract class AbstractSetting {
  public final String getSetting(String key) {
    String value = lookupCache(key);
    if (value == null) {
      value = readFromDatabase(key);
      putIntoCache(key, value);
    }
    return null;
  }

  public String readFromDatabase(String key) {
    return "value..";
  }

  protected abstract String lookupCache(String key);

  protected abstract void putIntoCache(String key, String value);
}

public class LocalSetting extends AbstractSetting {
  private Map<String, String> cache = new HashMap<>();

  @Override
  protected String lookupCache(String key) {
    return cache.get(key);
  }

  @Override
  protected void putIntoCache(String key, String value) {
    cache.put(key, value);
  }

}
  • 模板思想核心: 父类定义骨架, 子类实现某些细节.
  • 为了防止子类重写父类的骨架方法, 可以在父类中对骨架方法使用final.
  • 对于子类需要实现的抽象方法, 一般声明为protected, 使得这些方法对外部客户端不可见.

访问者

表示一个作用于某对象结构中的各个元素的操作.
它使你可以在不改变各元素的类的前提下, 定义作用这些元素的操作

  • 访问者模式(Visitor), 是一种操作一组对象的操作, 目的是不改变对象的定义, 但允许新增不同的访问者, 来定义新的操作.
public class FileStructure {
  // 根目录
  private File path;

  public void handle(Visitor visitor) {
    scan(path, visitor);
  }

  public void scan(File file, Visitor visitor) {
    if (file.isDirectory()) {
      // 让访问者处理文件夹:
      visitor.visitDir(file);
      for (File sub : file.listFiles()) {
        // 递归处理子文件夹
        scan(sub, visitor);
      }
    } else if (file.isFile()) {
      // 让访问者处理文件
      visitor.visitFile(file);
    }
  }

  public FileStructure(File path) {
    this.path = path;
  }
}

public class JavaFileVisitor implements Visitor {

  @Override
  public void visitDir(File dir) {
    System.out.println("Visit dir: " + dir);

  }

  @Override
  public void visitFile(File file) {
    if (file.getName().endsWith(".java")) {
      System.out.println("Found java file: " + file);
    }
  }
  
}
public interface Visitor {
  // 访问文件夹
  void visitDir(File dir);
  // 访问文件
  void visitFile(File file);
}

FileStructure fs = new FileStructure(new File("."));
fs.handle(new JavaFileVisitor());
  • 访问者模式的核心思想是为了访问比较复杂的数据结构, 不去改变数据结构, 而是把对数据的操作抽象出来
  • 在"访问"的过程中以回调形式在访问者中处理操作逻辑
public class App {

    public static void main(String[] args) throws IOException {
        Files.walkFileTree(Paths.get("."), new MyFileVisitor());
    }
}

class MyFileVisitor extends SimpleFileVisitor<Path> {
    // 处理文件夹
    public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)  {
        System.out.println("pre visit dir: " + dir);
        return FileVisitResult.CONTINUE;
    }

    // 处理文件
    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
        System.out.println("visit file: " + file);
        // 返回CONTINUE表示继续访问
        return FileVisitResult.CONTINUE;
    }
}
原文地址:https://www.cnblogs.com/zhangrunhao/p/14145228.html