软件设计模式

您所在的位置:网站首页 咪咕直播源静太源 软件设计模式

软件设计模式

2024-01-21 23:59| 来源: 网络整理| 查看: 265

文章目录 一、前置知识UML基础类图活动图时序图(顺序图)状态图 面向对象设计原则单一职责原则开闭原则里氏代换原则依赖倒转原则接口隔离原则合成复用原则迪米特法则 二、创建型模型简单工厂模式 ★★★☆☆工厂方法模式 ★★★★★抽象工厂模式 ★★★★★建造者模式 ★★☆☆☆原型模式 ★★★☆☆单例模式 ★★★★☆ 三、结构型模型适配器模式 ★★★★☆桥接模式 ★★★☆☆组合模式 ★★★★☆装饰模式 ★★★☆☆外观模式 ★★★★★代理模式 ★★★★☆ 四、行为型模型职责链模式 ★★☆☆☆命令模式 ★★★★☆迭代器模式 ★★★★★中介者模式 ★★☆☆☆备忘录模式 ★★☆☆☆观察者模式 ★★★★★状态模式 ★★★☆☆策略模式 ★★★★☆模板方法模式 ★★★☆☆

一、前置知识 UML基础

常见的UML模型有类图、活动图、时序图、状态图,不一定要会画,但起码要能看懂。

类图

类与类之间一共有六种关系:关联(association)、泛化 (generalization)、聚合(aggregation)、组合(composition)、实现(realization)、依赖 (dependency),它们图形表示如下图所示。

关联:一个类是另一个类的成员变量,关联可以是双向的。聚合:一个类是另一个类的成员变量,两者是整体与部分的关系,但不是同生共死的关系,一方的对象销毁,另一方的对象依然可以存在。组合:强化班的聚合,一个类是另一个类的成员变量,两者是整体与部分的关系,而且是生死与共的关系,两方的对象同时产生且同时销毁,不能独立于彼此而存在。继承:就是继承父类。实现:就是实现接口。依赖:指在一个类中用得到另一个类,比如函数参数、函数返回值等等。

在这里插入图片描述

活动图

活动图通常用表示一个程序或工作流,常用于计算流程和工作流程,在活动图中:

实心圆 是开始点,环形圆是终止点箭头——代表流程的方向圆矩形——代表着流程中的活动粗线——代表着分叉与结合菱形——代表着条件判断,根据判断结果的不同,流程会朝着不同的方向执行竖直分割线——把活动图分割为若干个泳道,目的是为了指明哪些活动是由哪些对象执行的 在这里插入图片描述 时序图(顺序图)

一个时序图通常表示一个用例的细节。

消息,用水平箭头书写,上面写着消息名称,显示交互。 实心箭头表示同步调用,空心箭头表示异步消息,虚线表示回复消息。如果调用方发送同步消息,则必须等待消息完成,例如调用子程序。 如果调用者发送异步消息,它可以继续处理而不必等待响应。 异步调用存在于多线程应用程序、事件驱动应用程序和面向消息的中间件中。 激活框或方法调用框是绘制在生命线顶部的不透明矩形,表示正在执行进程以响应消息(UML 中的 ExecutionSpecifications)。

在这里插入图片描述

状态图

状态模型是一种描述系统对内部或者外部事件响应的行为模型。它描述系统状态和事件,以及事件引发系统在状态间的转换。这种模型适用于描述实时系统。

初态用实心圆表示,终态用一对同心圆(内圆为实心圆)表示。

中间状态用圆角矩形表示,可以用两条水平横线把它分成上、中、下3个部分。上面部分为状态的名称,这部分是必须有的;中间部分为状态变量的名字和值,这部分是可选的;下面部分是活动表,这部分也是可选的。

下面是两个状态图实例,结合图片来看是比较形象易懂的。 在这里插入图片描述 在这里插入图片描述

面向对象设计原则

在这里插入图片描述

单一职责原则

一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中。

一个类(或者大到模块,小到方法)承担的职责越多,它被复用的可能性越小,而且如果一个类承担的职责过多,就相当于将这些职责耦合在一起,当其中一个职责变化时,可能会影响其他职责的运作。类的职责主要包括两个方面:数据职责和行为职责,数据职责通过其属性来体现,而行为职责通过其方法来体现。单一职责原则是实现高内聚、低耦合的指导方针,在很多代码重构手法中都能找到它的存在,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关重构经验。 开闭原则

一个软件实体应当对扩展开放,对修改关闭。也就是说在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展,即实现在不修改源代码的情况下改变这个模块的行为。

开闭原则的关键在于抽象,即抽象类和接口。

里氏代换原则

在软件中如果能够使用基类对象(父对象),那么一定能够使用其子类对象。

很多面向对象语言在语法层面上已经实现了里氏代换原则,如c++和java均支持多态。

依赖倒转原则

应该依赖于抽象,不要依赖于具体

高层模块不应该依赖低层模块,它们都应该依赖抽象。抽象不应该依赖于细节,细节应该依赖于抽象。

换个说法就是,要针对接口编程,不要针对实现编程。

接口隔离原则

客户端不应该依赖那些它不需要的接口。一旦一个接口太大,则需要将它分割成一些更细小的接口,使用该接口的客户端仅需知道与之相关的方法即可。

接口隔离原则是指使用多个专门的接口,而不使用单一的总接口。每一个接口应该承担一种相对独立的角色,不多不少,不干不该干的事,该干的事都要干。

(1) 一个接口就只代表一个角色,每个角色都有它特定的一个接口,此时这个原则可以叫做“角色隔离原则”。(2) 接口仅仅提供客户端需要的行为,即所需的方法,客户端不需要的行为则隐藏起来,应当为客户端提供尽可能小的单独的接口,而不要提供大的总接口。 合成复用原则

尽量使用对象组合,而不是继承来达到复用的目的。

迪米特法则

迪米特法则(Law of Demeter, LoD)又称为最少知识原则(Least Knowledge Principle, LKP),它有多种定义方法,其中几种典型定义如下:

(1) 不要和“陌生人”说话。(2) 只与你的直接朋友通信。(3) 每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位 二、创建型模型 简单工厂模式 ★★★☆☆

工厂模式的核心就是:把创建对象的过程封装成方法。当你想创建一个对象时,不能直接new一个它,而是要调用相应的工厂类中的方法,该方法会返回一个你想要的对象。

简单工厂模式(Simple Factory Pattern):定义一个工厂类(Factory),它可以根据参数(String arg)的不同返回不同类的实例(ConcreteProductA、ConcreteProductB),被创建的实例通常都具有共同的父类(Product)。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。 在这里插入图片描述

工厂方法模式 ★★★★★

在简单工厂模式中,只有一个具体的工厂类,一个工厂类生产多种产品对象。

在工厂方法模式中,有一个抽象工厂接口,和多个实现该接口的具体工厂类,每个具体的工厂类生产一种产品对象。

比如我现在需要一些鞋子,这些鞋子有着不同的类型,运动鞋、篮球鞋、皮鞋等等。在简单工厂模式中我们可以只需要一个工厂类即可,该工厂类可以生产所有类型的鞋子。而在工厂方法模式中我们需要一个抽象工厂接口和多个具体工厂类,没个具体工厂只能生产一个类型的鞋子。

工厂方法模式(Factory Method Pattern)定义:定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式(Factory Pattern),又可称作虚拟构造器模式(Virtual Constructor Pattern)或多态工厂模式(Polymorphic Factory Pattern)。工厂方法模式是一种类创建型模式。

在这里插入图片描述

抽象工厂模式 ★★★★★

与工厂方法模式相比,抽象工厂模式中的具体工厂不只是创建一种产品,它负责创建一族产品。比如一台电脑由cpu、memory、disk组成,那么cpu、memory、disk就是一族产品,工厂方法模式里的一个具体工厂只生产cpu、memory、disk中的某一个,而抽象工厂模式中的一个具体工厂既可以生产cpu又可以生产memory、disk。

抽象工厂模式(Abstract Factory Pattern)定义:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。

在抽象工厂模式中,每一个具体工厂都提供了多个工厂方法用于产生多种不同类型的产品,这些产品构成了一个产品族,抽象工厂模式结构如下图所示,图中的ProductA和ProductB构成了一个产品族,Factory为抽象工厂:

在这里插入图片描述

建造者模式 ★★☆☆☆

有时候一个复杂对象的构建不是一蹴而就的,我们需要先构建出这个复杂对象的各个部分,然后将各个部分组合起来。比如,我们要构建一个电脑对象,那么先要分别构建cpu、memory、disk对象,然后把三个对象组合成一个电脑对象。

而Client并不在乎这个cpu、memory、disk是如何构建的,它也并不想知道这三个对象如何组合成为一台电脑的。它的需求很简单,我告诉你我想要一台怎样的电脑,你给我生产出来就可以了,至于中间经过什么复杂的步骤,我不关心。

这时候就需要引出我们要说的建造者模式了,建造者模式就是为了满足上述需求而产生的。

建造者模式(Builder Pattern)定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。建造者模式是一种对象创建型模式。建造者模式一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。

如下图所示,用户只需要调用Director的construct方法,就可以得到自己想要的复杂对象。用户无需关心PartA、PartB、PartC是如何产生的以及它们是如何组成复杂对象的,这是Builder的职责。 在这里插入图片描述

原型模式 ★★★☆☆

原型模式很简单,就是让对象变得可以拷贝。我们需要在类中定义一个克隆方法,当调用这个克隆方法时,会返回该对象的一个深拷贝。

原型模式(Prototype Pattern)定义:使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。原型模式是一种对象创建型模式。

如下图所示,WeeklyLog为周报类,调用clone()方法可以得到一个完全相同的周报对象。

在这里插入图片描述

单例模式 ★★★★☆

单例模式太简单了,不再阐释,直接把课本上的定义和例子抄到下面:

单例模式(Singleton Pattern)定义:确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。

在这里插入图片描述

三、结构型模型 适配器模式 ★★★★☆

适配器模式(Adapter Pattern)定义:将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。

结合类图更容易说明适配器模式的内容和功能。

如下图所示,Client类只能引用Target接口,而Adaptee是没有实现Target接口的,那么现在想让Client使用到Adaptee的specificRequest方法,该怎么做呢?我们在Target和Adaptee之间加一个适配器类Adapter,Adapter即实现了Target接口又组合了Adaptee类,Client可以通过引用Adapter从而调用Adaptee的specificRequest方法。 在这里插入图片描述

桥接模式 ★★★☆☆

桥接模式是一种很实用的结构型设计模式,如果软件系统中某个类存在两个独立变化的维度,通过该模式可以将这两个维度分离出来,使两者可以独立扩展,让系统更加符合“单一职责原则”。与多层继承方案不同,它将两个独立变化的维度设计为两个独立的继承等级结构,并且在抽象层建立一个抽象关联,该关联关系类似一条连接两个独立继承结构的桥,故名桥接模式。

桥接模式(Bridge Pattern)定义:将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。

定义太抽象了,看了等于没看,结合实际例子解释会比较清楚。关于下图的例子,课本上说的比较好,所以直接抄课本:

通常情况下,我们将具有两个独立变化维度的类的一些普通业务方法和与之关系最密切的维度设计为“抽象类”层次结构(抽象部分),而将另一个维度设计为“实现类”层次结构(实现部分)。对于毛笔而言,由于型号是其固有的维度,因此可以设计一个抽象的毛笔类,在该类中声明并部分实现毛笔的业务方法,而将各种型号的毛笔作为其子类;颜色是毛笔的另一个维度,由于它与毛笔之间存在一种“设置”的关系,因此我们可以提供一个抽象的颜色接口,而将具体的颜色作为实现该接口的子类。而两个维度的抽象类和抽象接口相互之间是聚合的关系,这也就是在抽象层建立了一个抽象关联。在此,型号可认为是毛笔的抽象部分,而颜色是毛笔的实现部分。

其实吧,关于为什么把型号可认为是毛笔的抽象部分、而颜色是毛笔的实现部分,我有点不太理解。我觉得把下图稍作修改,做一些替换操作:毛笔→笔、大号毛笔→钢笔、小号毛笔→铅笔、中号毛笔→水笔,笔的种类是笔的固有维度,把笔的种类设置为抽象部分、笔的颜色设置为实现部分,这样会更明朗、更好理解一些。 在这里插入图片描述

组合模式 ★★★★☆

组合模式(Composite Pattern)定义:组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。

组合模式很好理解,它其实就是指对象和对象直接相互嵌套,形成一个属性的结构。就像计算机的文件系统那样,文件夹里可以包含各种文件与文件夹,然后文件夹里的文件夹还可以包含各种文件与文件夹。

组合模式的结构图如下图所示,可以把Leaf看作文件,把Composite看作文件夹,那么当调用一个Component类型实例的operation()方法时,如果这个实例是文件,则执行该文件的operation()操作;如果这个实例是文件夹,则调用文件夹所有子文件和子文件夹的operation()操作。 在这里插入图片描述

装饰模式 ★★★☆☆

装饰模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,就增加对象功能来说,装饰模式比生成子类实现更为灵活。装饰模式是一种对象结构型模式。

装饰模式是用关联(组合)的方式实现类的复用。下图所示的是装饰模式的结构图,我们想要拓展ConcreteComponent类的operation()方法的功能,我们的做法是先定义一个抽象装饰类Decorator,继承Component类并以它为成员变量,然后基于Decorator实现两个具体装饰者类:ConcreteDecoratorA、ConcreteDecoratorB,在这两个类中可以使用原ConcreteComponent类的operation()方法,并且可以在该方法内新增了addState和addBehavior()功能,至此便实现了对象职责的扩展。 在这里插入图片描述

外观模式 ★★★★★

外观模式比较简单,使用频率很高,我们在日常编写代码中可能不知不觉就会用到外观模式。

外观模式实际就是为复杂的子系统提供一个统一的入口,比如比如现在有六个类ABCXYZ,A类要用到X类的方法,B类要用到Y类的方法,C类要用到Z类的方法。这时候呢我们定义一个外观类Facade,这个外观类依赖于XYZ类并且统筹了它们三个类的方法,所以ABC类就可以只引用Facade类便可以间接地使用XYZ类的方法,从而实现了脱耦。

下图中的茶馆服务员就起到了外观类的作用。 在这里插入图片描述

代理模式 ★★★★☆

代理模式也很常见,由于某些原因,客户端不想或不能直接访问一个对象,此时可以通过一个称之为“代理”的第三者来实现间接访问,该方案对应的设计模式被称为代理模式。

代理模式定义:给某一个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。

如下图所示,Proxy类是RealSubject的代理,Proxy中引用了RealSubject,客户端可以通过使用Proxy来使用RealSubject的所有功能,Proxy还可以对RealSubject的功能进行一部分的拓展。 在这里插入图片描述

四、行为型模型 职责链模式 ★★☆☆☆

一件事务可能要先后经过多个对象处理,就像我们吃入口中的食物,要先后经过口腔、食道、胃、肠等多个器官的处理,才能转换为身体所需的能量。这些处理事务的对象构成了一个链式结构,事务沿着这条链被处理,这条链就被称为职责链。

职责链模式(Chain of Responsibility Pattern)定义:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。职责链模式是一种对象行为型模式。

职责链结构如下图所示,Handler就是事务的处理者,可以看到它有一个Handler对象作为成员变量,可以通过调用该成员变量的handleRequest方法,把事务传递给下一个处理者。 在这里插入图片描述

命令模式 ★★★★☆

命令模式(Command Pattern):将一个请求封装为一个对象,从而让我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作(Action)模式或事务(Transaction)模式。

命令模式如下图所示,其实就是把事务发起者Invoker和事务接收者Receiver解耦,在中间加一个命令Command。Invoker只能通过Command来对Receiver发起事务,在command内部可以对发起事务的命令进行排队、记录日志、撤销等操作。 在这里插入图片描述

迭代器模式 ★★★★★

迭代器模式(Iterator Pattern):提供一种方法来访问聚合对象,而不用暴露这个对象的内部表示,其别名为游标(Cursor)。迭代器模式是一种对象行为型模式。

这个模式很简单,就是为一个聚合对象造一个迭代器。迭代器模式结构如下图所示,ConcreteIterator就是我们要实现的迭代器类,左边的是抽象聚合接口和具体聚合类,我们的迭代器就是要遍历ConcreteAggregate聚合对象中的所有子对象。注意,这里使用了工厂模式,通过聚合对象中的createIterator方法来生产迭代器类。 在这里插入图片描述

下图是一个具体实例,ProductIterator就是遍历ProductList中所有子对象的迭代器。 在这里插入图片描述

中介者模式 ★★☆☆☆

中介者模式(Mediator Pattern)定义:用一个中介对象(中介者)来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。

如下图所示,引入中介者前,类与类之间的关系错综复杂,引入中介者后,每个类都只与中介者保持联系。

在这里插入图片描述 中介者模式的结构如下图所示,不同的同事Colleague之间可以通过中介者Mediator联系。 在这里插入图片描述

备忘录模式 ★★☆☆☆

这个名字我觉得取的不太好,叫历史记录模式应该更合适。

备忘录模式提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原,当前很多软件都提供了撤销(Undo)操作,其中就使用了备忘录模式。

备忘录模式(Memento Pattern)定义:在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是一种对象行为型模式,其别名为Token。

这个还没理解好,暂时不写。。。

观察者模式 ★★★★★

观察者模式的应用那可太广了,它又被称为发布-订阅模式。它用于建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象,其他对象将相应作出反应。在观察者模式中,发生改变的对象称为观察目标Subject,而被通知的对象称为观察者Observer。

观察者模式(Observer Pattern)定义:定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式的别名包括发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器 (Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。

观察者模式的结构如下图所示,Subject通过attach、detach来添加和删除观察者,通过notify来通知观察者发生改变,也就是调用update方法。观察者和观测目标是双向关联的关系,当update被调用时,观察者会读取观察目标的状态,然后根据状态值对自己做出改变。 在这里插入图片描述

状态模式 ★★★☆☆

状态模式(State Pattern)定义:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。

其实就是给对象添加一个状态值,而且在状态值不同时会有不同的行为。状态模式结构如下图所示,可以通过setState方法改变Context的状态,而状态对象中定义了handle方法,request方法中又调用了handle方法,所以对于不同的状态,request方法执行的结果也不同。 在这里插入图片描述

策略模式 ★★★★☆

策略模式很简单,就是对算法进行封装,通过继承抽象的方法,让每一种算法的封装对应一个具体类。

策略模式(Strategy Pattern)定义:定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。策略模式是一种对象行为型模式。

在这里插入图片描述

模板方法模式 ★★★☆☆

模板方法模式(Template Method Pattern)定义:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

注意定义中的两个说法:不改变算法结构、改变特定步骤。模板方法模式如下图所示,抽象类中定义了一个模板方法TemplateMethod,在模板方法内部先后执行三个成员方法,那么我们就可以通过在子类中覆盖重写这三个方法中的某些方法,从而达到不改变算法结构但改变某些特定步骤的效果。这就是模板方法模式的内容。 在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3