设计模式概述

        上周五参见了阿里巴巴的Android开发工程师面试,中间提到了设计模式的相关问题,我并没有答全答好,是一个很好的查缺补漏的机会。

  设计模式

        设计模式是用来表现程序内部组件(Java类)是如何被组装的,以及每一个组件(Java类)是如何通过相互关联来构成一个庞大的系统,其目的之一就是提高类的可复用性。GOF的论文总结了23种设计模式,根据特点被分为三大类,这三大类设计模式遵循六大设计原则。这些设计模式都是非常好的编程经验总结。

6种组件关系

       组件(Java类)的关系是设计模式的基础,这里概述下

1.泛化(Generalization)

        一种继承关系,表示一般与特殊的关系,它制定子类如何特殊化父类的特征和所有行为。

2.实现(Realization)

      类与接口的关系,类实现了接口的所有特征和行为。

3.关联(Association)

      拥有关系,一个类知道另一个类的属性和方法。

4.聚合(Aggregation)

      整体与部分的关系,且部分可以离开整体而单独存在,比如网卡与电脑主机。聚合关系是关联关系的一种,是强的关联关系。

5.组合(Composition)

    同样整体与局部,但是局部不能离开整体而单独存在,比如学校与班级。

6.依赖(Dependency)

    使用关系,既一个类的实现需要另一个类的协助,所以尽量不要使用双向的互相依赖。

各种依赖关系依次变强

Generalization=Realization<Assocation<Aggregation<Composition<Dependency

设计模式的六大原则

总原则:开闭原则

对拓展开发,对修改关闭,对程序进行功能拓展的时候,尽量不要修改原有的代码,而是扩展现有的代码,主要通过抽象类和接口来达到这个目的。

1.单一职责

    每个类实现单一的职责。

2.里斯科夫替换(Liskov Substitution Principle)

    任何基类可以出现的地方,子类一定可以出现,子类尽量不要对父类的方法进行重载或重写。

3.依赖倒转原则(Dependency Inversion Principle)  

    面向具体的接口编程,依赖于抽象,而不依赖于具体的类,写代码时用到具体的类,不与具体类交互,而与具体类的上层接口进行交互。

4.接口隔离原则(Interface Segregation Principle)

   每个接口不存在子类用不到的方法,使用多个隔离的接口,而不是将多个抽象方法集合到一个接口当中。

5.最少知道原则(Demeter Principle)

一个类对自己依赖的类越少越好。

6.合成复用原则(Composition Reuse Principle)

  尽量使用 聚合,组合的方式,少使用继承。

设计模式三大类

1.创建型模式(5)

工厂模式、抽象工厂模式、单例模式、建造者模式、原型模式

2.结构型模式(7)

适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式

3.行为型模式(11)

策略模式、模版模式、观察者模式、迭代模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、仲裁者模式、解释器模式

23种设计模式

创建型模式

1.工厂模式(Factory Method)--将实例的生成交给子类

  父类决定实例的生成方式,但不决定所要生成的具体的类,具体的处理全部交给子类负责。这样就可以将生成实例的框架(framework)和实际负责生成实例的类。父类决定生成方式,子类调用父类的生成方法来生成具体的实例。

2.抽象工厂模式(Abstract Factory)--将关联零件组装成成品

 将抽象零件组装为抽象产品,我们并不关心零件的具体实现,而是关心接口,通过调用抽象产品的接口(API)来组装抽象产品,生成具有复杂结构的实例。

3.单例模式(Singleton)--只有一个实例

将单一实例在类内部生命,并声明实现的方法,确保任何情况下这个类只有一个实例。

4.建造者模式(Builder)--组装复杂的实例

  建造组成这个模型的各个部分,然后分阶段将它们组装起来。

5.原型模式(Prototype)--通过复制生成实例

不根据类生成实例,而是根据实例来生成新实例。定义继承Cloneable接口的复制接口,通过类实现这个接口的clone()函数来实现具体的类。

结构型模式

6.适配器模式(Adapter)--加个适配器以便复用

       用于填补现有程序和所需程序之间的差异,通常是通过子类继承一个父类并实现“需求”接口,这样将父类的方法可以在子类中使用,适配器主要起到的是一个将不同模型进行连接的作用。

 

7.装饰器模式(Decorator)--装饰边框与被装饰物的一致性

        不断地为对象添加装饰,子类扩充父类的方法,以增量式来实现新的功能。

8.代理模式(Proxy)--只在必要时生成实例

     在面向对象编程中,“本人”和“代理人”都是对象,如果“本人”对象太忙了,有些工作自己无法亲自完成,就将其交给“代理人”对象负责。通常是通过使用Proxy角色,将耗时操作推迟调用。

9.外观模式(Facade) --简单窗口

    该模式可以为互相关联在一起的错综复杂的类整理出高层接口(API)。其中的Facade角色可以让系统对外只有一个简单的接口(API),而且,Facade角色还会考虑到系统内部各个类之间的责任关系,按照正确的顺序调用各个类。

10.桥接模式(Bridge)--将类的功能层次结构与实现层次结构分离

  父类具有基本功能,在子类中添加新的功能,这种层次结构被称为功能层次结构。父类通过生命抽象方法来定义接口,子类通过实现具体方法来实现接口,这种层次结构被称为类的实现层次结构。在多种继承关系中,分别有两路继承子类,一类实现功能层次结构,一类实现实现层次结构,这个父类便是类的功能层次结构与实现层次结构的桥。

11.组合模式(Composite)--容器与内容的一致性

      在计算机中有个“文件夹”的概念,文件夹下可以放目录和其他文件夹,这形成了一种容器结构和递归结构。文件夹和文件有时也被统称为“目录条目”(directory Entry),在目录条目中,文件夹与文件被看作同一种对象(即一致性)。能够使容器和内容具有一致性,创造出递归结构,这就是组合模式。

12.享元模式(Flyweight)--共享对象,避免浪费

     为了能够在计算机中保存对象,需要分配给其足够的内存空间。当程序需要大量对象时,如果使用new关键字来分配内存,将会消耗大量的内存。关于Flywei模式,一言蔽之就是“通过尽量共享实例来避免new出实例”,通常一个类要多次使用另一个类的实例。

行为模式

13.策略模式(Strategy)--整体地替换算法

       无论什么程序,其目的都是解决问题,而为了解决问题,我们又需要编写特定的算法。使用Strategy模式可以整体地替换算法的实现部分。能够整体的替换算法,让我们轻松地以不同的算法去解决同一个问题,这种模式就是Strategy模式。

14.模版模式(Template Method) --将具体的处理交给子类

       在父类定义处理流程框架,在子类具体实现具体处理的模式就称为Template Method。

15.观察者模式(Observer) --发送状态变化通知

      在Observer模式中,当观察的对象的状态发生变化时,会通知给观察者。Observer模式适用于根据对象状态进行相应处理的场景,模型类与观察者类为聚合关系,模型拥有观察者类的实例,当模型类发生变化的时候,观察者类相应的子类会对模型类问题场景进行一个处理。

16.迭代模式(Iterator)--一个一个遍历

Iterator模式用于在数据集合中按照顺序遍历集合,将循环变量的作用抽象化,通用化形成的模式。

17.责任链模式(Chain of Responsibity)--推卸责任

     当外部请求程序进行某个处理,但程序暂时无法直接决定由哪个对象负责处理的时候,就需要推卸责任,这种情况下,我们可以将多个对象组成一个责任链,然后按照它们在职责链上的顺序一个一个地找出到底应该谁来负责处理。通常设计一个处理的父类,这个父类内部实现链表结构,同时实现迭代下一代的问题解决方法,将所有子类组成一个链表,当外部的请求进来后,内部责任链开始进行迭代处理。

18.命令模式(Command)--命令也是类

        一个类在进行工作时会调用自己或是其他类的方法,虽然调用结果会反应在对象的状态中,但并不会留下工作的历史记录。这时,如果我们有一个类,用来表示“请进行这项工作的命令”就会方便很多。每一项工作不再是“方法调用”这种动态处理了,而是表示一个命令类的实例,即可以用“物”来表示。要想管理工作的历史记录,只需要管理这些实例的集合即可,而且还可以随时再次执行过去的命令,或者将多个过去的命令整合为一个新的命令并执行。

      Command有时也被称为事件(event)。它与“事件驱动”中的“事件”是一个意思。当发生点击鼠标,按下键盘按键等事件时,我们可以先将这些事件做成实例,然后按照发生顺序放入队列中。接着再依次去处理它们。简单来说Command模式是将处理问题的方法封装成一个类,Android的事件处理机制就用到了这一点,它将所有事件封装为Event类,通过dispatchEvent机制由具体的事件子类进行处理。命令模式私以为事件模式更为恰妥。

19.备忘录模式(Memento)--保存对象模式

Memento:a thing that you keep or give to sb to remind you or them of a person or a place.

       我们在使用文本编辑器编写文件时,如果不小心删除了某句话,可以通过撤销(undo)功能将文件恢复至之前的状态。有些文本编辑器甚至支持多次撤销,能够恢复至很久之前的版本。                                                                                                                        使用面向对象编程的方式实现撤销功能时,需要实现保存实例的相关状态信息。然后,在撤销时,还需要根据所保存的信息将实例恢复至原来状态。要想恢复实例,需要一个可以自由访问实例内部结构的权限,但是,如果稍不注意,又可能会将依赖于实例内部结构的代码分散地编写在程序的各个地方,导致程序变的难以维护,这种情况叫做破坏了程序的封装性。通过引入实例的状态角色,可以在保存和恢复实例时有效地防止对象的封装性遭到破坏,这就是所谓的Memento模式。想一下:在默认情况下,如果我们的Activity不做特殊处理,那么当系统配置发生改变后,Activity就会被撤销并重新创建,其onPause(),onStop(),onDestroy()均会调用,同时由于Activity是在异常的情况下终止的,系统会调用onSaveInstanceState()来保存当前的Activity状态,这个方法的调用时机是在onStop()之前,它和onPause()没有既定的时序关系(这个方法只出现在Activity被异常终止的情况下),当Activity被重建后,系统会调用onRestoreInstanceState(),并且把Activity销毁时onSaveInstanceState()所保存的bundle对象作为参数传递给onRestoreInstanceState()和onCreate()方法,从时序上讲,onRestoreInstanceState()调用在onStart()之前。这就是Memento的典型应用场景。

20.状态模式(State) --用类表示状态

      为每一个状态建立相应的类,在面向对象编程中,是用类表示对象的。也就是说,程序设计需要考虑考虑用类来表示什么东西。在State模式中,我们用类来表示状态。

21.访问者模式(Visitor)--访问数据结构并处理数据

       在数据结构中保存着许多元素,我们会对这些元素进行处理,通常将处理的代码放在表示数据结构的类中,但是如果处理有许多种呢,这种情况下,每当增加一种处理,我们不得不去修改表示数据结构的类。在Visitor模式中,数据结构与处理被分离开来。我们编写一个表示“访问者”的类来访问数据结构中的元素,并把对各元素的处理交给访问者类。这样,当需要增加新的处理时,我们只需要编写新的访问者,然后让数据结构可以接受的访问者的访问即可。

22.仲裁者模式(Mediator) --只有一个仲裁者

mediator:a person or an organization that tries to get agreement between people or groups who disagree with each other

一个类管理所有组员的类,组员类想仲裁者报告,仲裁者向组员下达指示,组员之间不再相互询问相互指示,在Mediator模式中,“仲裁者”被称为Mediator,个组员被称为Colleague,这个单词和Mediator的关系可能让人有些疑惑,但是GOF就是这么记述的。

23.解释器模式(Interpreter)--语法规则也是类

在Interpreter模式中,程序要解决的问题会被用非常简单的“迷你语言”表述出来,即用“迷你语言”编写的“迷你程序”把具体的问题表述出来,迷你语言是无法单独工作的,我们还需要用Java语言编写一个负责“翻译(interpreter)”的程序。翻译程序会理解迷你语言,并解释和运行迷你程序,这段翻译程序被称为解释器。

反思:

      我所论是的都是概念性的东西,想要融会贯通,不仅需要针对每个实例进行程序编写,更需要常年的经历大型开发项目。

 

      

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值