- 开闭原则
- 开闭原则(Open-ClosedPrinciple,OCP)是指一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。所谓的开闭,也正是对扩展和修改两个行为的一个原则。强调的是用抽象构建框架,用实现扩展细节。可以提高软件系统的可复用性及可维护性。开闭原则,是面向对象设计中最基础的设计原则。它指导我们如何建立稳定灵活的系统,例如:我们版本更新,我尽可能不修改源代码,但是可以增加新功能。
- 依赖倒置原则
- 依赖倒置原则(DependenceInversionPrinciple,DIP)是指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象。抽象不应该依赖细节;细节应该依赖抽象。通过依赖倒置,可以减少类与类之间的耦合性,提高系统的稳定性,提高代码的可读性和可维护性,并能够降低修改程序所造成的风险。
- 单一职责原则
- 单一职责(SimpleResponsibilityPinciple,SRP)是指不要存在多于一个导致类变更的原因。假设我们有一个Class负责两个职责,一旦发生需求变更,修改其中一个职责的逻辑代码,有可能会导致另一个职责的功能发生故障。这样一来,这个Class存在两个导致类变更的原因。如何解决这个问题呢?我们就要给两个职责分别用两个Class来实现,进行解耦。后期需求变更维护互不影响。这样的设计,可以降低类的复杂度,提高类的可读性,提高系统的可维护性,降低变更引起的风险。总体来说就是一个Class/Interface/Method只负责一项职责。
- 接口隔离原则
- 接口隔离原则(InterfaceSegregationPrinciple,ISP)是指用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口。这个原则指导我们在设计接口时应当注意一下几点:1、一个类对一类的依赖应该建立在最小的接口之上。2、建立单一接口,不要建立庞大臃肿的接口。3、尽量细化接口,接口中的方法尽量少(不是越少越好,一定要适度)。接口隔离原则符合我们常说的高内聚低耦合的设计思想,从而使得类具有很好的可读性、可扩展性和可维护性。我们在设计接口的时候,要多花时间去思考,要考虑业务模型,包括以后有可能发生变更的地方还要做一些预判。所以,对于抽象,对业务模型的理解是非常重要的。
- 迪米特法则
- 迪米特原则(LawofDemeterLoD)是指一个对象应该对其他对象保持最少的了解,又叫最少知道原则(LeastKnowledgePrinciple,LKP),尽量降低类与类之间的耦合。迪米特原则主要强调只和朋友交流,不和陌生人说话。出现在成员变量、方法的输入、输出参数中的类都可以称之为成员朋友类,而出现在方法体内部的类不属于朋友类。现在来设计一个权限系统,Boss需要查看目前发布到线上的课程数量。这时候,Boss要找到TeamLeader去进行统计,TeamLeader再把统计结果告诉Boss。
- 里氏替换原则
- 里氏替换原则(LiskovSubstitutionPrinciple,LSP)是指如果对每一个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都替换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。定义看上去还是比较抽象,我们重新理解一下,可以理解为一个软件实体如果适用一个父类的话,那一定是适用于其子类,所有引用父类的地方必须能透明地使用其子类的对象,子类对象能够替换父类对象,而程序逻辑不变。根据这个理解,我们总结一下:引申含义:子类可以扩展父类的功能,但不能改变父类原有的功能。1、子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。2、子类中可以增加自己特有的方法。3、当子类的方法重载父类的方法时,方法的前置条件(即方法的输入/入参)要比父类方法的输入参数更宽松。4、当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的输出/返回值)要比父类更严格或相等。 使用里氏替换原则有以下优点:1、约束继承泛滥,开闭原则的一种体现。2、加强程序的健壮性,同时变更时也可以做到非常好的兼容性,提高程序的维护性、扩展性。降低需求变更时引入的风险。
- 合成复用原则
- 合成复用原则(Composite/AggregateReusePrinciple,CARP)是指尽量使用对象组合(has-a)/聚合(contanis-a),而不是继承关系达到软件复用的目的。可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。继承我们叫做白箱复用,相当于把所有的实现细节暴露给子类。组合/聚合也称之为黑箱复用,对类以外的对象是无法获取到实现细节的。要根据具体的业务场景来做代码设计,其实也都需要遵循OOP模型。
- 工厂模式BeanFactory
- 装饰器模式BeanWrapper
- 代理模式AopProxy单例模式
- ApplicationContext
- 委派模式DispatcherServlet
- 策略模式HandlerMapping
- 适配器模式HandlerApdapter
- 模板方法模式JdbcTemplate
- 观察者模式ContextLoaderListener
单例模式的应用场景 单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并 提供一个全局访问点。单例模式是创建型模式。
- 简单工厂模式 简单工厂模式(SimpleFactoryPattern)是指由一个工厂对象决定创建出哪一种产品类的实例。
- 工厂方法模式 工厂方法模式(FatoryMethodPattern)是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。
- 抽象工厂模式 抽象工厂模式(AbastractFactoryPattern)是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。
- 饿汉式单例 饿汉式单例是在类加载的时候就立即初始化,并且创建单例对象。绝对线程安全,在线 程还没出现以前就是实例化了,不可能存在访问安全问题。 优点:没有加任何的锁、执行效率比较高,在用户体验上来说,比懒汉式更好。 缺点:类加载的时候就初始化,不管用与不用都占着空间,浪费了内存,
- 懒汉式单例 懒汉式单例的特点是:被外部类调用的时候内部类才会加载
- 注册式单例
注册式单例又称为登记式单例,就是将每一个实例都登记到某一个地方,使用唯一的标 识获取实例。注册式单例有两种写法:一种为容器缓存,一种为枚举登记。
- threadlocal式单例,伪单例模式,线程内单例(保证同一个线程内是单例的) ThreadLocal 不能保证其 创建的对象是全局唯一,但是能保证在单个线程中是唯一的,天生的线程安全。 ThreadLocal 将所有的对象全部放在 ThreadLocalMap 中,为每个线程都提供一个对象
原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些 原型创建新的对象。 原型模式主要适用于以下场景: 1、类初始化消耗资源较多。 2、new 产生的一个对象需要非常繁琐的过程(数据准备、访问权限等) 3、构造函数比较复杂。 4、循环体中生产大量对象时。
- 静态代理 动态代理和静态对比基本思路是一致的,只不过动态代理功能更加强大,随着业务的扩 展适应性更强。
- 动态代理
- JDK动态代理
- CGLib动态代理 CGLib 代理的目标对象不需要实现任何接口,它是通过动态继承目标对象 实现的动态代理 CGLib 动态代理执行代理方法效率之所以比 JDK 的高是因为 Cglib 采用了 FastClass 机 制,它的原理简单来说就是:为代理类和被代理类各生成一个 Class,这个 Class 会为代 理类或被代理类的方法分配一个 index(int 类型)。这个 index 当做一个入参,FastClass 就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,所以调用效率比 JDK
- 动态代理通过反射调用高。 CGLib 和 JDK 动态代理对比 1.JDK 动态代理是实现了被代理对象的接口,CGLib 是继承了被代理对象。 2.JDK 和 CGLib 都是在运行期生成字节码,JDK 是直接写 Class 字节码,CGLib 使用 ASM 框架写 Class 字节码,Cglib 代理实现更复杂,生成代理类比 JDK 效率低。 3.JDK 调用代理方法,是通过反射机制调用,CGLib 是通过 FastClass 机制直接调用方法, CGLib 执行效率更高。
- 静态代理和动态的本质区别
- 1、静态代理只能通过手动完成代理操作,如果被代理类增加新的方法,代理类需要同步 新增,违背开闭原则。
- 2、动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开 闭原则。
- 3、若动态代理要对目标类的增强逻辑扩展,结合策略模式,只需要新增策略类便可完成, 无需修改代理类的代码。
- 代理模式的优缺点
- 1、代理模式能将代理对象与真实被调用的目标对象分离。
- 2、一定程度上降低了系统的耦合度,扩展性好。
- 3、可以起到保护目标对象的作用。
- 4、可以对目标对象的功能增强。 缺点的:
- 1、代理模式会造成系统设计中类的数量增加。
- 2、在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。
- 3、增加了系统的复杂度。
委派模式(Delegate Pattern)的基本作用就是负责任务的调 度和分配任务,跟代理模式很像,可以看做是一种特殊情况下 的静态代理的全权代理,但是代理模式注重过程,而委派模式 注重结果。
策略模式(Strategy Pattern)是指定义了算法家族、分别封 装起来,让它们之间可以互相替换,此模式让算法的变化不会 影响到使用算法的用户。
- 模板模式通常又叫模板方法模式(Template Method Pattern)是指定义一个算法的骨架,并允许子类为一个或者 多个步骤提供实现。
- 模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。
- 1、一次性实现一个算法的不变的部分,并将可变的行为留给 子类来实现。
- 2、各子类中公共的行为被提取出来并集中到一个公共的父类 中,从而避免代码重复。
- 适配器模式(Adapter Pattern)是指将一个类的接口转换成 客户期望的另一个接口,使原本的接口不兼容的类可以一起工 作。
- 1、已经存在的类,它的方法和需求不匹配(方法结果相同或相似) 的情况。
- 2、适配器模式不是软件设计阶段考虑的设计模式,是随着软件维护, 由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决 方案。
-
装饰者模式(Decorator Pattern)是指在不改变原有对象的 基础之上,将功能附加到对象上,提供了比继承更有弹性的替 代方案(扩展原有对象的功能)。
-
1、用于扩展一个类的功能或给一个类添加附加职责。
-
2、动态的给一个对象添加功能,这些功能可以再动态的撤销。
-
3、优点
-
1、装饰者是继承的有力补充,比继承灵活,不改变原有对象 的情况下动态地给一个对象扩展功能,即插即用。
-
2、通过使用不同装饰类以及这些装饰类的排列组合,可以实 现不同效果。
-
3、装饰者完全遵守开闭原则。
装饰者模式 适配器模式 形式 是一种非常特别的适配器模式 没有层级关系,装饰器模式有层级关系 定义 装饰者和被装饰者都实现同一个接 口,主要目的是为了扩展之后依旧保留 OOP 关系 适配器和被适配者没有必然的联系,通 常是采用继承或代理的形式进行包装 关系 满足 is-a 的关系 满足 has-a 的关系 功能 注重覆盖、扩展 注重兼容、转换 设计 前置考虑 后置考虑
- 观察者模式(Observer Pattern)定义了对象之间的一对多 依赖,让多个观察者对象同时监听一个主体对象,当主体对象 发生变化时,它的所有依赖者(观察者)都会收到通知并更新。
- 1、观察者和被观察者之间建立了一个抽象的耦合。
- 2、观察者模式支持广播通信。
| 设计模式 | 一句话归纳 | 举例 |
|---|---|---|
| 工厂模式(Factory) 单例模式(Singleton) 原型模式(Prototype) | 只对结果负责,封装创建过程 | BeanFactory、Calendar |
| 代理模式(Proxy) | 保证独一无二。 | ApplicationContext、Calendar |
| 委派模式(Delegate) | 拔一根猴毛,吹出千万个。 | ArrayList、PrototypeBean |
| 策略模式(Strategy) 模板模式(Template) 适配器模式(Adapter) | 找人办事,增强职责。 | ProxyFactoryBean、JdkDynamicAopProxy、CglibAopProxy |
| 装饰器模式(Decorator) | 干活算你的(普通员工),功劳 算我的(项目经理)。 | DispatcherServlet、BeanDefinitionParserDelegate |
| 观察者模式(Observer) | 用户选择,结果统一。 | InstantiationStrategy |
| 模板模式(Template) | 流程标准化,自己实现定制。 | JdbcTemplate、HttpServlet |
| 适配器模式(Adapter) | 兼容转换头。 | AdvisorAdapter、HandlerAdapter |
| 装饰器模式(Decorator) | 包装,同宗同源。 | BufferedReader、InputStream、OutputStream、HttpHeadResponseDecorator |
| 观察者模式(Observer) | 任务完成时通知。 | ContextLoaderListener |
| Spring思想 | 应用场景(特点) | 一句话归纳 |
|---|---|---|
| OOP | Object Oriented Programming(面向对象编程)用程序归纳总结生活中一切事物。 | 封装、继承、多态。 |
| BOP | Bean Oriented Programming(面向Bean编程)面向Bean(普通的java类)设计程序。 | 一切从Bean开始。 |
| AOP | Aspect Oriented Programming(面向切面编程)找出多个类中 AOP 有一定规律的代码,开发时拆开,运行时再合并。面向切面编程,解耦,专人做专事。 即面向规则编程。 | 解耦,专人做专事。 |
| IOC | nversion of Control(控制反转)将new对象的动作交给Spring管理,并由Spring保存已创建的对象(IOC容器)。 | 转交控制权(即控制权反转) |
| DI/DL | Dependency Injection(依赖注入)或者Dependency Lookup(依赖查找)依赖注入、依赖查找,Spring不仅保存对象与对象之间的关联关系,注入即赋值,主要三种赋值方式,构造方法、set赋值、直接赋值(反射) |