前言:

整理自:尚硅谷设计模式

一、设计模式需遵守:7大基本原则

1.单一职责原则

【理解】对类来说,即一个类只应该负责一项职责。如A类负责多个职责,那么应该将A类拆分为多个A1.A2.A3…类来分别执行某一个职责。

【深入】对于一个复杂的功能,也可以利用这种思想,将这个复杂功能进行细粒度拆分,逐个完成拆分后的任务,这样开发和设计起来更加高效,更不容易出错。

【单一职责原则注意事项和细节】

1.降低类的复杂度,一个类只应负责一项职责

2.提高类的可读性,可维护性

3.降低变更引起的风险

4.通常情况下,都应当遵守单一职责原则,只有逻辑足够简单,才可以在代码级别违背次原则:只有在类中方法数量足够少时,在方法级别上保持单一职责原则

2.接口隔离原则

【概念】一个类不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最少接口上

【理解】A依赖B接口(B接口有5个方法)的2个方法,那么应当将B拆分为C接口(A依赖的那两个接口),剩下的3个方法在D接口中。如果E类依赖D接口中的1个方法,那么要将D接口再拆分,同上。此时A依赖的接口与E依赖的接口相互隔离互不影响。

3.依赖倒置原则

【抽象】:指的是接口或抽象类
【细节】:指的是实现类

【特点即理解】
1.高层模块不应该依赖低层模块,二者都应该依赖其抽象(接口或抽象类),不要去依赖具体的子类,这样抽象就相当于一个缓冲层

2.抽象不应该依赖细节,细节应该依赖抽象。?? 难以理解

3.依赖倒置的中心思想是面向接口编程

4.设计理念:相对于细节的多变性,抽象的接口或类要稳定的多。
以抽象为基础搭建的架构比以细节为基础搭建的架构要稳定的多。

5.使用接口和抽象类目的在制定好规范,不涉及任何具体操作,把实现细节交由子类实现

【依赖传递方式】

1.通过接口参数,不需要成员变量
2.通过构造方法,上层类需要拥有成员变量(即需要依赖的接口对象)
3.通过setter方法,上层类需要拥有成员变量(即需要依赖的接口对象)

【依赖倒置原则注意事项和细节】

1.低层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性会更好

2.变量的声明类型尽量是抽象类和接口(如Controller类引用IService接口),这样我们的变量引用和实际对象之间,就存在一层中间层,利于代码的扩展和优化

3.继承时应遵守【里式替换原则】,如下

4.里式替换原则

【大致解决了继承存在的问题】

1.基类中实现的方法,实际上是在设定规范和契约,虽然他不强制要求子类遵守,但子类对已经实现的这些方法进行任意修改,就会对整个继承体系造成破坏

2.继承给程序设计带来便利的同时,也带来了弊端。
如继承给程序来带了入侵性、程序可移植性降低、增加了对象之间的耦合。
如需要修改基类时,即使考虑所有子类,但也可能造成子类功能出现异常

【概念】对于基类A实现的方法,其子类B.C等都可以完全替换A类来实现,但不影响原有的代码功能。

【理解】子类可以扩展父类的功能,但不能改变父类原有的功能;
通俗的说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法
如果子类强制要重写父类的方法,那么可以再抽象一个基类,为他们的公共父类,或采用依赖、组合、聚合的方式来实现

【特点及总结】
1.子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
2.子类可以增加自己特有的方法
3.当子类的方法重载父类的方法时,方法的前置条件(即方法输入的参数)要比父类的方法更宽松。强调入参
4.当子类实现父类方法时(重载/重写或实现抽象方法),方法的后置条件要比父类的更为严格或相等。强调返回值

5.开放封闭原则

【介绍】
1.是编程中最基础、最重要的设计原则
2.一个类的模块和函数应该是对扩展开放、对修改封闭。用抽象构建框架,用实现扩展细节
3.程序变化时,应当扩展软件实体的行为来进行扩展,而不是通过修改已有代码来实现变化
4.编程中遵循的其他原则以及使用设计模式的目的就是遵循开放封闭原则

6.迪米特法则-(最少知道原则)

【特点及理解】
1.一个对象应该对其他对象保持最少的了解;类与类关系越密切,耦合度越大
2.即一个类对自己依赖的类知道的越少越好。被依赖的类,只提供一个对外的public接口,内部不管实现有多复杂,都应该用private修饰对外不可见
3.即只与直接的类或接口通信

【注意事项和细节】
1.迪米特法则的核心是降低类之间的耦合
2.注意:由于每个类都减少了不必要的依赖,因此迪米特法则只是降低类之间(对象之间)的耦合关系,并不是要求完全没有依赖

7.合成复用原则

【原则】尽量采用合成/聚合的方式,而不是使用继承

这7大原则目的:

使程序具有更好的:

1.代码重用性:

即:相同功能的代码,不用重复编写

2.可读性

即:编程规范,便于其他同事阅读和理解

3.可扩展性(可维护性)

即:需要增加新的功能时非常方便

4.健壮性

即:当新加了功能后对原有的功能不造成影响

5.使具有高内聚、低耦合的特性

即:对于模块内部联系非常紧密;模块与模块之间耦合性很低

这7大原则核心思想:

1.找出应用中可能出现变化的部分,把他们独立出来,不需要和那些变化的代码混在一起
2.针对接口编程,而不是针对实现编程
3.为了交互对象之间的送耦合设计而努力

二、UML类图-统一建模语言

1.介绍

1.1是一种用于软件系统分析和设计的语言工具,帮助开发人员进行思考和记录思路的结果
1.2是一套符号的规定,用这些符号来描述类之间的关系;
比如:类、接口、实现、泛化(继承)、依赖、组合、聚合等

2.种类

2.1用例图
2.2静态结构图:类图(最重要)、对象图、包图、组件图、部署图
2.3动态行为图:交互图(时序图、协作图)、状态图、活动图等

类图具体符号图解如下:
在这里插入图片描述
聚合与组合区别:
组合:属性与类共存亡,比不可少;如人对象和人的头对象
聚合:属性与类的生存周期不一样;如人对象和身份证对象

三、设计模式

掌握设计模式的5个层次

1.刚开始学编程不久,听说过什么是设计模式
2.有很长时间的编程经验,自己也写了很多代码,其中用到了设计模式,但自己却不知道
3.学习过了设计模式,发现自己已经在使用了,并且发现一些新的设计模式挺好用的
4.阅读了很多别人写的源码和框架,在其中看到别人的设计模式,并且能够领会到设计模式的精妙和带来的好处
5.代码写着写着,自己没有意识到就使用了设计模式,并且熟练的写了出来

设计模式分为3大类

1.创建型模式(5种):单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式
2.结构型模式(7种):适配器模式、桥接模式、装饰器模式、组合模式、外观模式、享元模式、代理模式
3.行为型模式(11种):模板方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介模式、备忘录模式、解释器模式(interpreter模式)、状态模式、策略模式、责任链模式。

1.单例模式9种:

1.1 饿汉式(静态常量)
1.2饿汉式(静态代码块)
1.3懒汉式(线程不安全)
1.4懒汉式(同步方法)
1.5懒汉式(同步代码块)
1.6双重检查+volate
1.7静态内部类
1.8枚举
1.9原子类:如下图
在这里插入图片描述

单例模式注意事项和使用说明:
1.单例模式保证了系统内存中,该类只有一个对象,节省了系统资源,对于一些需要频繁创建和销毁的对象,使用单例模式可以提高系统性能
2.当想初始化一个单例类的时候,必须要记住使用方法来获取对象的实例,而不是用new,因为根本new不出来
3.单例模式的使用场景:需要频繁创建和销毁的对象、创建对象耗时过多或耗费资源过多(即重量级对象)、但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂对象等)

2.工厂模式

简单工厂模式(静态工厂模式):

1.简单工厂模式还有一个工厂对象决定创建出哪种类型产品的实例。工厂模式中最简单的一种。
2.简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为
3.使用场景:当会用到大量的创建某种、某类或某批对象时,就会使用到工厂模式

【uml类图解释】
在这里插入图片描述

工厂方法模式:

【特点】定义了个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式是将
对象的实例化推迟到了子类

相比简单工厂模式:当简单工厂模式能够完全满足业务时,使用简单工厂。当创建的一种对象又分几种情况创建时,那么简单工厂就满足不了业务需求了(代码复杂等)。这时候就需要在原有简单工厂创建的对象上,再抽象一个接口,用于其下层对象的创建:

如简单工厂关系:手机={小米,华为},这时候多了子类创建条件按国家来分,此时就难处理了
抽象工厂关系:手机={小米={中国,俄罗斯},华为={中国,俄罗斯}}
【uml类图解释工厂方法模式】
在这里插入图片描述

抽象工厂模式:

【介绍】
1.抽象工厂模式:定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指定具体的类
2.抽象工厂可以将简单工厂模式和工厂方法模式进行整合
3.从设计层面来看,抽象工厂模式就是对简单工厂模式的改进(进一步的进行了抽象)
4.抽象工厂分为两层,AbsFactory(抽象工厂)和具体实现的工厂子类。程序员可以根据创建对象的类型使用对应的工厂子类。这样将单个的简单工厂变成了工厂簇,更有利于代码的维护和扩展。
【类图解释】
在这里插入图片描述

【注意事项】
1.创建对象时不要直接new,而是把这个new的动作放在工厂方法中,并返回对象。
2.不要让类继承具体的类,而是继承抽象类或实现接口
3.不要覆盖基类中已实现的方法

【总结】
简单工厂模式:处理一级对象创建。适用简单业务
工厂方法模式:处理一级和二级对象创建。适用稍复杂业务
抽象工厂模式:处理一级和二级对象的创建。适用稍复杂业务

实战传送门:Java抽象工厂实战

3.原型模式:

【注意事项和细节】
1.创建的对象较为复杂的时候,可以利用原型模式简化对象的创建过程,同时也能够提高效率
2.不用重新初始化对象,而是动态获得对象运行时状态
3.如果原始对象发生变化时(增加或减少属性),其克隆对象也会发生相应的变化,无需修改代码
4.在实现深拷贝的时候可能需要比较复杂的代码
5.【缺点】需要为每一个原型类配一个克隆方法,这对新增的类来说,比较容易,但对已有的类做修改时,就违背了ocp原则

【原型模式的实现】

场景:经典克隆羊例子。spring的bean创建方式

主要有两种实现方式:
浅拷贝:原型类重写object类的clone方法。不会拷贝引用类型的属性,如list,obj对象,只是会拷贝这些引用对象的引用等
深拷贝:原型类需重写object类的clone方法。使用在clone方法对引用对象在做处理或序列化。

4.建造者模式:

介绍:
1.建造者模式,又叫生成器模式,是一种对象构建模式。它可以将复杂的对象建造过程抽象处理来,使这个抽象过程的不同实现方法可以构造出不同表现或属性的对象
2.建造者模式是一步一步创建一个复杂的对象,它允许用户通过制定复杂对象的类型和内容就可以构建他们,用户不需要知道具体的构建细节

【4个角色】
1.product(产品角色):一个具体的产品对象
2.builder(抽象建造者):创建一个product对象的各个部件指定的接口
3.concreteBuilder(实际建造者):实现接口,构建和装配各个部件
4.director(指挥者):构建一个使用builder对象的接口。他主要是用于创建一个复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是:负责控制产品对象的生产过程

【原理图】
在这里插入图片描述

【对应类图】 构建房子为例
在这里插入图片描述

【抽象工厂与建造者模式】
抽象工厂模式实现对产品家族的创建,一个产品家族是这样一系列的产品;具有不同分类维度的组合,抽象工厂不需要关心具体的构建过程,只关心产品是那个工厂生产的。建造者模式更加关注产品的构建过程,

5.装饰器模式:(装饰者模式)

【定义】装饰者模式:动态的将新功能附加在对象上。在对象的扩展方面它比继承更有弹性,装饰者模式也体现了面向对象的核心思想ocp(开放封闭)原则

【原理】
1.装饰者模式就像是打包一个快递
2.component组件:
主体(被装饰者):陶瓷,衣服等
包装(装饰者 Decorator):报纸填充、塑料泡沫、纸板、木板等
3.concreteComponent:具体的主体
Decorator:具体包装
4.component与concreteComponent中间还可以设计一个缓冲层,将共有的部分提取出来,作为一个单独的缓冲层

以定咖啡为例图解装饰者原理:
在这里插入图片描述
装饰者包裹模型:对主体层层包裹
在这里插入图片描述

装饰者要继承被装饰者并且要组合被装饰者

6.代理模式:

【介绍】
1.代理模式:为一个对象提供一个替身,以控制对这个对象的访问;
即通过代理对象访问目标对象。好处:可以在目标对象实现的基础上,增强额外的扩展功能,即扩展目标对象的功能(核心价值)
2.被代理的对象可以是远程对象、创建开销较大的对象或需要安全控制的对象
3.代理模式有三种实现方式:静态代理、jdk动态代理、Cglib动态代理

6.1静态代理-AspectJ

【优缺点】
1.优点:在不修改目标类的情况下,通过代理对象对目标功能进行扩展
2.缺点:因为代理类和目标类都会实现很相同的接口,所以会有很多代理类
一旦接口增加了方法,那么目标类和代理类都需要维护

编译时植入AspectJ

6.2 JDK动态代理

【介绍】
1.代理对象不需要实现接口,但是目标对象要实现接口,否则就不能用动态代理
2.代理对象的生成是用jdk的api动态的在内存中构建代理对象
3.jdk动态代理也叫接口代理

主要用JDK的Proxy.newInstance();

Proxy.newInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler hander);

6.3 CGlib动态代理

【JDK动态代理与CGlib异同】
相比JDK动态代理,CGlib代理的类可以不需要继承接口。
JDK动态代理主要是通过对父类进行继承后实现的代理。
【性能对比】
在jdk 1.7,1.8以前,jdk动态代理性能远不如cglib;但jd,1.7,1.8以后,jdk动态代理性能得到大幅提升,但有些场景还是建议使用cglib
1.CGlib运行时性能远高于jdk动态代理,大约10倍。
2.CGlib在创建对象时花费的时间远大于JDK动态代理,大约是8倍
3.对单例对象或具有池对象的代理,因为无需频繁创建对,所以CGlib更为适合;

性能原因参照如下:
从springaop深入到代理

【介绍】
1.静态代理和JDK动态代理都模式都是要求目标对象实现一个接口,但是有时目标对象只是一个单独的对象,并没有实现任何接口,这时可以使用目标对象的子类来实现代理-这就是CGlib
2.Cglib代理也叫子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能扩展。有final修饰的类不能派生子类,所以不能使用CGlib
3.CGlib是一个强大的高性能的代码生成包,它可以在运行期间扩展java类或实现接口,它广泛的被许多AOP框架使用,如果spring的AOP代理,实现方法拦截
4.在AOP编程中如何选择代理模式:
4.1目标对象需要接口实现:jdk动态代理
4.2目标对象不需要接口实现:CGlib动态代理
5.CGlib是底层是通过字节码处理框架ASM来转换成字节码生成新的类

7.模板方法模式

【介绍】
1.模板方法模式又叫模板模式,在一个抽象类中公开定义了执行它的模板方法,它的子类可以按需要重写方法实现,但调用将以抽象类中的定义来进行
2.简单来说,模板方法定义了一个操作中的算法骨架,而将一些步骤延迟到子类中去执行,使得子类可以不改变一个算法结构,就可以重新定义某些特定的步骤

【以生产豆浆为例子】
在这里插入图片描述
【模板模式钩子方法对上面的改进】
理解:在模板方法模式的父类中,定义一个方法,默认不做任何事情,子类可以视情况去覆盖它,该方法称为“钩子”方法

【模板模式:注意事项和细节】
1.基本思想:算法只存在一个地方,就是父类中,容易修改,一改全改。
2.实现了最大化代码复用,父类的模板方法和某些已经实现的方法可以被子类字节使用
3.即统一了算法,也提供了很大的灵活性。
4.不足:每一个不同实现都需要一个类,导致类的数量变多
5.一般父类的模板方法都要加final,防止子类覆盖
6.使用场景:完成某个过程,这些过程调用顺序基本相同,个别步骤可能不同情况下,可以使用模板方法模式

好像与建造者模式很像?他们有什么区别?

模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。是行为旨在这个事情要怎么做

建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。旨在创建对象

8.观察者模式

【天气预报为例图解观察者模式】
在这里插入图片描述

【使用观察者模式好处】
1.观察者模式设计好后,会以集合的形式来管理用户(Observe),包括注册、移除、 通知
2.这时新增一个观察者,就不需要去修改核心的被观察者。遵守OCP原则

ssl._create_default_https_context = ssl._create_unverified_context
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐