什么是设计模式,为什么要学习设计模式?
设计模式的概念
在软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。这个术语是由埃里希·伽玛(Erich Gamma)等人在1990年代从建筑设计领域引入到计算机科学的。
设计模式并不直接用来完成代码的编写,而是描述在各种不同情况下,要怎么解决问题的一种方案。面向对象设计模式通常以类别或对象来描述其中的关系和相互作用,但不涉及用来完成应用程序的特定类别或对象。设计模式能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免会引起麻烦的紧耦合,以增强软件设计面对并适应变化的能力。
学习设计模式的意义
- 设计模式本质上是对面向对象设计的描述,是对对象的封装,继承,多态,组合等设计的更深入的理解。
- 为了提高代码的易读性、可维护性和可扩展性。
- 能提高源码阅读能力。
一般而言,一个模式有四个基本要素
- 模式名称(pattern name): 一个助记名,它用一两个词来描述模式的问题、解决方案和效果。命名一个新的模式增加了我们的设计词汇。设计模式允许我们在较高的抽象层次上进行设计。基于一个模式词汇表,我们自己以及同事之间就可以讨论模式并在编写文档时使用它们。 模式名可以帮助我们思考,便于我们与其他人交流设计思想及设计结果。找到恰当的模式名也是我们设计模式编目工作的难点之一。
- 问题(problem):简单来说就是你想在某种情景下达成的目标,但也可以是某种约束。描述了应该在何时使用模式。它解释了设计问题和问题存在的前因后果,它可能描述了特定的设计问题,如怎样用对象表示算法等。也可能描述了导致不灵活设计的类或对象结构。有时候,问题部分会包括使用模式必须满足的一系列先决条件。
- 解决方案(solution):通过一个通用的设计,可以解决约束,达成目标。 描述了设计的组成成分,它们之间的相互关系及各自的职责和协作方式。因为模式就像一个模板,可应用于多种不同场合,所以解决方案并不描述一个特定而具体的设计或实现,而是提供设计问题的抽象描述和怎样用一个具有一般意义的元素组合(类或对象组合)来解决这个问题。
- 效果(consequences) 描述了模式应用的效果及使用模式应权衡的问题。尽管我们描述设计决策时,并不总提到模式效果,但它们对于评价设计选择和理解使用模式的代价及好处具有重要意义。软件效果大多关注对时间和空间的衡量,它们也表述了语言和实现问题。因为复用是面向对象设计的要素之一,所以模式效果包括它对系统的灵活性、扩充性或可移植性的影响,显式地列出这些效果对理解和评价这些模式很有帮助。
如何描述设计模式
将用统一的格式描述设计模式,每一个模式根据以下的模板被分成若干部分。模板具有统一的信息描述结构,有助于更容易地学习、比较和使用设计模式。
- 模式名和分类 模式名简洁地描述了模式的本质。一个好的名字非常重要,因为它将成为你的设计词汇表中的一部分。模式的分类反映了模式的目的和范围。
- 意图 是回答下列问题的简单陈述:设计模式是做什么的?它的基本原理和意图是什么?它解决的是什么样的特定设计问题?
- 适用性 什么情况下可以使用该设计模式?
- 效果 模式的优缺点
如何使用设计模式
使用设计模式的初衷是为了提高代码的易读性,维护性和可扩展行,不能为了使用而使用。应根据不同的需求和业务场景,选择合适的设计模式。并且你会发现有些设计模式存在相似性,因此在使用时不用在意一定要用哪种设计模式。
为了保证实现高内聚,低耦合,高可用,易维护,易扩展,需要遵循相应的设计原则,然而在学习设计模式时,你会发现并这些模式没有完全按照设计原则,这就涉及到了取舍问题,要对目标(要解决的问题)和约束(成本)进行平衡。
设计原则
1.开闭原则
开放封闭原则(Open-Closed principle):可扩展,不可修改。开发扩展功能,关闭修改功能。这样做是为了保证稳定性,延续性和扩展性。
实现方式:将整体分为可变和不可变两部分,可变部分抽象成接口或实现类。通过组合或实现的方式将两部分结合起来。使用面向对象的继承和多态,可动态的扩展,并且保证了内部的稳定性。2.单一职责原则
单一职责原则(Single-Responsibility Principle):一个类应该有且仅有一个引起它变化的原因,否则应该被拆分。
如果一个类承担了太多的职责,会导致该类不仅将非必须的功能加进来,削弱了其他类的功能,而且导致该类过于冗余,可读性变差,复杂度提升,不利于维护。3.里氏替换原则
里氏替换原则(Liskov Substitution Principle,LSP):子类可以替换父类,但不能改变父类原有的功能。 里氏替换原则是实现开闭原则的重要方式之一。通过面向接口编程,创建接口或抽象类作为父类来保证子类不重写父类的公共方法。
4.依赖倒置原则
依赖倒置原则(Dependecy-Inversion Principle): 高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。要面向接口开发,降低两者之间的耦合度。
5.接口隔离原则
接口隔离原则(Interface-Segregation Principle):和单一职责类似,为了保证接口的高内聚,低耦合。降低接口颗粒度,提高灵活性和可维护性。
23种设计模式的功能和分类
根据设计模式的目的和范围进行分类。
- 目的:表示使用设计模式可以完成什么,分为三类:创建型(创建对象);结构型(处理类或对象的组合);行为型(对类或对象怎么交互和怎样分配职责进行描述)。
- 创建型:都涉及到将对象实例化,这些模式都会提供一个方法,将其与实例化的对象中解耦。
- 结构型:可以将类或对象放入更大的组合中,针对结构的改变
- 行为型:涉及到类或对象之间如何交互及分配职责。
- 范围:模式用于类还是用于对象。类模式用于处理类和子类之间的关系,在编译器已经确定,数据静态的。对象模式处理对象间的关系,运行期调用才能确定,属于动态变化的。从某种意义上来说,几乎所有模式都使用继承机制,所以“类模式”只指那些集中于处理类间关系的模式,而大部分模式都属于对象模式的范畴。 创建型类模式将对象的部分创建工作延迟到子类,而创建型对象模式则将它延迟到另一个对象中。结构型类模式使用继承机制来组合类,而结构型对象模式则描述了对象的组装方式。行为型类模式使用继承描述算法和控制流,而行为型对象模式则描述一组对象怎样协作完成单个对象所无法完成的任务。 |范围 |创建型|结构型 |行为型 | | --- | --- | --- | --- | | | | | 类 |工厂方法(FactoryMethod)|适配器模式(类Adapter) |解释器(Interpreter),模板方法模式(TemplateMethod) | | 对象 | 抽象工厂(Abstract Factory);建造者模式(Builder);原型模式(Prototype);单例(Singleton) | 适配器模式(对象Adapter);桥接模式(Bridge);组合模式(Composite);装饰器模式(Decorator);外观模式(Facade);享元模式(Flyweight);代理模式(Proxy) | 责任链模式(Chain of Respoinsibility);命令模式(Command);迭代器模式(Iterator);中介者模式(Mediator);备忘录模式(Memento); 观察者模式(Observer);状态模式(State);策略模式(Strategy);访问者模式(Visitor) | | | |
参考书籍
《设计模式可复用面向对象软件基础》
《Head First 设计模式》