美文网首页右耳菌-邓小白的Java架构师的修炼之路
JAVA 开发能力之编码能力、设计模式及复杂度

JAVA 开发能力之编码能力、设计模式及复杂度

作者: 右耳菌 | 来源:发表于2022-04-21 23:25 被阅读0次

    一、开发设计模式

    1. 常用的JAVA 开发模式
    • Model1 JSP页面和JavaBean
      使用JSP页面和JavaBean相结合的方式,由JSP页面来接收客户端请求,用JavaBean或其他服务完成业务逻辑、数据库操作和返回页面。我们这里的JavaBean主要是完成特定功能的Java类。
    JSP页面和JavaBean相结合
    • Model2 MVC
      Model1虽然在一定程度上解耦了,但JSP依旧即要负责页面控制,又要负责逻辑处理,职责不单一。此时Model2应运而生,使得各个部分各司其职。

      MVC
    • Model3 三层模型
      Model2巧妙的将JSP中的业务逻辑部分分给了Servlet,使得页面控制与逻辑处理彻底分离,达到了部分解耦的目的。但我们现实项目开发中,往往在Model2的基础上又进行了分层。将业务逻辑细分为业务逻辑和持久化逻辑两层。

      三层模型
    • 总结对比

    总结对比
    2. 设计模式
    • 模式: 在某些场景下,针对某类问题的某种通用的解决方案。
    • 设计模式(Design Pattern):开发经验的总结,是解决特定问题的一系列套路。不是什么语法规定之类的东西,其存在的目的就是为了提高代码的可复用性可维护性可读性稳健性以及安全性的解决方案。(常说的设计模式有 23 种,当然不是说只有23种,设计模式是在不停地发展的)

    • 设计原则(六大设计原则)
    1. 单一职责原则(Single Responsibility Principle, SRP)

    一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因

    • 类的功能尽量单一,这样才能提高复用率。
    • 单一职能原则是软件高内聚低耦合的指导方针。
    1. 开闭原则(Open Close Principle,OCP)
    • 应当对扩展开放,对修改关闭。
    • 即软件实体应尽量在不修改原有代码的情况下进行扩展
    • 开闭原则即对拓展开放,对修改关闭,要想在功能新增的时候不修改原先的代码,即程序中使用的是抽象类或者接口,我们新增的子类或者实现,这样才能保障我们拓展功能的时候不用修改原先的代码,所以说抽象化是开闭原则的关键。
    1. 里氏替换原则(Liskov Substitution Principle,LSP)

    所有引用基类(父类)的地方必须能透明地使用其子类的对象
    基类存在的地方必定能被子类替换,且功能不会发生影响。里氏替换原则是“开-闭原则的补充”
    里氏替换通俗来讲就是子类可以拓展父类但是不能改变父类已确定的行为,包含以下四个含义:

    • 子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法。
    • 子类中可以增加自己特有的方法
    • 当子类重载父类方法时,形参的范围要比父类的形参范围大,这样别的类调用这个方法时会优先匹配父类的实现而不是子类的实现。
    • 当子类实现父类的抽象方法时,方法的返回值要比父类更严格(更具体)
    1. 依赖倒置原则(Dependence Inversion Principle,DIP)

    抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。

    • 依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。
    • 在实现依赖倒转原则时,我们需要针对抽象层编程,而将具体类的对象通过依赖注入(Dependency Injection, DI)的方式注入到其他对象中,依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。
    • 常用的注入方式有三种,分别是:构造注入,设值注入(Setter注入)和接口注入。
      1. 构造注入是指通过构造函数来传入具体类的对象,
      2. 设值注入是指通过Setter方法来传入具体类的对象,
      3. 而接口注入是指通过在接口中声明的业务方法来传入具体类的对象。
        这些方法在定义时使用的是抽象类型,在运行时再传入具体类型的对象,由子类对象来覆盖父类对象。
    • 开闭原则是目标,里氏代换原则是基础,依赖倒转原则是手段。
    1. 接口隔离原则(Interface Segregation Principle, ISP)

    使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口
    每一接口都应该承担一种相对独立的角色,该干的事情都干,不该干的事情都不干。

    1. 迪米特法则(Law of Demeter, LoD)

    一个软件实体应当尽可能少地与其他实体发生相互作用。

    • 类与类之间的耦合度应尽量的低,这样如果类发生变化,影响才会最小。
    • 不要和陌生人说话,只和你的直接朋友通信,直接朋友包含如下:
      • 当前对象本身(this)
      • 作为参数的对象
      • 成员变量
      • 集合成员变量中的元素
      • 创建的对象
    • 可以通过使用第三者类来降低两个类的耦合度。

    • 设计模式分类
    1. 行为型模式
      • 访问者模式
      • 模板模式
      • 策略模式
      • 状态模式
      • 观察者模式
      • 备忘录模式
      • 中介者模式
      • 迭代器模式
      • 解释器模式
      • 命令模式
      • 责任链模式
    2. 创建型模式
      • 单例模式
      • 工厂方法模式
      • 抽象工厂模式
      • 建造者模式
      • 原型模式
    3. 结构性模式
      • 适配器模式
      • 桥接模式
      • 组合模式
      • 装饰模式
      • 外观模式
      • 亨元模式
      • 代理模式

    • 需要重点了解的设计模式

    一、创建型模式:

    1. 单例
    • 懒汉模型 - 线程不安全
    /**
     * 懒汉模式 - 并发情况下线程不安全
      */
    public class Singleton {
    
        private static Singleton uniqueInstance;
    
        private Singleton() {
        }
    
        public static Singleton getUniqueInstance() {
            if (uniqueInstance == null) {
                // 为空时候,在内部通过new关键字来创建
                uniqueInstance = new Singleton();
            }
            return uniqueInstance;
        }
    }
    
    • 饿汉模式 - 线程安全,但是无法实现懒加载,即无法加载到Spring中进行管理
    /**
     * 饿汉模式 - 线程安全
     */
    public class Singleton2 {
    
        private static Singleton2 uniqueInstance = new Singleton2();
    
        private Singleton2() {
        }
    
        public static Singleton2 getUniqueInstance() {
            return uniqueInstance;
        }
    }
    
    • 加锁懒汉式 - 线程安全
    /**
     * 加锁懒汉模式 - 线程安全
     * 同样使用懒汉式,并在静态方法加上 synchronized 同步,
     * 但这会让线程阻塞时间过长、有性能问题,不推荐使用。
     */
    public class Singleton3 {
    
        private static Singleton3 uniqueInstance;
    
        private Singleton3() {
        }
    
        public static synchronized Singleton3 getUniqueInstance() {
            if (uniqueInstance == null) {
                uniqueInstance = new Singleton3();
            }
            return uniqueInstance;
        }
    }
    
    • 双重校验懒汉式 - 线程安全且不会过大的降低性能,仅在第一次访问存在并发时会有性能下降
    /**
     * 双重校验锁
     * 线程安全且不会过大的降低性能,仅在第一次访问存在并发时会有性能下降,此时     
     * uniqueInstance = null 判断都为true, 
     * 并发的线程在synchronized (Singleton4.class)时,将排队执行,此时有性能下降
     */
    public class Singleton4 {
    
        // 1
        private volatile static Singleton4 uniqueInstance;
    
        private Singleton4() {
        }
    
        public static Singleton4 getUniqueInstance() {
            // 2
            if (uniqueInstance == null) {
                // 3
                synchronized (Singleton4.class) {
                    // 4
                    if (uniqueInstance == null) {
                        uniqueInstance = new Singleton4();
                    }
                }
            }
            return uniqueInstance;
        }
    }
    
    • 利用静态内部类延迟加载的特性 - 不建议使用
    /**
     * 利用静态内部类延迟加载的特性
     *
     * 当 Singleton 类加载时,静态内部类 SingletonHolder 没有被加载进内存。
     * 只有当调用 getUniqueInstance() 方法从而触发 SingletonHolder.INSTANCE 时 SingletonHolder 才会被加载,
     * 此时初始化 INSTANCE 实例,并且 JVM 能确保 INSTANCE 只被实例化一次。
     * 这种方式不仅具有延迟初始化的好处,而且由 JVM 提供了对线程安全的支持。
     */
    public class Singleton5 {
    
        private Singleton5() {
        }
    
        public static Singleton5 getUniqueInstance() {
            return SingletonHolder.INSTANCE;
        }
    
        // 静态内部类 + 静态内部域
        private static class SingletonHolder {
            private static final Singleton5 INSTANCE = new Singleton5();
        }
    
    }
    
    • 枚举实现
     /**
     * 枚举实现
     *
     */
    public class Singleton6 {
    
        // 私有构造函数
        private Singleton6() {
        }
    
        public static Singleton6 getInstance() {
            return SingletonEnum.INSTANCE.getInstance();
        }
    
        private enum SingletonEnum {
    
            INSTANCE;
    
            private Singleton6 singleton;
    
            // JVM 保证这个方法只调用一次
            SingletonEnum() {
                singleton = new Singleton6();
            }
    
            public Singleton6 getInstance() {
                return singleton;
            }
        }
    }
    
    1. 工厂
    2. 建造者

    二、结构性模式:

    1. 适配器
    2. 代理

    三、行为型模式

    1. 责任链
    2. 策略
    3. 观察者

    待后续完善

    相关文章

      网友评论

        本文标题:JAVA 开发能力之编码能力、设计模式及复杂度

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