• Java笔记19


    • 使用设计模式的目的是为了可重用代码, 提高代码的可扩展性和可维护性

    • 尽量复用代码, 降低代码的偶合度

    • 设计模式主要是基于OOP编程提炼的

    • 开闭原则: 尽量对扩展开发, 对修改关闭. 能不修改代码, 只增加代码即可完成新功能, 是最好的.

    • 里氏替换原则: 如果我们调用父类的方法可以成功, 替换成子类调用也可以成功

    • 创建性模式
    • 关注如何创建对象, 核心是把对象的创建和使用分开, 两者可以相对独立的变换

    工厂方法

    定义一个用于创建对象的接口, 让子类决定实例化哪一个类. 工厂方法是: 使一个类的创建延迟到子类

    • 工厂方法目的: 使得创建对象和使用对象是分离的, 并且客户端总是引用抽象工场和抽象产品.
    public class Main {
      public static void main(String[] args) {
        NumberFactory factory = NumberFactory.getFactory();
        Number result = factory.parse("1234");
        System.out.println(result);
      }
    }
    
    // 实现一个解析字符串到`Number`的Factory
    interface NumberFactory {
      Number parse(String s);
      // 获取工厂实例
      static NumberFactory getFactory() {
        return impl;
      }
      static NumberFactory impl = new NumberFactoryImpl();
    }
    
    // 工厂的实现类
    class NumberFactoryImpl implements NumberFactory {
      public Number parse(String s) {
        return new BigDecimal(s);
      }
    }
    
    • 可以完全忽略真正的工程NumberFactoryImpl和产品BigDecimal
    • 允许创建产品的代码独立变化, 而不会影响到调用方
    interface NumberFactory {
      public static Number parse(String s) {
        return new BigDecimal(s);
      }
    }
    
    • 静态工厂方法

    • 工厂方法可以隐藏创建产品的细节, 且不会每一次都会真正的创建的产品. 也可能是从缓存中拿出, 从而提升速度并减少内存消耗

    • 例如Integer.valueOf(), 可以提前初始化很多常用的, 实例, 每次都调用缓存中的实例, 当没有的时候, 再放一个进去

    • 总是引用接口, 能允许变化子类, 而不影响调用方, 尽可能面向对象编程

    // TODO: 没搞明白List.of()是如何执行并返回的.
    List<String> list = List.of("a", "b", "c", "d");
    System.out.println(list);
    
    class LocalDateFactory {
      private static Map<Integer, LocalDate> cache = new HashMap<Integer, LocalDate>();
    
      public static LocalDate fromIn(int yyyyMMdd) {
        if (yyyyMMdd > 20000101 && yyyyMMdd < 20200101) {
          if (cache.containsKey(yyyyMMdd)) return cache.get(yyyyMMdd);
          LocalDate value = createDate(yyyyMMdd);
          cache.put(yyyyMMdd, value);
          return value;
        } else {
          return createDate(yyyyMMdd);
        }
      }
    
      private static LocalDate createDate(int yyyyMMdd) {
        System.out.println("run createDate");
        return LocalDate.of(yyyyMMdd / 1000, yyyyMMdd / 100 % 100, yyyyMMdd % 100);
      }
    }
    
    • 产生实例的过程外界并不知道, 可以进行适当的缓存, 增加产生实例的效率

    抽象工厂

    提供一个创建一系列相关或者相互依赖对象的接口, 而无需指定他们具体的类

    • 工厂是抽象的, 工厂产出的产品也是抽象的.
    • 然后有个具体的工厂1, 实现了工厂, 工厂1中的产品1-1, 实现了产品
    ├── lib
    └── src
        ├── App.java
        ├── fastfactory
        │   ├── FastFactory.java // 实际工厂
        │   ├── FastHtmlDocument.java // 实际产品
        │   └── FastWordDocument.java // 实际产品
        ├── goodfactory
        │   ├── GoodFactory.java // 实际工厂
        │   ├── GoodHtmlDocument.java // 实际产品
        │   └── GoodWordDocument.java // 实际产品
        └── services
            ├── AbstractFactory.java // 虚拟工厂
            ├── HtmlDocument.java // 虚拟产品
            └── WordDocument.java // 虚拟产品
    
    // 虚拟工厂
    public interface AbstractFactory {
      HtmlDocument createHtml(String md);
    
      WordDocument createWord(String md);
    }
    // 虚拟产品
    public interface HtmlDocument {
      String toHtml();
    
      void save(Path path);
    }
    // 虚拟产品
    public interface WordDocument {
      void save(Path path);
    }
    // 实际工厂
    public class GoodFactory implements AbstractFactory {
    
      @Override
      public HtmlDocument createHtml(String md) {
        return new GoodHtmlDocument(md);
      }
    
      @Override
      public WordDocument createWord(String md) {
        return new GoodWordDocument(md);
      }
    
    }
    // 实际产品
    public class GoodHtmlDocument implements HtmlDocument {
      private String md;
    
      public GoodHtmlDocument(String md) {
        this.md = md;
      }
    
      @Override
      public String toHtml() {
        System.out.println(md);
        return null;
      }
    
      @Override
      public void save(Path path) {
      }
    
    }
    // 实际产品
    public class GoodWordDocument implements WordDocument {
      private String md;
    
      public GoodWordDocument(String md) {
        this.md = md;
      }
    
      @Override
      public void save(Path path) {
        System.out.println(md);
      }
    
    }
    

    生成器

    将一个复杂对象的构建与表示分离, 使得同样的构建过程可以创建不同表示

    public class HtmlBuilder {
      // 分成多个builder, 一步步构建
      private HeadingBuilder headingBuilder = new HeadingBuilder();
      private HrBuilder hrBuilder = new HrBuilder();
      private ParagraphBuilder paragraphBuilder = new ParagraphBuilder();
      private QuoteBuilder quoteBuilder = new QuoteBuilder();
    
      public String toHtml(String md) {
        StringBuilder buffer = new StringBuilder();
        md.lines().forEach(line -> {
          if (line.startsWith("#")) {
            buffer.append(headingBuilder.buildHeading(line))
              .append("
    ");
          } else if (line.startsWith(">")) {
            buffer.append(quoteBuilder.buildQuote(line))
              .append("
    ");
          } else if (line.startsWith("---")) {
            buffer.append(hrBuilder.buildHr(line))
             .append("
    ");
          } else {
            buffer.append(paragraphBuilder.buildParagraph(line))
              .append("
    ");
          }
        });
        return buffer.toString();
      }
    }
    
    // 分步骤构建
    public class URLBuilderImpl implements URLBuilder {
    
      private String domain = "www.baidu.com";
      private String scheme = "http";
      private String path = null;
      private Map<String, String> query;
    
      @Override
      public URLBuilder setDomain(String domain) {
        this.domain = Objects.requireNonNull(domain);
        return this;
      }
    
      @Override
      public URLBuilder setScheme(String scheme) {
        this.scheme = Objects.requireNonNull(scheme);
        return this;
      }
    
      @Override
      public URLBuilder setPath(String path) {
        this.path = Objects.requireNonNull(path);
        return this;
      }
    
      @Override
      public URLBuilder setQuery(Map<String, String> query) {
        this.query = query;
        return this;
      }
    
      @Override
      public String build() {
        StringBuilder sb =  new StringBuilder();
        sb.append(scheme)
          .append("://")
          .append(domain)
          .append(path);
        if (this.query.size() > 0) {
          sb.append("?");
          this.query.forEach((k, v) -> {
            sb.append(k).append("=").append(v).append("&");
          });
          sb.setLength(sb.length() - 1);
        }
        return sb.toString();
      }
    
      public URLBuilderImpl() {
      }
    }
    

    原型

    • 用原型实例指定创建对象的种类, 并且通过拷贝这些原型创建新的对象

    原型模式 就是 Prototype, 只指创建新对象的时候, 根据现有的一个原型来创建.

    public class Student  {
      private int id;
      private String name;
      private int score;
    
      // 复制对象并, 直接返回相同类型, 省去类型转换
      public Student copy() {
        Student std = new Student();
        std.id = this.id;
        std.name = this.name;
        std.score = this.score;
        return std;
      }
    }
    

    单例

    • 保证一个类仅有一个实例, 并提供一个访问它的全局访问点

    单例模式的目的是为了保证在一个进程中, 某个类有且仅有一个实例.

    public class Singleton {
      // 静态字段引用唯一实例:
      private static final Singleton INSTANCE = new Singleton();
    
      // 通过静态方法返回实例
      public static Singleton getInstance() {
        return INSTANCE;
      }
    
      // private构造方法, 保证外部不能实例化
      private Singleton() {
      }
    }
    
    public class Singleton {
      // 静态字段引用唯一实例:
      public static final Singleton INSTANCE = new Singleton();
    
      // private构造方法, 保证外部不能实例化
      private Singleton() {
      }
    }
    
    • 对构造函数进行private私有化保护

    • 延迟加载的方式, 多线程的方式会导致错误

    • 使用枚举的方式实现单例

      • 可以避免序列化和反序列化会绕过普通类的private方法
      • 也可以定自己的字段方法等
    // java保证枚举类的每个枚举, 都是单例
    public enum World {
      // 唯一枚举
      INSTANCE;
    
      private String name = "world";
    
      public String getName() {
        return name;
      }
      public void setName(String name) {
        this.name = name;
      }
    }
    
    • 通过约定, 在框架中直接使用单例. 例如@Component
  • 相关阅读:
    UWP AppConnection.
    Qt 多线程使用moveToThread
    C#综合细说进程、应用程序域与上下文
    C++ std::function
    商品价格加价区间的实现(策略模式)
    学习web前端三个月感悟
    triangle leetcode C++
    Linux入门视频
    轻松学习Linux之进程监视与管理
    阻止缓冲区溢出攻击
  • 原文地址:https://www.cnblogs.com/zhangrunhao/p/14077515.html
Copyright © 2020-2023  润新知