泰安市网站建设公司,企业培训课程设置,技术支持 随州网站建设,代理注册公司网站模版本文主要介绍设计模式的主要设计原则和常用设计模式。 一、UML画图
1.类图 2.时序图 二、设计模式原则
1.单一职责原则
就是一个方法、一个类只做一件事#xff1b;
2.开闭原则
就是软件的设计应该对拓展开放#xff0c;对修改关闭#xff0c;这在java中体现最明显的就… 本文主要介绍设计模式的主要设计原则和常用设计模式。 一、UML画图
1.类图 2.时序图 二、设计模式原则
1.单一职责原则
就是一个方法、一个类只做一件事
2.开闭原则
就是软件的设计应该对拓展开放对修改关闭这在java中体现最明显的就是访问控制修饰符
3.里式替换原则
就是在设计父子关系时就是如果能用子类则一定也能用父类替代
4.接口隔离
每个接口的设计要高内聚低耦合
5.迪特米原则
这个也叫最小知道原则就是设计一个类的时候要保证这个对象知道的最小
6.依赖倒置原则
主要是为了解决类之间的耦合性这个在spring中体现的很详细就是类间的依赖通过接口来实现
三、常用设计模式
设计模式分为三种类型共23种
创建型模式单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。 结构型模式适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。 行为型模式模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、责任链模式、访问者模式。
创建型模式
1.原型模式singleton
1) 概述
解决问题在系统中其实只需要该类的一个对象为避免频繁创建和销毁其他对象只给该类一个单例对象供使用解决方法给该类一个全局静态变量来保存单例只提供一个共有方法来获取该实例不提供构造方法来实例化对象使用场景1.只需要一个全局实例的比如说生产全局UUID的生成器
2) 具体说明
普通模式重点注意由于只有一个实例化对象所以实例变量是静态成员变量再就是构造方法要是private修饰排除new方法创建新的对象还有就是创建实例对象的方法要是public static这样才能通过类名直接创建 饿汉式就是创建一个静态常量作为实例这样类一加载就完成了实例对象的初始化操作劣势也很明显就是没法懒加载但后面没有用到该单例时候也被加载进来的了 懒汉式就是在调用getInstance()方法时才实例出单例对象并且之前创建单例模式的方法都没有考虑到并发情况当同时进入到getInstance()创建实例时候没有办法保证只创建一个实例所以动用synchronized和volatile关键字来保证方法的调用并发执行 双重检验式在创建单例之前判断单例是否存在再进入加锁阶段和懒汉式有区别的是加锁阶段后还会再次判断是否单例存在这是生产环境常用的模式。 IoDH方式就是通过内部静态类的方式来避免懒汉式类加载的时候就创建了实例的问题
3) 代码实现
/*** author yangnk* desc* date 2023/08/13 16:46**/
public class Singleton {//volatile 保障可见性private volatile static Singleton singleton;//private构造方法无法通过new来实例化对象private Singleton() { }public static Singleton getSingleton() {if (singleton null) {//用synchronized加锁只允许并发情况下进行一个实例化操作synchronized (Singleton.class) {//需要再次判断singletonTest null避免指令重排导致初始化和分配内存失序if (singleton null) {singleton new Singleton();}}}return singleton;}public static void main(String[] args) {for (int i 0; i 3; i) {Singleton singleton Singleton.getSingleton();System.out.println(singletonTest.hashCode() singleton.hashCode());}}
}
4) 总结
优点1、只有一个对象在内存中不用占用过多堆内存2、只有一个实例可以严格控制访问控制缺点1、违法类设计模式的单一指责的原则一个实例就能做好所有的事肯定不行
2.工厂模式factory
1) 概述
解决问题将产品实例的创建过程封装在工厂类中实现将产品的声明和创建分离开来提供统一的接口来创建不同的产品实例解决需要创建多种继承同一接口的产品解决方法每个产品实现同一抽象产品类每个工厂类实现同一抽象工厂类通过多态特性实现不同的产品由不同的产品工厂类来实现使用场景工厂设计模式在各大框架中是运用最多的在自己之前写过的代码中日志记录也用到了这种设计模式他可以拓展其他记录日志的方式再通过反射和配置的形式可以做到不需要修改代码就能实现不同记录日志的功能
2) 具体说明
**主要角色**
抽象工厂类声明了一组用于创建产品对象的方法每个方法对应一种产品类型。抽象工厂可以是接口或抽象类。 具体工厂类生产具体产品的类实现了抽象工厂类 抽象产品类是具体产品类的父类封装了具体产品的方法 具体产品类实现具体方法实现了抽象产品类 几种不同的工厂模式 简单工厂模式工厂方法的思路是通过工厂类来创建相应的实体对象简单工厂的逻辑是具体产品类实现抽象或接口产品类的方法外部想要使用该产品需要通过工厂类来获取该类工厂模式通过判定来生产相应的具体产品类 抽象工厂模式当碰到所需生产的具体产品太多的时候它只需要实现相应的具体产品类但是在工厂类中他是需要修改代码来实现的这就违背了设计模式修改闭合的原则所以借鉴产品类有抽象或接口的思路工厂类也有相应的抽象类或接口如果新增了具体产品就新增相应产品工厂类。
3) 代码实现
4) 总结
优势1、向用户隐藏了产品生产的逻辑符合Java良好封装性的特征2、如果想要再加新的产品类不需要修改其他代码只需要实现他们的接口就好了劣势1、如果产品很多那就很麻烦了所以工厂模式不太适合产品超过5个的设计
3.原型模式prototype
1) 概述
模式定义允许通过拷贝原始对象的属性创建一个相同的对象而不需要关注这个对象怎么创建的。 解决问题不需要关注怎么创建一个新的对象。 解决方案在Java中年通过实clone()方法在Spring中通过声明bean为Prototype类型来实现。 应用场景通过Java中的clone方法可以根据模板对象克隆一个原型对象这就是原型模式的应用。在使用原型模式的时候要着重关注浅克隆还是深克隆。比较适合创建一个实例化比较复杂的时候比如创建网络链接或数据库连接 原型创建的对象一般会缓存起来在运行时在缓存中获取即可。
2) 具体说明
原型的设计模式在于系统中有一个原型实例之后在需要只需要**复制**他的副本就好了。原型设计模式最初由原型抽象类和原形实现类组成其中最关键的在于要实现原型副本的拷贝在Java中这是很容易实现的直接重写clone方法就好了但这个要注意Java里的深复制和浅复制如果成员变量有对象的话需要实现通过流来实现深复制。之后原型进化出另外一个组件是原型管理器其将原型保存到一个map中等到其他类需要的话再从这个map中拷贝。
3) 代码实现
4) 总结
优势提高实例化对象的性能不需要关注构造函数和初始化的过程一般创建好的原型对象会放在缓存中后续直接从缓存中获取对象即可 。劣势如果类的成员变量引用比较深的话那样clone起来就比较麻烦了参考资料深度分析java设计模式中的原型模式看完就没有说不懂的https://segmentfault.com/a/1190000023831083
4.构建者模式Builder
1) 概述
解决问题当实例化一个对象的时需要配置多个参数并且参数的组合类型还非常多的情况可以考虑使用使用构建者模式。解决方案通过Builder统一给需要的对象来进行构建。应用场景应用于一个实例需要通过配置 多个参数才能构建并且这样的参数搭配有很多种这种情况可以将产品本身和产品的创建解耦产品的创建就交给builder来实现实践中一般构造函数中的参数超过4个就可以考虑使用构建者模式了
2) 具体说明
构建者模式讲的是这样一件事就是如果一个实例有很多类组件或属性共同组成而且没有固定套路这样的的组合有很多种所以就需要一种套餐的形式去构建就像kfc套餐一样汉堡和饮料作为套餐具体类别你可以再选择
构建者模式有三大组件包括builder接口类、builder实现类还有director。他们的逻辑关系是这样的builder实现类负责组合各类产品最合成一个套餐这个套餐其实在他的接口中就已经制定好了而director就负责构建这样一个套餐 3) 代码实现
简单构建者模式的实现
public class Computer {private final String cpu;//必须private final String ram;//必须private final int usbCount;//可选private final String keyboard;//可选private final String display;//可选private Computer(Builder builder){this.cpubuilder.cpu;this.rambuilder.ram;this.usbCountbuilder.usbCount;this.keyboardbuilder.keyboard;this.displaybuilder.display;}public static class Builder{private String cpu;//必须private String ram;//必须private int usbCount;//可选private String keyboard;//可选private String display;//可选public Builder(String cup,String ram){this.cpucup;this.ramram;}public Builder setUsbCount(int usbCount) {this.usbCount usbCount;return this;}public Builder setKeyboard(String keyboard) {this.keyboard keyboard;return this;}public Builder setDisplay(String display) {this.display display;return this;}public Computer build(){return new Computer(this);}}
}
4) 总结
优势针对很多参数组成的实例将对象的构建和使用分离能够非常灵活的构建一个对象
劣势1.他有一定的局限性就是builder的实例是同一个类别的或者说他是实现同一个接口的2.使用构建者模式进行对象创建适合参数比较多得情况参数较少不建议使用
参考资料秒懂设计模式之建造者模式Builder pattern shusheng007https://zhuanlan.zhihu.com/p/58093669
结构性模式
5.适配器模式adapter
1) 概述
解决问题已有的对象和需要的对象无法直接对接需要通过适配器来进行中转适配。 解决方案适配器继承或者依赖适配者在适配器中实现需要提供的功能 使用场景适配器类的使用场景还是很广的 在SpringMVC中就有广泛的使用比如Handler和HandlerAdapter的关系
2) 具体说明
主要角色
适配器接口类规定适配器需要实现的接口方法适配器类为目标类实现功能匹配的类适配者接口类目标类原始还未适配的类的接口适配者类目标类的实现类
适配器模式是利用一个适配器类来将接口无法适配的类对接起来。常用组件是一个适配器类和一个适配器接口类外加一个适配者类适配者类上面可以有个是适配者类接口要做的就是外部通过适配器就能够直接调用适配者的方法具体实现是适配器类实现适配接口类的方法适配器类接口种定义了外部需要的接口适配器类可以继承适配者这样就能从其身上继承他的方法另一种方式是组合适配者对象引用。总的来说适配器模式的关键在于实现他的适配器接口类继承适配者类。他的UML类图如下所示 3) 代码实现
4) 总结
优势1、可以通过一个适配器适配多个适配者这样可以弥补前期设计没有考虑周全的问题 劣势 加了中间一层适配器类转发导致代码关系变复杂了 一文彻底弄懂适配器模式(Adapter Pattern)https://segmentfault.com/a/1190000040524953
6.装饰者模式decorator
1) 概述
解决问题在不改变目标类的前提下拓展功能。 解决方案通过将目标类包装在修饰器内在能够实现目标类的功能同时修饰器类也能拓展其他功能 应用场景装饰者设计模式在Java IO中运用的十分普遍为什么在IO中引用普遍呢在于IO为了兼顾不同应用场景和需求有太多不同类型的IO流了所以利用修饰者模式的话只需要在基础IO流上进行功能补充就好了
2) 具体说明
主要组件
构建接口目标类的接口类定义目标类需要实现的功能 具体构建类构建接口的具体实现 修饰器接口持有对构建类的引用并实现了构建接口的方法能够统一对外提供目标类的方法 具体修饰器类实现了修饰器接口作为修饰器具体实现类还会新增其他功能
修饰者模式又称为包装器模式出现的原因在于有在基础类上进行增加功能的需求如果直接修改当然违背了对修改闭合的原则所以就想出了在原本的类上新增特性的修饰者类。实现该种模式的逻辑是原始的被目标类实现对应的接口修饰者也实现这个接口当然这不是真正的修饰者类其真正的修饰者类继承了修饰者接口将其补充功能在真正的修饰者类中实现。 3) 代码实现
4) 总结
优势1、修饰者是类似于继承的一种增强其他类的一种方式但是他更灵活要增加什么功能可以自己增加2、通过配置和运行时动态生成的方式可以让他变得更灵活 劣势变复杂了
7.门面模式facade
1) 概述
解决问题访问系统中存在多个子系统访问起来非常复杂解决方案为客户端提供一个统一的门面类型之后只需要访问门面即可访问子系统中方法使用场景Spring的日志框架中用到了slf4j统一了丰富多样的日志实现
2) 具体说明
主要角色
门面类通过门面统一向外界提供服务 子系统接口规定子系统需要实现的逻辑 子系统类实现子系统接口实现各自的业务逻辑 门面模式又称外观模式用以解决在多个外部系统要和多个内部系统进行通信可能存在非常多的联系提升系统交互的复杂度通过引入门面统一负责和外部系统的通信减少系统的复杂程度在门面模式中存在门面和子系统两个角色。 3) 代码实现
4) 总结
优点1.化繁为简将对多个不同的子系统访问转换为会单个门面的访问缺点1.违反了开闭原则组件间相互依赖修改子系统会涉及修改门面
8.代理模式proxy
1) 概述
解决问题通过代理类来实现对委托类的操作可以出现在委托类无法获得或者不便获得也可以用以增强对委托类的操作
解决方案JDK和Spring源码中有很多实现
2) 具体说明
主要角色
委托者接口定义目标类需要实现的方法 委托者实现具体实现委托类中的方法 代理者代理类中有委托类的引用在代理类中也需要实现委托类的方法所以可以执行委托类的本身的方法外除此之外还能够在该方法前后进行增加
代理模式有3个组件包括委托者接口、委托者还有代理者他们的关系是定义一个委托者接口委托者和代理者都要实现他的方法在代理类中还需要创建委托者的对象引用这样在对委托者类方法进行重写时候可以直接调用。动态代理的UML类图 代理模式经常用在1委托类不想被直接调用可以通过调用他的代理类来实现像房产中介一样2还有一种情况是可以增强委托类的能力像Java中的动态代理这中在spring aop中应用广泛
3) 代码实现
4) 总结
优势降低调用者和被调用者的耦合关系怎么说呢就是被调用者想要拓展新功能可以在代理类中实践不需要在自身类中进行修改符合设计模式的开闭原则
劣势1对于JDK的动态代理他需要委托类有接口通过CgLib来动态代理可以不需要
行为型模式
9.责任链模式chain of responsibility
1) 概述
解决问题一条处理链中的每个角色都能够处理请求避免请求方和相应方的耦合关系沿着这条处理链处理请求直到最后处理得到结果。使用场景Spring的Filter中使用了责任链这个适合于可以进行一系列链式处理的场景
2) 具体说明
对于处理流程是线性的比较合适每个handler中包含目前节点需要处理的业务也包括下一个节点的引用。 3) 代码实现
4) 总结
10.观察者模式Observer
1) 概述
2) 具体说明
观察者模式又称订阅发布模式所以他适合发布订阅的场景当目标对象有事件发生就会通知观察者。 3) 代码实现
4) 总结
四、代码实现
GitHubhttps://github.com/yangnk/MyComputerScience/tree/07f4ea1e6c06437ba5fa552a288e67a1adae3cf9/src/main/java/designPattern
TODO
需要完善已经写的设计模式需要补充新的还未加上的设计模式
参考资料
类图、时序图怎么画https://design-patterns.readthedocs.io/zh_CN/latest/read_uml.html#id2 设计模式gitbook上的一本书讲的很好https://gof.quanke.name 菜鸟教程上的教程http://www.runoob.com/design-pattern/design-pattern-tutorial.html 本文由博客一文多发平台 OpenWrite 发布