• 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;
        }
    }
    
  • 相关阅读:
    SVN 服务器 配置
    字符串写入到json文件
    关于Linux系统打开最大文件数量
    svn clearup svn cleanup failed–previous operation has not finished; run cleanup if it was int错误的解决办法
    原标题:北大最短毕业致辞,4分钟9次掌声!
    Mysql 基础操作命令
    Git 合并两个分支内容
    微信、QQ第三方登录授权时的问题总结
    PHP CI框架数据库常用操作
    Python 抓取数据存储到Mysql中
  • 原文地址:https://www.cnblogs.com/zhangrunhao/p/14145228.html
Copyright © 2020-2023  润新知