Java研发基础——设计模式

什么是设计模式

设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。

设计模式的分类

设计模式主要分为以下三大类:

  • 创建型模式(5种):工厂方法模式(Factory Method Pattern)、抽象工厂模式(Abstract Factory Pattern)、单例模式(Singleton Pattern)、建造者模式(Builder Pattern)、原型模式(Prototype Pattern)。
  • 结构型模式(7种):适配器模式(Adapter Pattern)、装饰器模式(Decorator Pattern)、代理模式(Proxy Pattern)、外观模式(Facade Pattern)、桥接模式(Bridge Pattern)、组合模式(Composite Pattern)、享元模式(Flyweight Pattern)。
  • 行为型模式(11种):策略模式(Strategy Pattern)、模板方法模式(Template Method Pattern)、观察者模式(Observer Pattern)、迭代器模式(Iterator Pattern)、责任链模式(Chain of Responsibility Pattern)、命令模式(Command Pattern)、备忘录模式(Memento Pattern)、状态模式(State Pattern)、访问者模式(Visitor Pattern)、中介者模式(Mediator Pattern)、解释器模式(Interpreter Pattern)。

设计模式的六大原则

  • 开放封闭原则(Open Close Principle)

原则思想:尽量通过扩展软件实体来解决需求变化,而不是通过修改已有的代码来完成变化。
描述:一个软件产品在生命周期内,都会发生变化,既然变化是一个既定的事实,我们就应该在设计的时候尽量适应这些变化,以提高项目的稳定性和灵活性。
优点:单一原则告诉我们,每个类都有自己负责的职责,里氏替换原则不能破坏继承关系的体系。

  • 里氏代换原则(Liskov Substitution Principle)

原则思想:使用的基类可以在任何地方使用继承的子类,完美的替换基类。
描述:子类可以扩展父类的功能,但不能改变父类原有的功能。子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法,子类中可以增加自己特有的方法。
优点:增加程序的健壮性,即使增加了子类,原有的子类还可以继续运行,互不影响。

  • 依赖倒转原则(Dependence Inversion Principle)

原则思想:依赖倒置原则的核心思想是面向接口编程。
描述:依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类。这个是开放封闭原则的基础,具体内容是:对接口编程,依赖于抽象而不依赖于具体。

  • 接口隔离原则(Interface Segregation Principle)

描述:使用多个隔离的接口,比使用单个接口要好。是一个降低类之间的耦合度的意思。例如:支付类的接口和订单类的接口,需要把这俩个类别的接口变成俩个隔离的接口。

  • 迪米特法则(最少知道原则)(Demeter Principle)

原则思想:一个对象应当对其他对象有尽可能少地了解,简称类间解耦。
描述:一个类尽量减少自己对其他对象的依赖,原则是低耦合,高内聚,只有使各个模块之间的耦合尽量的低,才能提高代码的复用率。
优点:低耦合,高内聚。

  • 单一职责原则(Principle of single responsibility)

原则思想:一个方法只负责一件事情。
描述:单一职责原则很简单,一个方法 一个类只负责一个职责,各个职责的程序改动,不影响其它程序。 这是常识,几乎所有程序员都会遵循这个原则。
优点:降低类和类的耦合,提高可读性,增加可维护性和可拓展性,降低可变性的风险。

主要设计模式介绍

单例模式

  1. 什么是单例
    保证一个类只有一个实例,并且提供一个访问该全局访问点。

  2. 单例模式的应用
    ① 网站的计数器,一般也是采用单例模式实现,否则难以同步。
    ② 应用程序的日志应用,一般都是单例模式实现,只有一个实例去操作才好,否则内容不好追加显示。
    ③ 多线程的线程池的设计一般也是采用单例模式,因为线程池要方便对池中的线程进行控制。
    ④ Windows的任务管理器就是很典型的单例模式,他不能打开两个。
    ⑤ Windows的回收站也是典型的单例应用。在整个系统运行过程中,回收站只维护一个实例。

  3. 单例模式优缺点
    优点
    ① 在单例模式中,活动的单例只有一个实例,对单例类的所有实例化得到的都是相同的一个实例。这样就防止其它对象对自己的实例化,确保所有的对象都访问一个实例。
    ② 单例模式具有一定的伸缩性,类自己来控制实例化进程,类就在改变实例化进程上有相应的伸缩性。
    ③ 提供了对唯一实例的受控访问。
    ④ 由于在系统内存中只存在一个对象,因此可以节约系统资源,当需要频繁创建和销毁的对象时单例模式无疑可以提高系统的性能。
    ⑤ 允许可变数目的实例。
    ⑥ 避免对共享资源的多重占用。
    缺点
    ① 不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
    ② 由于单利模式中没有抽象层,因此单例类的扩展有很大的困难。
    ③ 单例类的职责过重,在一定程度上违背了“单一职责原则”。
    ④ 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;如果实例化的对象长时间不被利用,系统会认为是垃圾而被回收,这将导致对象状态的丢失。

  4. 单例模式使用注意事项
    ① 使用时不能用反射模式创建单例,否则会实例化一个新的对象。
    ② 使用懒单例模式时注意线程安全问题。
    ③ 饿单例模式和懒单例模式构造方法都是私有的,因而是不能被继承的,有些单例模式可以被继承(如登记式模式)。

  5. 单例创建方式
    (主要使用饿汉式和懒汉式)
    饿汉式:类初始化时会立即加载该对象,线程天生安全,调用效率高。
    懒汉式:类初始化时不会初始化该对象,真正需要使用的时候才会创建该对象,具备懒加载功能。
    静态内部方式:结合了懒汉式和饿汉式各自的优点,真正需要对象的时候才会加载,加载类是线程安全的。
    枚举单例:使用枚举实现单例模式。优点:实现简单、调用效率高,枚举本身就是单例,由jvm从根本上提供保障,避免通过反射和反序列化的漏洞; 缺点:没有延迟加载。
    双重检测锁方式(因为JVM本质重排序的原因,可能会初始化多次,不推荐使用)。
    :如何选择单例创建方式?
    如果不需要延迟加载单例,可以使用枚举或者饿汉式,相对来说枚举好于饿汉式。如果需要延迟加载,可以使用静态内部方式或者懒汉式,相对来说静态内部方式好于懒汉式。最好使用饿汉式。

工厂模式

  1. 什么是工厂模式
    它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。实现了创建者和调用者分离,工厂模式分为简单工厂、工厂方法、抽象工厂模式。

  2. 工厂模式的优点
    ① 工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。
    ② 利用工厂模式可以降低程序的耦合性,为后期的维护修改提供了很大的便利。
    ③ 将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。

  3. 工厂模式分类
    简单工厂模式(不是设计模式):简单工厂模式相当于是一个工厂中有各种产品,创建在一个类中,客户无需知道具体产品的名称,只需要知道产品类所对应的参数即可。但是工厂的职责过重,而且当类型过多时不利于系统的扩展维护。
    优点:简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。明确区分了各自的职责和权力,有利于整个软件体系结构的优化。
    缺点:很明显工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则。
    工厂方法模式:工厂方法模式Factory Method,又称多态性工厂模式。在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。
    抽象工厂模式:抽象工厂简单地说是工厂的工厂,抽象工厂可以创建具体工厂,由具体工厂来产生具体产品。

代理模式

  1. 什么是代理模式
    通过代理控制对象的访问,可以在这个对象调用方法之前、调用方法之后去处理/添加新的功能。(也就是AODP微实现)
    代理在原有代码乃至原业务流程都不修改的情况下,直接在业务流程中切入新代码,增加新功能,这也和Spring的面向切面编程很相似。

  2. 代理模式应用场景
    Spring AOP、日志打印、异常处理、事务控制、权限控制等。

  3. 代理的分类
    静态代理(静态定义代理类):由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。
    缺点:每个需要代理的对象都需要自己重复编写代理,很不舒服。
    优点:可以面相实际对象或者是接口的方式实现代理。
    动态代理(动态生成代理类,也称为JDK自带动态代理):动态代理也叫做JDK代理、接口代理。动态代理的对象,是利用JDK的API动态地在内存中构建代理对象(是根据被代理的接口来动态生成代理类的class文件,并加载运行的过程),这就叫动态代理。
    缺点:必须是面向接口,目标业务类必须实现接口。
    优点:不用关心代理类,只需要在运行阶段才指定代理哪一个对象。
    Cglib、javaassist(字节码操作库):CGLIB动态代理和jdk代理一样,使用反射完成代理,不同的是他可以直接代理类(jdk动态代理不行,他必须目标业务类必须实现接口),CGLIB动态代理底层使用字节码技术,CGLIB动态代理不能对final类进行继承。(CGLIB动态代理需要导入jar包)

  4. 三种代理的区别
    静态代理:简单代理模式,是动态代理的理论基础。常见使用在代理模式。
    jdk动态代理:使用反射完成代理。需要有顶层接口才能使用,常见是mybatis的mapper文件是代理。
    cglib动态代理:也是使用反射完成代理,可以直接代理类(jdk动态代理不行),使用字节码技术,不能对final类进行继承。(需要导入jar包)

建造者模式

  1. 什么是建造者模式
    将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的方式进行创建。

  2. 建造者模式与工厂模式的区别
    工厂类模式提供的是创建单个类的产品,而建造者模式则是将各种产品集中起来进行管理,用来管理具有不同的属性的产品。

  3. 建造者模式通常包括下面几个角色
    uilder:给出一个抽象接口,以规范产品对象的各个组成成分的建造。这个接口规定要实现复杂对象的哪些部分的创建,并不涉及具体的对象部件的创建。
    ConcreteBuilder:实现Builder接口,针对不同的商业逻辑,具体化复杂对象的各部分的创建。 在建造过程完成后,提供产品的实例。
    Director:调用具体建造者来创建复杂对象的各个部分,在指导者中不涉及具体产品的信息,只负责保证对象各部分完整创建或按某种顺序创建。
    Product:要创建的复杂对象。

  4. 建造者模式的使用场景
    ① 需要生成的对象具有复杂的内部结构。
    ② 需要生成的对象内部属性本身相互依赖。
    :与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。JAVA 中的 StringBuilder就是建造者模式创建的,他把一个单个字符的char数组组合起来。Spring不是建造者模式,它提供的操作应该是对于字符串本身的一些操作,而不是创建或改变一个字符串。

模板方法模式

  1. 什么是模板方法模式
    定义一个操作中的算法骨架(父类),而将一些步骤延迟到子类中。
    模板方法使得子类可以不改变一个算法的结构来重定义该算法。

  2. 什么时候使用模板方法模式
    实现一些操作时,整体步骤很固定,但是其中一小部分需要改变,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。

  3. 模板方法模式的应用场景
    数据库访问的封装、Junit单元测试、servlet中关于doGet/doPost方法的调用等等。

原型模式

  1. 什么是原型模式
    原型设计模式简单来说就是克隆。
    原型表明了有一个样板实例,这个原型是可定制的。原型模式多用于创建复杂的或者构造耗时的实例,因为这种情况下,复制一个已经存在的实例可使程序运行更高效。

  2. 原型模式的应用场景
    ① 类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。这时我们就可以通过原型拷贝避免这些消耗。
    ② 通过new产生的一个对象需要非常繁琐的数据准备或者权限,这时可以使用原型模式。
    ③ 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。
    :Spring框架中的多例就是使用原型。

  3. 原型模式的使用方式
    实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。
    重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此Prototype类需要将clone方法的作用域修改为public类型。

  4. 原型模式分为浅复制和深复制
    浅复制只是拷贝了基本类型的数据,而引用类型数据只是拷贝了一份引用地址。
    深复制在计算机中开辟了一块新的内存地址用于存放复制的对象。

参考资料:https://juejin.cn/post/6844904125721772039

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值