设计模式小结

本文总结了设计模式中的创建型、结构型和行为型模式,包括工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式、适配器模式、桥接模式、过滤器模式、组合模式、装饰器模式、外观模式、享元模式、代理模式、责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、空对象模式、模板方法模式、访问者模式、MVC模式、组合体模式、数据访问对象模式、前端控制器模式、拦截器模式、服务定位模式、传输对象模式、业务封装及设计原则等。通过对这些模式的理解和应用,可以提高代码的可扩展性和可维护性。
摘要由CSDN通过智能技术生成

开始的毛病:变量命名不规范,if-else判断有的代码做无用功,代码健壮性太差,没有做try-cath异常处理

工厂模式(创建型模式):

创建对象接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建延伸到子类进行
主要解决接口选择问题,明确计划不同条件下执行创建不同实例
通过子类实现工厂实例,创建过程在其子类执行
优点:提高扩展性,屏蔽产品具体实现,调用者只关心产品接口; 缺点:增加一个产品,会导致系统中类个数增加,造成系统复杂度
使用场景:
1.日志记录:用户选择将日志记录到磁盘/系统事件/远程服务器
2.数据库访问:系统采用不同的数据库
3.设计连接服务器的框架, 比如针对pop3, imap, http设计接口
注:工厂模式作为类的创建模式, 复杂的对象使用工厂模式, 简单对象使用new, 而非工厂模式
简单工厂:一个工厂类,一个产品抽象类
工厂方法:多个工厂类,一个产品抽象类
抽象工厂:多个工厂类,多个产品抽象类

采用松耦合,多态的方式,使得我想要哪一个功能,就生成相应对象, 问题的考虑方向只需放在要实例化哪个类,要增加哪一项功能
也可以使用枚举的方式, 实现工厂模式: 将每个工厂实例作为枚举对象,通过枚举工厂进行调用

抽象工厂模式(创建型模式,其他工厂的工厂):

接口只负责创建一个相关的对象的工厂,不需要显式指定类,工厂模式就能按照工厂模式提供对象(多态)
用于解决接口选择问题
优点:当产品族中,多个对象被设计成一起工作,能保证客户端只使用一个产品族中对象
缺点:产品族中扩展产品,需要在抽象类中添加代码, 还需要在具体实现里面添加代码
懂得一点,使用设计模式, 先搞定UML
建立多个工厂, 然后建立一个总的工厂,通过总的工厂调用下属,主要还是多态的性质运用, 程序中还有很多瑕疵
主要还是接口的选择, 以及状态的变化

单例模式(创建型模式):

涉及到的单一的类,该类只负责自己对象的创建,并且只有单个对象被创建,提供唯一的对象访问方式,可直接访问
注: 只能有一个实例作为全局的访问点, 构造函数私有,单例类只能自己创建自己唯一的实例, 必须给所有其他对象提供这一实例;

!!!使用synchronized防止多线程同时创建多个实例

主要用于:控制资源,全局使用的类创建/销毁
优点:只有一个实例,减少资源开销,避免对资源的多重占用(写文件操作)
缺点:没有接口,不能被继承,只关心内部逻辑,不关心外部
使用场景–产品的唯一序列号; web计数器,使用单例将其缓存,不用每次在数据库中刷新; 创建对象消耗资源, 比如IO,数据库连接
懒汉模式/饿汉模式—在/不在类内方法构造实例

建造者模式(创建型模式,使用多个简单对象构建复杂对象):

使用: 基本组件不变,其组合常常在变化, 将变的部分和不变的部分分开
建造者:创建和提供实例, 导演: 管理建造出来的实例的依赖关系
优点:建造者独立,易扩展; 便于控制细节风险
缺点: 产品必须有公共点,范围有限制; 生成对象之间有依赖关系
注: 建造者模式与工厂模式的区别—建造者更关注零件的装配顺序, 将一个复杂的构建过程与其表示相分离, 并不是由建造者负责一切,而是由监工负责控制(定义)一个复杂的构建过程,由各个不同的建造者分别实现构建过程所用到的构建步骤

原型模式(创建型模式,创建重复对象且保证性能):

该模式创建一个原型接口,此接口用于创建对象的克隆. 例:将一些高代价的对象进行缓存,在下一次请求创建的时候返回他的克隆, 减少资源开销
优点: 性能提高,逃避构造函数的约束
缺点:配备克隆操作需要对类的功能全盘考虑,对已有的类不一定很容易,特别是当一个类饮用不支持串行化的间接对象,或者引用含有循环结构; 必须实现Cloneable接口
什么时候使用–一个系统应该独立立于它的产品创建,构成,表示; 实例化的类是在运行时指定,如动态装载; 为了避免创建一个和产品类层次平行的工厂类层次时; 当一个类的实例只能有几个不同状态组合中的一种时,
使用场景–
1.资源优化, 类加载需要消耗很多资源, 性能和安全要求高的场景
2.通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模型
3.一个对象,多个修改者
4.大多数眼型模式伴随工厂模式出现,通过clone方法创建一个对象,然后由工厂方法提供给调用者
注:原型模式通过拷贝一个现有对象生成新对象, 浅拷贝实现Clonable接口, 重写clone方法, 深拷贝通过实现Serializable读取二进制流
//
原型角色:定义用于复制现有的实例来生成新的实例的方法(实现Cloneable接口的类)
具体原型角色:实现用于复制现有实例来生成新实例的方法(具有clone()方法的类)
使用者角色:维护一个注册表, 提供获取clone的类

适配器模式(结构型模式):

是作为两个不兼容的接口之间的桥梁,结合两个独立的接口; 这种模式涉及到一个单一的类, 该类负责加入独立的或不兼容的接口的功能; 例如读卡器连接内存卡与笔记本
实现方式: 一般通过适配器继承或者以来已有对象, 实现想要的目标接口
优点: 可以让两个没有关系的接口/类一起运行, 提高类的复用性, 增加类的灵活性
缺点:
过多使用适配器造成系统凌乱, 例如:表面上使用A接口,适配器却将A改为B接口,造成接口使用的混乱, 因此如果不是有必要的, 可以不使用适配器, 而是直接对系统重构
由于java单继承, 当适配类的时候, 只能适配一个类(为抽象类);
注: 适配器主要是用与解决正在服役的项目的问题, 不是在类详细设计的时候添加

桥接模式(结构型模式):

抽象类依赖实现类,用于把抽象化与实现化解耦,使二者可以独立变化, 提供抽象化和实现化直接的桥接结构; 使得实体类的功能能独立于接口实现类
主要解决类继承造成的爆炸问题,应对类的多种变化, 便与扩展; 实现系统多个角度分类,每一个角度都可能会变化
优点:抽象与实现的分离, 优秀的扩展功能, 实现细节对客户透明
缺点: 增加系统设计理解难度,由于聚合关系建立在抽象层,要求针对抽象进行设计与编程
使用场景:

  1. 系统需要在构建的抽象化角色和具体角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系, 通过桥接模式使得他们在抽象层建立一个关联关系
  2. 避免因继承,或多层次继承导致系统类的个数急剧增加2.避免因继承,或多层次继承导致系统类的个数急剧增
  3. 一个类存在两个独立变化的维度, 且两个维度需要进行扩展3.一个类存在两个独立变化的维度, 且两个维度需要进行扩展

类的功能层次结构:父类具有基本功能,子类增加新的功能类的功能层次结构:父类具有基本功能,子类增加新的功能
类的实现层次结构:父类通过声明抽象方法定义接口,子类通过实现具体的方法来实现接口
桥接模式的角色:
抽象化角色:实现者角色提供的接口来定义基本功能接口,持有实现者角色,并在功能中委托给他,起到搭建桥梁的作用, 抽象化角色非抽象类,而指抽象了实现
改善后的抽象化角色:作为抽象化角色的子类,增加新功能,增加新的接口,与其构成类的功能层次结构
实现者角色:提供用于抽象化角色的接口,它是一个抽象类/接口
具体实现者角色:作为实现者角色的子类,通过实现具体方法来实现接口,与其构成类的实现层次结构

过滤器/标准模式(结构型模式):

通过不同的标准来过滤一组对象,通过逻辑运算符以解耦的方式把他们连接起来
在java8中,最典型的应用就是分组操作,根据指定的指标进行分组筛选(如Collectors.groupingBy(Persons::getGender)分组条件为getGender)

组合/整体模式(结构型模式):

就是在一个对象中包含其他对象,这些被包含的对象可能是终点对象(不再包含别的对象),也有可能是非终点对象(其内部还包含其他对象,或叫组对象),
我们将对象称为节点,即一个根节点包含许多子节点,这些子节点有的不再包含子节点,而有的仍然包含子节点,以此类推。
通过组合的方式(在对象内部引用对象)来进行布局,我认为这种组合是区别于继承的,而另一层含义是指树形结构子节点的抽象(将叶子节点与数枝节点抽象为子节点),区别于普通的分别定义叶子节点与数枝节点的方式。
主要解决:在树型结构的问题中,模糊了简单元素和复杂元素的概念, 客户程序处理复杂元素如同简单元素,使客户程序与复杂元素的内部结构解耦;表示对象的部分-整体层次结构, 用户忽略组合对象与单个对象的不同,用户统一使用组合结构中的所有对象
优点:高层模块调用简单,节点自由增加
缺点:由于叶子和树枝声明为实现类,而非接口, 违反依赖倒置原则
注: 通常树枝内部组合接口, 含有List,里面具有Component

装饰器模式(结构型模式):

允许向一个现有的对象添加新的功能,同时不改变其结构(作为现有类的一个包装);
动态为对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类更加灵活;
一般情况,为扩展一个类经常使用继承,相反,子类会变得很膨胀, 应该将具体功能划分,同时继承装饰者模式
优点:装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式就是继承的一个替代模式,可以动态扩展一个实现类的功能
缺点:多层装饰比较复杂

外观模式(结构型模式):

向客户端提供一个客户端可以访问的系统接口, 类似于中介模式,隐藏系统的复杂性;只涉及到一个单一的类;
为子系统中一组接口提供一个一致的界面,外观模式定义一个高层接口,使得子系统更加容易使用;
此模式用于降低访问复杂系统的内部子系统的复杂度,简化客户端与之的接口
注:在客户端和复杂系统之间再加一层,这一层将调用顺序,依赖关系处理好
优点:减少系统相互依赖, 提高灵活性, 提高安全性
缺点:不符合开闭原则,改写代码很麻烦,继承重写不适合
使用场景:为复杂系统的模块或子系统提供外界访问的模块;子系统相对独立;

享元模式(结构型设计模式):

用于减少创建对象的数量,以减少内存占用和提高性能;尝试重用现有的同类对象,未找到匹配对象,则创建新对象;运用共享技术有效地支持大量细粒度的对象, 类似于单例模式
主要解决: 有大量对象时,可能造成内存溢出,把共同部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建; 一般使用HashMap存储这些对象
优点:大大减少对象的创建,降低系统的内存
缺点:提高系统的复杂度,需要分离出外部状态,内部状态;外部状态具有固有化的性质,不应该随内部状态的变化而变化
注:注意划分外部状体和内部状态,否则会引起线程安全问题; 这些类必须有一个工厂对象加以控制
该模式优点相似单例模式,都是为了避免创建过多相似对象浪费空间内存资源

代理模式(结构型模式):

一个类代表另一类的功能,为其他对象提
供一种代理以控制对这个对象的访问(即代理权),使用在想访问一个类时做一些控制
一般添加中间层解决代理问题
,比如:复制粘贴的快捷方式
注:
1.与适配器模式的区别: 适配器主要是考虑改变对象的接口,而代理模式不能改变所代理类的接口
2.与装饰器模式的区别: 装饰器模式是为了增强功能, 代理模式是为了加以控制
JDK自带动态代理—java.lang.reflect.Proxy生成动态代理类和对象; java.lang.reflect.InvocationHandler可以通过invoke方法实现对真实角色的代理访问

责任链模式(行为模式):

为请求创建一个接受这对象的链,对请求的发送者和接受者进行解耦,通常每个接受者都包含另一个接受者的引用,如果一个对象不能处理该请求,他会把相同的请求传递给下一个接受者,直到找到符合处理当前任务的对象
避免请求者与接受者耦合,让多个对象都有可能接受请求,将对象连接成一条链,沿着这一条链传递请求,直到有对象处理它为止
注:Handler里面聚合他自己,在HanleRequest里面判断是否合适,如果没有达到条件则向下传递,向谁传递之前set进去; JavaWeb中遇到很多应用
优点:减低耦合度,将请求者和接受者解耦,简化对象,使对象不需要知道链的结构, 增强给对象指派职责的灵活性,通过改变链内的成员或者调动他们的次序,允许动态的增加或删除责任,增加新的请求方便
缺点:不能保证请求一定被接收, 系统性能会受到一定影响,在进行代码调试时不方便,会造成循环调用, 不容易观察运行时特征
使用场景–多个对象处理同一个请求,具体处理该请求由运行时刻确定; 在不确定指定接受者的情况下, 向多个对象中提交一个请求; 动态指定一组对象处理请求

命令模式(行为模式):

数据驱动型设计模式,请求以命令的形式包裹在对象中,并传给对象,调用对象寻找可以处理该命令的合适对象,并把该命令传给相应的对象,此对象执行命令
主要解决行为请求者与实现者之间的松耦合,一般情况行为请求者与实现者是紧耦合关系, 在针对记录的撤销重做,事务处理就必须保证松耦合
关键代码: 定义三个角色: 1.received真正的命令执行对象, 2.Command 3.invoker使用命令对象的入口
优点: 降低系统耦合度, 新的命令可以添加到系统中去
缺点:导致系统有过多的具体命令类
使用场景:例:GUI中的按钮, 模拟CMD, 脚本编程

解释器模式(行为模式):

实现一个表达式接口,解释一个特定的上下文,多用于SQL解释,符号处理引擎,主要是还是固定文法的解释
通常构建语法树,定义终结符,非终结符, 构建环境多采用HashMap
该模式使用场景少,对于复杂文法难以维护,引起类膨胀,且解释器通常使用递归调用方法,Java中多采用experssion4J代替

迭代器模式(行为模式):

主要用于顺序访问迭代器中元素,典型的Java中的Iterator
注:迭代器分离了集合对象的遍历行为,做到不暴露集合内部结构,且让外部代码做到透明地访问集合内部的元素

中介模式(行为模式):

降低多个对象与类之间的通信复杂, 此模式提供一个中介类, 该类通常处理不同类之间的通信, 并支持松耦合, 使代码便于维护
使用中介对象封装一系列对象之间的交互方式, 中介者使个对象不需要显式的互相引用, 主要解决对象与对象之间的大量耦合关系
使用场景: 系统中对象之间存在较为复杂的引用关系, 导致他们之间的依赖关系复杂而难以复用该对象; 通过一个中间类封装多个类中的行为, 而又不想生成太多子类
注: 不应当在职责混乱的时候使用

备忘录模式(行为模式):

在不破坏封装性的前提下,捕获一个对象的内部状态,保存一个对象的某个状态, 在合适的情况下恢复此对象; 例如Ctr+Z
注:整个过程一般增加一个备忘录类, 为节约内存,通常使用原型模式+备忘录模式

观察者模式(行为模式):

当对象存在一对多的关系的时候,观察者将一个对象的修改情况自动通知其他的依赖他的对象;广播通知;触发机制链
一般在抽象类中使用ArrayList存放观察者

优点:观察者与被观察者抽象耦合
缺点:当一个被观察对象存在多个观察者,通知所有观察者将会花费较多的时间, 若观察者与被观察者之间存在循环关系,可能会导致死循环通知;观察者模式通知观察者观察目标发生了变化,并没有告诉观察者目标对象是怎样发生变化的
注:java中存在对观察者支持的类, 避免循环引用; 当一个观察者出现错误的时候将会导致系统错误,一般采用异步的方式

状态模式(行为模式):

允许对象在内部状态发生改变的时改变他的行为, 对象看起来修改了他的类, 主要解决对象的行为依赖于他的状态,并根据他的状态改变而改变他的相关行为, 类似于广播通知
通常将具体的状态抽象出来
优点:封装转换原则;枚举所有的状态;可让多个环境对象共享一个状态对象,从而减少系统中对象的个数
缺点:使用不当将会导致系统结构混乱, 不太支持开闭原则, 切换状态将会修改负责状态转换的代码
注:在行为状态受约束的时候使用状态模式,且状态不超过5个

空对象模式:

使用空对象取代null, 取代的过程中并不是对象不存在,而是面对反应的时候不作出任何动作

模板方法设计模式(行为模式):

定义操作中算法的骨架,将通用的算法抽象出来, 抽象类定义算法的方式/模板, 子类按需要重写
优点: 封装不变的部分,扩展变的部分, 行为由父类控制, 子类实现
缺点:每种不同的实现都需要子类去实现, 导致类的个数增加
注:为防止恶意操作, 将模板方法加上final关键字
爷爷(接口)->父亲(抽象类)->儿子(最终实现类); 儿子重写父类方法, 父类重写爷爷方法, 进行方法查找只能去爷爷辈查找,多态的原因去父类中查找, 但是子类重写父类方法, 最终去子类中查找

访问者模式(行为模式):

将数据结构与数据操作分离,解决稳定的数据结构与易变的操作之间的耦合,避免对象的操作污染对象的类, 访问者将访问过程的操作封装到类中
在访问的类里面加一个对外提供接待访问者的接口
优点: 符合单一职责, 良好扩展性,灵活性
缺点:具体元素对访问者公布细节

MVC模式(模式-视图-控制器):

用于应用程序的分层开发
model:代表一个存取数据的对象; view:数据的可视化 controller:控制数据流向模型对象,更新视图,将视图与模型分离开
业务代表模式: 对表示层和业务层解耦, 减少通信或对表示层代码中的业务层代码的远程查询功能
客户端 client: jsp, Servlet, UIJava,选择业务代表
业务代表 BusinessDelegate: 提供对业务服务方法的访问,选择服务
查询服务: 获取相关业务实现, 提供对象对业务代表对象的访问
业务服务: 业务接口,实现业务服务的实体类, 提供实际业务实现逻辑
//将业务访问的服务与用户所需要的服务通过业务代表选择对应的服务

组合体模式:

用在EJB持久化机制中; 一个组合实体是一个EJB实体bean, 代表对象的图解; 当更新一个组合实体时, 内部依赖对象beans会自动更新
组合实体(Composite Entity):主要实体bean, 可以是粗粒的, 或者包含一个粗粒对象, 用于持续生命周期
粗粒度对象(Coarse-Grained Object):此对象包含依赖对象, 具有自己的生命期, 也能管理依赖对象的生命期
依赖对象(Dependent Object): 是一个持续生命期依赖于粗粒度对象的对象
策略(Strategies): 如何实现组合实体
整个过程中层层解耦, 由小到大由底层到上层, 最终的底层实现由依赖对象实现有点像工厂模式/策略模式(负责处理组合体)

数据访问对象模式:

就是将JDBC从高级业务中抽取出来, 不去干扰业务操作
数据对象访问接口(Data Access Object Interface): 定义模型对象执行的标准操作
数据访问对象实体类(Data Access Object concrete class): 实现上述接口
模型对象/数值对象(Model Object/Value Object): get/set方法检索数据

前端控制器模式:

提供一个集中的请求处理机制, 将所有请求交给单一的处理程序(认证,授权,记录日志,跟踪请求)
前端控制器(Front Controller):基于Web应用程序, 基于桌面应用程序
调度器(Dispatcher):使用一个调度对象来调度请求到相应的具体处理程序
视图(view)
与组合模式差不多

拦截器模式:

对程序的请求或响应做出预处理/后处理, 与过滤模式,责任链模式雷同
过滤器(Filter):过滤器在请求之前/之后,执行某些任务
过滤器链(Filter Chain):具有多个过滤器,顺序执行
Target: 目标对象,交由过滤器处理
过滤管理器(Filter Manger):管理过滤器/过滤链
Client:向target发送请求对象

服务期定位模式:

利用缓存技术, 类似于单例模式/原型模式, 避免重复new 服务对象, 造成资源浪费
服务(Service):实际处理请求服务
Context: 带有对要查找对象的引用
缓存(Cache):缓存储存服务的引用,以便重复使用
Client: ServiceLocator调用服务对象

传输对象模式:

用于从客户端向服务端传输带有多个属性的数据(带有get/set方法的POJO类 或者 序列化对象,类)
业务对象(Business Object):为传输对象填充的数据
传输对象(Transfer Object):简单POJO,只有设置/获取属性的方法
客户端(Client):接收传送对象

业务的封装:

让业务逻辑和界面逻辑分开,降低耦合度,使之达到可扩展,可维护
例: 将测试代码, 功能实现代码分开
紧耦合,松耦合
紧耦合:当一个类中含有多个功能,例如Collections,当我修改sort函数, 或者添加功能有可能将其他功能改变,或者对其他功能造成影响,耦合度过高
松耦合:
将类中各个功能抽象出单独的类, 然后每个类又去实现最初的Collections接口,或者继承Collections,将各个功能模块分开,使得功能之间互不影响,就此保证良好的可扩充性
在松耦合的前提下,需要考虑哪些功能需要单独抽象为类,哪些不需要, 不能做没有意义的抽象,说明----面向对象的编程,不是类越多越好, 类的划分只是为了封装, 分类的基础是抽象, 具有相同和功能的抽象集合才是类

策略模式(行为模式):

一个类的行为或算法在运行过程中修改,在相同条件下避免if-else带来的复杂性,以及难以维护,实现同一个接口让算法之间可以做到相互替换
优点:算法自由切换, 扩展性好, 避免多重if-else判断
缺点:策略类增多, 所有策略类需要对外暴露
以相同的方式调用所有的算法,减少各种算法类与使用算法类之间的耦合;还是封装"规则"
基本的策略模式: 具体的策略选择由客户端对象选择吗并没有解除客户端选择判断的压力,使用工厂模式与策略模式结合,将判断过程转移到工厂模式中

单一原则:

一个类中,应该仅有一个引起它变化的原因
一个类承担的职责过多,造成职责耦合,当一个职责变化将会导致其他功能受到影响, 解决方式:将界面与代码逻辑分开

开放封闭原则:

对于扩展是开放的,对于更改是封闭的,面对需求,对程序的改动只用于增加新的代码,而不是改变现有的代码
例:对共同存在的功能抽象为类, 增加功能的时候只需要添加实现类

依赖倒转原则:

高层模型不能依赖低层模型, 两个应该依赖接口; 例如:高层依赖低层, 当复用高层的时候, 就需要改变低层, 造成大量代码改动
抽象不应该依赖细节,细节应该依赖抽象

里氏代换原则:

子类型必须能够替换他们的父类型, 例:鸟类,企鹅类,企鹅类不能继承鸟类(企鹅不会飞),若继承鸟类,造成飞的属性不能被复用
注:此原则保证继承复用成为可能,只有当子类可以替换父类,软件的功能单位不受影响,父类才能被真正重用,
子类也可在父类的基础上扩展新的功能
总述:针对抽象编程, 依赖关系都是依赖于抽象类或接口
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值