此篇博客是在疫情期间,一直没有开学,认识到了设计模式的重要性,然后通过上网课和自己收集资料认真学习了java的设计模式,然后将其中重要的概念,类图和代码整理了一下,以便以后的查阅,共同学习。由于代码量比较大。大家在浏览的过程中,如果想要每一个设计模式对应类图的代码可以加我QQ:2924582869。
如果看不懂IDEA中画的类图,可以去这个链接:认识IDEA类图中的各种符号
设计模式:设计模式的本质是:提高软件的维护性,通用性和扩展性,并降低软件的复杂度。设计模式并不局限于某种语言各种语言都会使用设计模式。
设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
听别人说过这样一句话:那些被时间沉淀下来的最贱的编程模式,就是设计模式。它有利于提高沟通和设计的效率和质量。
单一职责原则:
一个类应该只负责一项职责
接口隔离原则
客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上
依赖倒转原则
高层模块不因该依赖底层模块,两者都应该依赖其抽象
抽象不应该依赖细节,细节应该依赖抽象
中心思想是:面向接口编程
设计理念:相对于细节的多边性,抽象的稳定性更强。以抽象为基础搭建的基础架构要比以细节为基础搭建的基础架构稳定很多。在java中,抽象指的是接口或者抽象类,细节就是具体的实现类。
里氏替换原则
所有引用基类的方法,必须能透明的使用其子类的对象。
在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法
开闭原则
是编程中最基础,最重要的设计原则
一个软件实体的类,模块和函数应该对扩展开放(提供方),对修改关闭(修改方)。用抽象建立框架,用实现扩展细节。
当软甲需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现。
迪米特法则
一个对象应该对其他对象保持最少的了解
核心是降低类之间的耦合
合成复用原则
原则是:尽量使用合成,聚合的方式,而不是使用继承。
定义:确保某一个类只有一个实例,而且自行实例化并像整个系统提供这个实例
类图:
特点:单例模式保证了系统内存中该类只存在一一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使
用单例模式可以提高系统性能
单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象), 但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象。
单例模式的写法有八种,分别是:饿汉式(静态常量);饿汉式(静态代码块);懒汉式(线程不安全);懒汉式(线程安全,同步方法);懒汉式(线程安全,同步代码块);双重检测;静态内部类;枚举。
定义:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
类图:
特点:
浅拷贝:对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成员变量值
深拷贝:复制对象的所有基本数据类型的成员变量值
为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达到的所有对象。也就是说,对象进行深拷贝要对整个对象(包括对象的引用类型)进行拷贝
定义:将一个复杂对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示
类图:
优点:
每一个具体的建造者都相对独立,与其他建造者无关,因此可以很方便替换建造者或增加新的建造者,用户用不同的具体的建造者就可以得到不同的产品对象
增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭
原则”
缺点:
如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大
建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使
用建造者模式,因此其使用范围受到一定的限制。
应用实例:盖房问题
问题描述:需要建房子:这一-过程为打桩、砌墙、封顶
房子有各种各样的,比如普通房,高楼,别墅,各种房子的过程虽然一样,但是要求不要相同的.
代码实现类图:
定义:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
类图:
特点:遵循设计模式的依赖抽象原则
定义:将一个类的接口变换成客户端期望的另一种接口,从而使原本因为接口不匹配而无法工作的两个类能一起工作
类图:
特点:Adapter模式最大的作用还是将原本不兼容的接口融合在一-起工作。
应用实例:
问题描述:家用电源是220v但是给手机充电只需要5v,所以需要一个适配器来将电源转换为目标电压
定义:将抽象和实现解耦,使得两者可以独立的变化
类图:
优点:桥接模式可以减少子类的个数,降低系统的管理和维护成本。
缺点:桥接模式要求正确识别出系统中两个独立变化的维度(抽象、和实现),因此其使用范围有一定的局限性,即需
要有这样的应用场景。
应用实例:
问题描述:手机操作问题,现在对不同手机类型的品牌实现操作编程(比如:手机品牌有小米,华为;手机类型有折叠和旋转类型
代码实现,类图如下:
定义:动态地给一个对象添加一些额外的额职责,就增加功能来说,它相比生成子类更加灵活
类图:
特点:体现了ocp原则(开闭原则)
应用实例:
问题描述:咖啡订单问题,咖啡(三种)有很多种类,然后可以添加不同数量的调料(牛奶,巧克力,豆浆)
定义:将对象组合树型结构表示“部分 - 整体“的层次结构,使得用户对单个对象或组合对象的使用有一致性
类图:
优点:简化客户端操作。具有较强的扩展性。方便创建出复杂的层次结构。
缺点:要求较高的抽象性,如果节点和叶子有很多差异性的话,比如很多方法和属性都不一-样,不适合使用组合模式。
应用实例:
问题描述:学校院系展示功能,要在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系
定义:要求一个子系统的外部与其内部的通信必须通过一个同一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用
类图:
特征:外观模式对外屏蔽了子系统的细节,因此外观模式降低了客户端对子系统使用的复杂性
应用实例:
问题描述:影院管理。组建一个家庭影院:DVD播放器、投影仪、自动屏幕、爆米花机,要求完成使用家庭影院的功能,其过程为:
直接用遥控器:统筹各设备开关
定义:使用共享对象可有效地支持大量的细粒度的对象
类图:
优点:享元模式大大减少了对象的创建,降低了程序内存的占用,提高效率
缺点:享元模式提高了系统的复杂度。需要分离出内部状态和外部状态,而外部状态具有固化特性,不应该随着内部
状态的改变而改变,这是我们使用享元模式需要注意的地方.
应用实例:
问题描述:展示网站。小型的外包项目,给客户A做一个产品展示网站,客户A的朋友感觉效果不错,也希望做这样的产品展示网站,但是要求都有些不同:
代码实现,类图如下:
定义:为其他对象提供一种代理以控制对这个对象的访问
类图:
特点::可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象
应用实例:
问题描述:完成代理需求
代码实现,类图如下:
定义:定义一个操作中的算法的股价,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构就可以重定义该算法的某些特定的步骤
类图:
优点:实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用。
缺点:每一个不同的实现都需要-一个子类实现,导致类的个数增加,使得系统更加庞大
应用实例:
问题描述:豆浆制作问题。制作豆浆的流程中原料是不一样的,但是步骤相同。
定义:把一个请求或者操作封装在命令对象中。命令模式允许系统使用不同的请求把客户端参数
类图:
优点:容易实现对请求的撒销和重做
缺点:可能导致某些系统有过多的具体命令类,增加了系统的复杂度,这点在在使用的时候要注意
应用实例:
问题描述:智能生活。想要实现一个app就可以控制所有的家电,则每一个家电都需要提供一个同一的接口给app调用
代码实现,类图如下:
定义:封装一些作用于某种数据结构中的各个元素的操作,它可以在不改变数据结构的情况下定义作用于这些元素的新的操作
类图:
优点:访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高
缺点:具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的,这样造
成了具体元素变更比较困难
违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素
应用实例:
问题描述:测评系统。将观众分为男人和女人,对歌手进行测评,当看完某个歌手表演后,得到他们对该歌手不同的评价(评价有不,同的种类,比如成功、失败等)
代码实现,类图如下:
定义:提供一个种方法访问一个容器对象中各个元素,而又不需要暴露该对象的内部细节
类图:
优点:提供一个统一的方法遍历对象,客户不用再考虑聚合的类型,使用一种方法就可以遍历对象了。
缺点:每个聚合对象都要一个迭代器,会生成多个迭代器不好管理类
应用实例:
问题描述:编写程序展示-一个学校院系结构:需求是,要在一个页面中展示出学校的院系组成,- 一个学校有多个学院,
一个学院有多个系。
代码实现,类图如下:
定义:定义对象间一种一对多的依赖关系,使得每当一个独享改变状态,则所有依赖于它的对象都会得到通知并被自动更新
类图:
特点:观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除和通知。当我们增加观察者(这里可以理解成-一个新的公告板),就不需要去修改核心类WeatherData不会修改代码,
遵守了ocp原则。
应用实例:
问题描述:天气预报。气象站可以将每天测量到的温度,湿度,气压等等以公告的形式发布出去(比如发布到自己的网站或第三方)。测量数据更新时,能及时的通知第三方
代码实现,类图如下:
定义:用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示的相互作用,从而使其耦合松散,而且可以独立地改变他们之间的交互
类图:
优点:多个类相互耦合,会形成网状结构,使用中介者模式将网状结构分离为星型结构,进行解耦。减少类间依赖,降低了耦合,符合迪米特原则
缺点:中介者承担了较多的责任,一旦中介者出现了问题,整个系统就会受到影响
应用实例:
问题描述:智能家庭。主人要看电视时,各个设备可以协同工作,自动完成看电视的准备工作,比如流程为:闹铃响起~>窗帘自动落下->电视机开始播放
代码实现,类图如下:
定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态
类图:
优点:实现了信息的封装,使得用户不需要关心状态的保存细节
缺点:如果类的成员变量过多,势必会占用比较大的资源,而且每- -次保存都会消耗- -定的内存
应用实例:
问题描述:游戏角色状态恢复。游戏角色有攻击力和防御力,在大战Boss前保存自身的状态(攻击力和防御力),当大战Boss后攻击力和防御下降,从备忘录对象恢复到大战前的状态
代码实现,类图如下:
定义:给定一种语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言种的句子
类图:
特点:解释器:在编译原理中,一个算术表达式通过词法分析器形成词法单元,而后这些词法单元再通过语法分析器构建语法分析树,最终形成一颗抽象的语法分析树。这里的词法分析器和语法分析器都可以看做是解释器
应用实例:
定义:当一个对象内在状态改变时允许其改变行为,这个对象看起来象时改变了其类
类图:
优点:代码有很强的可读性。状态模式将每个状态的行为封装到对应的-一个类中
符合开闭原则,容易增删状态。
缺点:会产生很多类,每一种状态对应一种类,当状态过多时会产生很多类,加大了维护难度。
应用实例:
问题描述:app抽奖活动。活动有四个状态:可以抽奖、不能抽奖、发放奖品和奖品领完。每次参加活动需要扣除积分,奖品数量固定,抽完就不能进行。
代码实现,类图如下:
定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并且沿着这条链传递该请求,直到有对象处理它为止
类图:
优点:将请求和处理分开,实现解耦,提高系统的灵活性
缺点:性能会受到影响,特别是在链比较长的时候,因此需要控制链中最大节点数量,避免无意识的出现超长链,破坏系统的性能。 调试不方便。采用了类似递归的方式,调试时逻辑可能比较复杂
应用实例:
问题描述:采购审批项目。如果金额小于等于5000,由教学主任审批;如果金额小于等于10000,由院长审批;如果金额小于等于30000,由副校长审批;如果金额超过30000以上,有校长审批。请完成程序完成采购任务
代码实现,类图如下:
定义:定义一组算法,将每个算法都封装起来,并且时澳门之间可以互换
类图:
优点:体现了“对修改关闭,对扩展开放”原则,客户端增加行为不用修改原有代码,只要添加一-种策略
缺点:每添加一个策略就要增加一个类,当策略过多就会导致类庞大
应用实例:
问题描述:鸭子问题。有各种鸭子,每种鸭子会的技能不相同,请完成鸭子展示需求。
代码实现,类图如下: