设计模式复习

来源:互联网 发布:muse for mac 编辑:程序博客网 时间:2024/06/08 12:22

每种模式的起源是什么?解决什么问题?

工厂模式:

简单工厂模式包含如下角色:

Factory工厂角色:

Product抽象产品角色

Concreate Product具体产品角色

 

使用场景:

场景:主要用于创建对象。添加类时,不会影响以前的系统代码。核心思想是用一个工厂来根据输入的条件产生不同的类,然后根据不同的virtual函数得到不同的结果。

 

优点:适用于不同情况创建不同的类时

不足:客户端必须要知道基类和工厂类,耦合性差。

 

装饰模式

含义

动态地给一个对象增加一些额外的职责,就增加对象的功能来说,装饰模式比生成子类实现更为灵活,装饰模式也有人称之为“油漆模式”

 

模式结构:

角色:

Component :抽象构建

ConcreteComponent:具体构建

Decorator:抽象装饰类

ConcreteDecorator:具体装饰类

 

模式动机:给对象添加更多的职责。在不需要创建更多子类的情况下,给对象的功能加以扩展。

 

因为有相同的基类,所以可以动态添加,参数类型为基类类型,这样就可以添加不同的类对象了。

应用场景

可以直接扩展ConcreteComponent:具体构建,增加相应的具体构建就行了,只需在main函数中创建相应的对象。

 

1、  在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

2、  需要动态地给一个对象添加功能,这些功能也可以动态地被撤销。

3、  当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩充和维护时。

如果设计端不法列出所有的策略时。就采用策略模式。

 

优缺点

把类中的装饰功能从类中移走除开,这样可以简化原有的类。

有效的把类的核心功能和装饰功能分开了,而且可以去除相关类总重要的逻辑装。

 

缺点:

将产生很多小对象

装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为繁琐。

 

适用场景

1、  在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责

2、  需要动态的给一个类添加功能,也可以动态的撤销这些功能

3、  当不能采用继承的方式对系统进行扩充,(就是采用继承进行功能扩充会有很多缺点,而采用装饰模式更好。

实现码

虚函数:想实现多态。在子类中实现也可以,不实现也可以。

纯虚函数:必须实现,否则会报错

 

 

代理模式

定义:提供一个代理类,并由这个代理类来控制对这个对象的访问。

 

 

适用场景

远程代理

虚拟代理

安全代理

智能引用

缺点:需要提供额外的代理类和接口类,且名称必须与实体相同才能实现方法。

 

无论讲什么都要说清楚,有什么紧张的。慢!!!!!!!

工厂方法模式(又叫虚拟构造器,或者多态工厂)

定义:工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象目的:工厂方法使一个类的实例化延迟到其子类。

 


解决了简单工厂模式的开闭问题

 

工厂方法是解决简单工厂违反开闭原则的一个方法。(还有其他方法)

 

适用工厂方法的地方都适用简单工厂方法。

 

缺点:增加了一定的系统复杂度和开销。

 

使用场景:

1、  不需要知道他所创建的具体的类,只需要知道工厂类

2、  通过子类来指定创建哪一个类

3、  将创建对象的任务委托给多个工厂子类中的某一个。

原型模式

模式动机原型模式通过克隆出多个原型对象一模一样的对象

 

定义:用原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。

允许一个对象再创建另外一个可定制的对象,无需知道任何创建的细节。

 

基本工作原理:通过将一个原型对象传给那个要发动创建的对象通过请求原型对象拷贝原型自己来实现创建过程。

 

解决什么问题:

它主要面对的问题是:某些结构复杂的对象的创建工作;由于需求的变化,这些对象经常面临着剧烈的变化,但是他们却拥有比较稳定一致的接口。

 

 

隐式:系统自动转换,

显示转换:显示的给出指定转换类型

类型之间的转换:小(子类)大(父类)

->可以隐式转换

->必须要显示的转换

 

浅拷贝:属性中有指针时只复制指针

深拷贝:还要复制指针所指向的值

 

记住clone方法,它是通过自身的clone方法,创建一个指向本身类对象的抽象类指针,然后再将自己赋值给这个抽象类指针,在在clone方法中返回,因为返回的是一个基类类型的指针,再经过强制类型转换,赋值给新创建的另一个子类。

模板模式(基于继承的代码复用技术)

将相同的代码放在父类中,而将不同的方法实现放在不同的子类中

模板方法模式(Template Method):

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。模板模式是一种行为型模式

 

 

优点:

1、  在一个类中形式化地定义算法,而由它的子类实现细节的处理

2、  模板模式是一种代码复用的技术

3、  模板方法导致了一种反向控制结构通过其父类调用其子类的操作,通过对子类的扩展增加新的行为,符合开闭原则。

 

缺点:每个不同的实现都需要定义一个子类,导致类的个数增加

 

反向控制,有父类控制子类的方法调用顺序

模板模式的控制权在父类,父类在自己的方法中写了相应的规则。

原型模式的控制全在子类自己

 

 

类的关系是依赖时,菱形在依赖方的那边。

#pragmaonce //能保证文件只被编译一次

 

 

备忘录模式

 

不破坏封装,捕获一个对象内部状态,并在该对象之外保存这个状态。

 

优点:

提供了一种状态恢复的实现细节

实现了信息的封装

 

缺点:

资源消耗过大。

 

(给某个控件添加类):选中某个控件,右键添加,可以添加相应的类。

 

外观模式

建立通用的方法,实现对不同的数据库的连接。、

模式动机:引入外观角色之后,用户只需要直接与外观角色交互,用户与子系统之间的复杂关系由外观角色来实现,从而降低了系统的耦合度。

定义:外部与子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称门面模式,它是一种对象结构型模式。

 

外观模式的有优点:

1、  对客户屏蔽子系统组件,减少客户处理的对象数目,并使得子系统使用起来更加容易。通过引入外观模式,客户代码将变得很简单,与之关联的对象也很少。

2、  实现了子系统与客户之间的松耦合关系,这使得子系统的组件变化不会影响到调用它的客户端,只需要调用外观类即可。

3、  只是提供了一个访问子系统的统一入口,并不影响用户直接使用子系统类。

外观模式的缺点:

1、  不能很好地限制客户使用子系统类,如果对客户访问子系统类太多的限制则减少了可变性和灵活性。

2、  在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了“开闭原则”

 

外观模式使用场景:

1、  当要为一个复杂子系统提供一个简单接口时可以使用外观模式。该接口可以满足大多数用户需求,而且用户也可以越过外观模式直接访问子系统。。

2、  客户程序与多个子系统之间存在很大的依赖性。引入外观类将子系统与客户以及其他子系统解耦,可以提高子系统的独立性和可移植性。

3、  在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接联系,而是通过外观类建立联系,降低层之间的耦合度。

 

观察者模式( 又叫“发布-订阅”,“模型-视图”,“源-监听器”,“从属者”模式)

 

抽象后的UML

 

模式动机:

1、对象与对象之间的依赖关系,一个对象发生改变时,将自动通知其他对象,其他对象发生改变时将自动通知其他对象,其他对象将做出相应的反应。

2、发生改变的对象称为观察目标,而被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系。

 

定义:定义对象间的一种一对多的依赖关系,使得每当一个对象的状态发生改变时,其相关依赖的对象皆得到通知并被自动更新。

 

优点:将有依赖的双方进行分离(解耦),使双方都依赖于抽象,而不是依赖于具体。

 

缺点:

1、  有循环依赖的话,可能导致系统崩溃

2、  观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅是知道观察目标发生了变化。

 

适用场景:

1、  一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。

2、  一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这些方面封装在独立的对象中使他们可以各自独立的改变和复用。

 

抽象工厂

模式动机:

1、  有时我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。

 

 

两个概念:

1、  产品等级结构(横向的):产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机,TCL电视机等。

2、  产品族:产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品。

如海尔电器工厂生产的海尔电视机,海尔电冰箱。海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。

 

定义:提供一系列相关或相互依赖的对象接口,而无须指定他们具体的类。

优点:

1、易于交换产品系列,由于具体工厂类在一个应用中只需要在初始化一次,使得改变一个应用的具体工厂变得非常容易

2、产品的创建实例过程与客户端分离,产品的具体类名也被具体工厂的实现分离,不会出现在客户代码中。

 

缺点:

1、在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展

2、开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)

 

适用环境:

1、一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。

2、系统中有多于一个的产品族,而每次只使用其中某一产品族。

3、属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。

4、系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

 

工厂模式的变形

当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。

 

 

Curl

curl是利用URL语法在命令行方式下工作的开源文件传输工具。它被广泛应用在Unix、多种Linux发行版中,并且有DOSWin32Win64下的移植版本。

 

适配器模式(Adapter):

将一个类的接口转换成客户希望的另外一个接口。A d a p t e r模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

适用场景:

1、已经存在的类的接口不符合我们的需求;

2、创建一个可以复用的类,使得该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作;

3、在不对每一个都进行子类化以匹配它们的接口的情况下,使用一些已经存在的子类。

建造者模式

建造者模式(Builder Pattern)

使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

介绍

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

何时使用:一些基本部件不会变,而其组合经常变化的时候。

如何解决:将变与不变分离开。

关键代码:建造者:创建和提供实例,导演:管理建造出来的实例的依赖关系。

应用实例: 1、去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。 2、JAVA 中的 StringBuilder。

优点: 1、建造者独立,易扩展。 2、便于控制细节风险。

缺点: 1、产品必须有共同点,范围有限制。 2、如内部变化复杂,会有很多的建造类。

使用场景: 1、需要生成的对象具有复杂的内部结构。 2、需要生成的对象内部属性本身相互依赖。

状态模式

允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States)

意图:允许一个对象在其内部状态改变时改变它的行为

适用场景:

1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。

2.一个操作中含有庞大的多分支结构,并且这些分支决定于对象的状态。

Ping++相当于提供一个外观模式,整合现在的很多支付方式

Ping++API 采用 REST风格设计。所有接口请求地址都是可预期的以及面向资源的。使用规范的HTTP响应代码来表示请求结果的正确或错误信息。使用 HTTP内置的特性,如 HTTP Authentication HTTP请求方法让接口易于理解。所有的 API请求都会以规范友好的 JSON对象格式返回(包括错误信息)。

 

Notify()

Change()

静态工厂也称简单工厂

 

抽象工厂实例规则

 

判断题

填空题

选择题

解答题

应用题

 

面向对象设计的七个原则

1、  单一职责原则:类的职责要单一,不能将太多的职责放在一个类中

2、  开闭原则:对扩展开放对修改关闭

3、  里氏代换原则:一个可以接受基类对象的地方必然可以接受其子类对象

4、  依赖倒转原则:要针对抽象层编程,而不要针对具体类编程。

5、  接口隔离原则:使用多个专门的接口来取代一个统一的接口

6、  合成复用原则:在系统中应该多使用组合和聚合关联关系,尽量少使用甚至不使用继承关系。

7、  迪米特法则:一个软件实体对其他类的引用应该越少越好,或者说如果两个两个类不必彼此直接通信,那么这两个类不应当发生直接的相互作用,而是通过引入第三者间接交互。

 

我对这七个原则的理解

1、  单一职责原则:为什么类的职责要单一呢?我们往往通过类名来判断这个类的功能是什么,如果这个类的功能除了其名称所赋予给他的功能外还有其他的功能,这样就会给程序员的使用带来很大的不变,简单工厂方法的工厂类就违背了单一职责原则,照理说他就创建工厂就行,他却能根据参数创建不同的类对象。

2、  开闭原则:为什么要有它?现在编程大多都是很多人在一起编,因为项目很大,每个人负责一块功能,那么其他人就不太清楚别人写的代码,如果以后集成进来了,没有遵循开闭,那么让其他人去改你的代码有时可能是一件很痛苦的事情。可以扩展,但是不能修改已经写好的类或模块。

3、  里氏代换:为什么有?我觉得他的出现是想增加系统的灵活性,每个类继承相同的抽象类,都去实现同一个接口,各子类方法名相同,但实现的功能各不相同。因为是继承相同的父类,那么创建了一个父类对象后,这个父类就可以指向这些子类。一个父类对象可以指向所有的它的子类对象。这样就大大增加了灵活性。

4、  依赖倒转:针对抽象层编程,可以让我们拥有大的方向感,而如果针对具体的实现去编程,往往会是我们失去这种方向感。

5、  接口隔离我觉得最大的作用应该是为了提高易用性,以前需要调用多个接口才能实现的功能,现在调用一个接口就可以实现了。

6、  合成复用:尽量少使用继承而应该多使用组合,我觉得最大的原因应该是想提高系统的开销,因为继承会大量继承重复的代码。

7、  迪米特:通过第三者进行交互,而不是直接交互,解耦。让系统更加灵活。

 

我对各个模式的总结

模式的分类

 

 

简单工厂模式:

实现思路:

1、定义一个虚基类,其实这个虚基类相当于定义多个接口,然后子类根据各自不同的需求去实现相应的接口。

2、创建一个简单工厂类,去创建需要的对象,简单工厂类中有个专门去创建对象的接口,这个方法会得到一个参数,由客户端输入,

用户根据输入的参数去创建相应的对象,这个方法会返回一个运算类对象,即这些具体类的基类,基类指针可以指向任何他的子类,(里氏代换)

创建成功后返回这个对象。

3、因为这些子类继承自父类,有一个相同的接口getResult()客户端根据得到的对象,调用自身的getResult方法,返回想要的结果。

 

缺点:

在简单工厂类中,违背了单一职责原则,开放封闭原则。

 

 

策略模式

使用场景:定义算法家族,让他们可以相互替换,算法变化,不会影响客户端程序员的调用。

 

优点:适合类中的成员以方法为主,算法经常变动的场景。

         简化了单元测试,因为可以通过自己的接口测试

缺点:客户端需要做判断(有客户端做出决定,创建什么对象,如什么优惠策略)

 

 

它与简单工厂模式有什么不同:“简单工厂模式主要解决了对象创建的问题,而策略模式解决算法动态变化的问题”

它创建了一个context类,而这个context类中已经定义了一个策略类对象,通过给这个策略类对象赋予不同的子类对象,调用其抽象接口方法,就会返回不同的结果。在客户端调用的方法名,不会返回对象,只会返回结果。

 

低耦合:不直接访问,而是通过第三方间接访问。这就实现可低耦合。

 

注意:一种情况下只允许使用一种策略。而模板模式:可以在一种情况下使用多个策略(方法)

 

策略模式返回的是想要得到的结果,简单工厂返回的是具体的对象。

 

 

 

 

原创粉丝点击