美文网首页
Java 重构 & 设计模式

Java 重构 & 设计模式

作者: bowen_wu | 来源:发表于2022-06-24 15:16 被阅读0次

    重构 Refactor

    对软件的内部结构进行的调整

    • 不改变软件的对外功能
    • 提高可读性和可维护性,降低维护成本

    优点

    • 提高可读性
    • 找到 bug
    • 提高后续的开发效率

    原则

    • 如果没有自动化测试,不要重构
    • 重构要小步进行 => 每进行一次重构,运行自动化测试保证没有错误
    • 事不过三,三则重构

    方法

    • 重复代码 => 提炼代码 => Do not Repeat Yourself
    • 过长函数(超过50行 || 严重影响可读性和维护效率)
      1. 代码越小越容易理解
      2. 代码越小越不容易出错
      3. 代码越小越容易复用
      4. 代码越小越容易实现模板方法
    • 删除临时变量 => 不要让临时变量在方法中跳来跳去 => 创建函数去返回
    • 使用多态取代 if | else | switch
      1. 多态是虚拟机提供的隐藏的 if | else 功能
      2. 使用多态 + 策略模式重构 if | else | switch
      3. 使用枚举 + 方法引用重构 if | else | switch
    • 过大的类 => 一个类做了太多的事情 => 降低维护效率 & 破坏封装 => 使用继承或组合
      1. 明确类的职责,将工作提取到父类或者委托类中
      2. 越小的类越方便测试、维护和复用
      3. 缺点:逻辑散落在很多地方
    • 太多注释 => 没有注释不是最可怕的,过时的、有误导性的注释才是最可怕的 => 每当你想要写注释时,请先尝试重构,让注释显得多余 => 使用良好的命名代替注释

    设计模式

    • 人们在长久的生产实践中总结出来的一套方法论
    • 提高开发效率
    • 降低维护成本

    单例模式 Singleton

    在整个 JVM 中只存在某个类的一个实例 => 这个实例或对象是全局的,不可变的,唯一的

    • static
    • lazy init
    • 多线程 + 双锁检测
    • 枚举
    public class MySingleton {
        private static MySingleton instance = null;
    
        private MySingleton {
        }
    
        public static MySingleton getInstance() {
            if (instance == null) { // 多线程并发问题 => 两个线程各自创建一个 => 在单个线程内只有一个实例
                instance = new MySingleton();
            }
            return instance;
        }
    }
    
    public class World {
        // public static final World SINGLETON_INSTANCE = new World();
        private static final World SINGLETON_INSTANCE = new World();
    
        public static World getInstance() {
            return SINGLETON_INSTANCE;
        }
    
        private World() {
        }
    }
    

    工厂模式 Factory

    根据传入的参数动态产生出相应的产品

    静态工厂模式

    1. 使用静态工厂方法代替构造器
    2. 当使用静态工厂方法时,把构造器私有化 => private Cat() {} => 封装 => 使用者只能通过使用静态工厂方法进行创建实例,之后构造器内部的细节可以随意更改,只要对外接口不变外界就不需要改动代码
    优点
    • 有方法名,可以描述方法在做什么
    • 可能不需要创造新的对象,可以返回 null 或者之前创造好的对象 => 省时间 + 省内存
    • 可以返回当前声明类型的子类型,以提高静态工厂方法的灵活性
    • 根据传入的参数动态创建相应的对象
    • 静态工厂方法返回的对象可以不存在 => 动态加载 => 运行时动态加载子类 + 加载未来才会编写好的类
    缺点
    • 没有办法被子类化 => 如果只提供静态工厂方法,那么该类不能被继承 => Java 世界中规定了一个没有 public | protected 构造方法的类不能被继承
    • 静态工厂方法不容易被找到

    抽象工厂模式

    • 工厂和产品都是接口 => 抽象工厂模式 => 使用一个抽象的工厂来生产抽象的产品
    • 优点:使用产品时不需要关心实现,工厂可以动态的通过具体的情况决定提供的某些特定产品的实现
    • 实例:MultimapBuilder.build()

    建造者模式 Builder

    • 当一个类里面有很多属性时,此时实例化的时候需要传递很多参数,即使使用抽象工厂模式,也需要创建很多方法
    • 使用 IDEA 的 Builder Generator plugin,一键创建 builder,通过静态工厂方法创建实例,通过 withX (X 为属性名) 进行链式调用(return this),有选择性的设置属性,最后通过 .build() 结束。通过有名字的方法清楚地告知使用者在设置哪个属性
    • 隐藏创建对象的建造过程和细节
    • 仍可以直接创建复杂的对象
    • 实例:HttpClientBuilder | MultimapBuilder
    //  使用 builder 的静态工厂方法
    person  = PersonBuilder.createPerson()
                    .withFirstName("")
                    .withLastName("")
                    .withAddress("")
                    .build();
    

    代理模式 Proxy

    • 为其他对象提供一种代理以控制对这个对象的访问
    • 当调用一个接口的方法时,JDK 使用动态代理,将这个接口的方法转发给其中的代理 => MyBatis
    • java.lang.reflect.Proxy
    • 实例:RPC 框架 => Remote Procedure call => 远程过程调用 => dubbo

    适配器模式 Adapter

    • 作为两个不兼容的接口之间的桥梁
    • 实例:Spock JUnitFilterAdapter
    • org.apache.ibatis.logging.Log.java

    装饰器模式 Decorator

    • 动态的为一个对象增加功能,但是不改变其结构 => 不需要改之前类的任何代码
    • 向一个现有的对象添加新的功能,同时又不改变其结构
    • 实例:Collections.synchronizedList
    • org.apache.ibatis.executor.CachingExecutor.java => Cache + delegate(委托 | 代表)
    // DataService interface
    
    // DateServiceImpl class
    
    // Main.java
    
    // LogDecorator class
    
    // CacheDecorator class
    
    

    适合场景

    1. 面向接口
    2. 每个 Decorator 都需要写重复的代码 => AOP 解决这个问题

    享元模式 Flyweight

    • 使用共享对象减少创建对象的数量 => 减少内存占用和提供性能
    • 实例:String.intern()
      String a = new String('a').intern();
      String b = new String('a').intern();
      String c = new String('a').intern();
      
      System.out.pringln(a == b); // true
      System.out.pringln(a == c); // true
      

    组合模式

    • 用于把一组相似的对象当做一个单一的对象
    • 实例:JUnit TestSuite | TestCase

    模板模式

    • 提供一个模板,具体实现可以覆盖模板的全部或者部分 => 父类提供一些模板方法的实现,子类通过覆盖某些模板方法从而实现丰富多彩的功能 => 面向对象之继承
    • 一个抽象类公开定义了执行它的方法的模板
    • 子类可以按需求重写方法实现
    • 实例:AbstractApplicationContext.refresh()
    // 模板方法
    public class BookWriter {
        public void writeBook() {
            writeTitle();
            writeContent();
            writeEnding();
        }
    
        public void writeTitle() {
            System.out.println("标题");
        }
    
        public void writeContent() {
            System.out.println("内容");
        }
    
        public void writeEnding() {
            System.out.println("谢谢大家");
        }
    }
    
    // 实现 => 多态
    public class MyBookWriter extends BookWriter {
        public static void main(String[] args) {
            new MyBookWriter().writeBook();
        }
    
        @Override
        public void writeTitle() {
            // 如果想在模板的 writeTitle 方法中添加自己的方法
            super.writeTitle();
            System.out.println("My Title!");
        }
    
        // 覆盖模板的部分 => writeEnding
        @Override
        public void writeEnding() {
            // 如果想在模板的 writeEnding 方法中添加自己的方法
            System.out.println("Thank everyone!");
        }
    }
    

    策略模式

    • 一个类的行为或其算法可以在运行时更改
    • 实例:线程池 RejectedExecutionHandle
    class User {
        private boolean vip;
    
        public boolean isVip() {
            return vip;
        }
    }
    
    class PriceCalculator {
        public int calculate(DiscountStrategy discountStrategy, int price, User user) throws IllegalAccessException {
            return discountStrategy.discount(price, user);
    
    //        switch (strategy) {
    //            case "NoDiscount":
    //                return price;
    //            case "95":
    //                return (int) (price * 0.95);
    //            case "VIP":
    //                if (user.isVip()) {
    //                    return (int) (price * 0.85);
    //                }
    //                return (int) (price * 0.95);
    //            // ...
    //            default:
    //                throw new IllegalAccessException();
    //    }
        }
    }
    
    class DiscountStrategy {
        public int discount(int price, User user) {
            return price;
        }
    }
    
    class NoDiscountStrategy extends DiscountStrategy {
        @Override
        public int discount(int price, User user) {
            return price;
        }
    }
    
    class Discount95Strategy extends DiscountStrategy {
        @Override
        public int discount(int price, User user) {
            return (int) (price * 0.95);
        }
    }
    
    class VipDiscountStrategy extends DiscountStrategy {
        @Override
        public int discount(int price, User user) {
            if (user.isVip()) {
                return (int) (price * 0.85);
            }
            return (int) (price * 0.95);
        }
    }
    

    门面模式 Facade

    知识点

    1. 《重构改善既有代码的设计》Martin Fowler
    2. TODO: search 多线程 + 双锁检测 单例模式

    相关文章

      网友评论

          本文标题:Java 重构 & 设计模式

          本文链接:https://www.haomeiwen.com/subject/yeovvrtx.html