作用:实例化对象交由工厂类来负责,使客户端代码与实际对象管理松耦合。
适用场景:客户端不感知具体的实现功能的对象实例,由工厂类创建,客户端只专注于调用自身想要的方法即可。可用于解耦provider有多种实现的情况。
案例:计算器的加减乘除等算法,后端就可以通过工厂模式与前端解耦。
作用:定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响到使用算法的客户
适用场景:适用于有多个不同算法实现同一功能的场景。
案例:商场促销有打折、返现、积分等多种方式,也就是多种实现策略。
作用:装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
适用场景:
1.想要在单个对象中动态并且透明地添加责任,⽽这样并不会影响其他对象
2.想要在以后可能要修改的对象中添加责任
3.当⽆法通过静态⼦类化实现扩展时
案例:比如穿衣服
作用:为其他对象提供一种代理以控制对这个对象的访问。
适用场景:一、为了隐藏真实对象。二、为了在代理时完成一些其他的附带工作,比如打日志、计算耗时等。三、为了权限控制,可以通过代理做权限控制。
案例:spring-AOP的动态代理。nginx的反向代理。
作用:定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到了其子类。
适用场景:它是简单工厂模式的进一步抽象,相当于把简单工厂模式中工厂类创建示例的部分,进一步抽象了,降低了每次变化都需要修改工厂类的风险,每次修改不必再修改工厂类,而是新增工厂接口子工厂。符合开放封闭原则
每一个具体工厂只能生产一种产品,这个问题可由抽象工厂模式解决。
案例:参考学习:工厂方法模式(详解版)
作用:用原型实例创建对象的种类,并且通过拷贝这些原型创建新的对象。
适用场景:适用于初始化的信息不发生变化的场景,就可以直接克隆。这样隐藏了创建对象的细节。
案例:Java中提供的Cloneable接口,就是在使用原型模式。
作用:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
适用场景:当子类中的实现具有多变和不变的的代码混在一起时,就可以提取出不变的部分抽象到父类中,而可变的部分就抽象一个模板方法,由子类去各自实现。
案例:业务中经常会用在一个bizService中,建立一个执行方法的list并调用,但实际实现在子类中,父类要么写默认方法,要么写空方法,客户端直接通过子类对象调bizService即可。
作用:对系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
适用场景:隐藏多个接口的组合,由一个高层的接口来完成这个组合的过程,客户端不感知这个组合过程。
案例:使用很常见的模式,比如MVC,每一层与另一层其实都会写很多方法封装来隐藏底层接口的组合,比如你要组装数据,数据源需要查多张表,那DAO层的组合就可以封装在service层里,客户端只知道基于功能调用service层即可。
作用:将一个复杂对象的构建与他的表示分离,使得同样的构建过程可以创建不同的表示。
适用场景:当创建复杂对象的算法,应该独立于改对象的组成部分以及他们的装配方法时使用。
案例:画胖小人、瘦小人
作用:所谓观察者模式,即有一个类作为观察者,观察到某个目标的变化,即通知其他订阅监听了目标状态的类。
适用场景:适用于多个对象需要监听某个目标对象的状态,以便在发生变化时实时做出某些动作的场景。
案例:类似zookeeper等中间件,还有一些即时生效的配置管理中间件,都是基于观察着模式,由各自应用中的类统一实现一个监听接口,在配置变更时可以立刻通知到每个应用实例中进行数据更新。
作用:抽象工厂模式是由于工厂方法模式在工厂类中。
适用场景:。
案例:
作用:当一个对象的状态改变,需要改变其行为时,将每个状态的逻辑下沉到每个子类中处理,这样在修改某个状态的行为时,不会影响到其他状态。
适用场景:适用于对象的状态很多且每个状态都有不同行为的场景。
案例:全天早中晚工作精力不同,状态不同导致行为不同。
作用:如其名,适配器就是一个用来适配之前不适用的接口的工具,如某个接口入参出参与现在的调用者不同,在不改接口的前提下,通过适配器来调,这样就不需要改接口的实现和定义了。
适用场景:新用户接入老接口但是接口不匹配,架构升级老接口升级等老接口不匹配。
案例:json的调用方适配xml的接口,调用微信支付的接口需要支持调用支付宝支付接口。
作用:存储某个对象某个历史时点的状态。
适用场景:保存某个对象的历史状态,在需要的时候进行恢复回滚,并且保证对象的密封性。
案例:游戏存进度。
作用:一群人是一个人的组合,当我们希望对一群人的操作和一个人的操作都统一时,就可以使用组合模式了。
适用场景:适用于父类、子类具有相同的一些行为的结构,如公司–子公司。
案例:比如一个公司、分公司、部门都有相同的行为:招聘、入职、团建等等,就可以通过组合模式。
作用:目的针对集合对象进行迭代处理,这个应该所有程序员都很熟悉了,for循环、while循环、iterator迭代器等等现在已经是面向对象语言的基础语法了。
适用场景:循环迭代处理集合类对象。
案例:for循环、while循环、Iterator迭代器。
作用:如果想要在整个运行环境中保证只有一个对象实例存在,那就需要用到单例模式。
适用场景:适用于全局只需要一个实例的情况,或者没必要每次都创建新实例的情况,因为有的时候创建的这个实例不是我们的最终目的,调用其方法、或者取其通用的一些属性才是目的,那就没必要每次都创建新的实例去获取了。
案例:如spring中的bean,基本都是单例的,因为我们主要是为了调用bean的一些行为,没有必要每次都创建新的实例,并且这样我们还能共享一些通用变量。
作用:说白了就是将统一的行为抽象成一个接口,不同子类去继承实现,以获取不同的实现,但是一个对象可能有很多种统一的行为,那就需要定义很多接口,然后通过标准化接口+个性化实现的方式,去实现我们想要的功能。
适用场景:不同的实例针对同一个行为有不同的实现。
案例:比如手机都有打电话、发短信、微信、支付宝等等功能,也就是行为,但是苹果、安卓、华为系统不一样,那就需要支付宝提供统一的对接接口,然后通过不同的实现基于不同的系统实现功能。
作用:将请求记录下来,以便于针对请求进行一些修改、记录、回退等操作。
适用场景:需要针对请求做一些处理的情况,如记日志、回退等。
案例:一般的消息中间件都有消息持久化,不仅可以事后查看,还可以失败重试等。
作用:主要就是将处理请求的每一方串成一个链,谁能处理就处理,不能处理就转到下一个,处理完后返回,后面的不用处理。
适用场景:审批场景;每个处理程序能力不同,不一定每次请求到谁可以处理完。
案例:审批,有些审批到主管即可,有些需要到经理,有些需要到总经理。
作用:提供中介能力,让访问者不直接接触实现者。
适用场景:访问者不需要知道具体实现者,或者两者需要解耦的情况。
案例:房产中介,中介知道所有的房屋提供者,也知道所有的买房人,由他来对接合适的双方。
作用:共享对象,类似单例,也算是享元的一种方式,只要大家需要的是一样的内容,那么没必要创建大量重复的实例,共享即可。
适用场景:创建的对象比较复杂,并且重复使用的部分多,那么重复的部分就可以使用享元模式。
案例:jsp页面中大部分静态内容都可以享元,动态部分插入参数即可,不用每次都需要构建生成全新的页面。
作用: 简单理解,用于解释一段逻辑,或者语法,或者文本。
适用场景:需要针对一类特定的文法进行一些表达上的转换的场景,使复杂问题按我们的期望方式进行表述或者理解。
案例:正则表达式,如怎么判断数字,怎么判断英文字符,怎么判断中文字符,怎么判断标点符号。
作用:在频繁变更状态的情况,不想改变某个类,通过访问者模式,新增某个行为,你可以理解为switch-case的升级版,不需要每次都新增case。
适用场景:行为变更,但是不想直接修改类实现,通过访问者模式去定义新的行为操作。
案例:switch-case不想每次都新增case,那就通过这样的方式新增行为。
封装,继承,多态
就一个类而言,应该仅有一个引起它变化的原因。
单一职责原则是为了防止一个类承载太多能力,导致其中一个能力发生变化修改时,会影响到其他能力。
软件实体(类、模块、对象)应该可以扩展,但是不可修改。
两个特征:对于扩展是开放的,对于修改是封闭的。
类似于中国的一个国家,两种制度,大陆的共产主义不可更改,但也不能强制要求港澳台完全变更过来,可以看做一种扩展。
高层模块不应该直接依赖低层模块,两者都应该依赖抽象,比如我们的service、dao层,都会使用接口+继承的方式实现。
抽象不应该依赖细节,细节应该依赖抽象。比如我们要调用一个功能,不应该依赖于具体功能的实现,应该依赖它的抽象,也就是接口。
子类型必须能够替换掉他们的父类型。
是多态的一种表现。
如果两个类不必彼此直接通信,那么就不应该发生直接的调用,应该通过第三者进行转发。
符合封装和松耦合的原则。
在学习了各种模式之后,你会发现很多种模式在你开发的过程中或是模仿,或是自创,有意无意都用过,其过程无非是从一段简单代码到慢慢复杂,然后因为维护不方便开始重构,基于各种实现场景,使用不同的结构整合、逻辑拆分等手段,产生了一种适用于当下场景的“设计模式”。所以高手往往不会拘泥于什么场景套用什么设计模式,就是按照各种简单、易维护、可读性等原则目标,去活用某种设计模式甚至某多种设计模式搭配使用。