设计模式的总结有助于构建软件开发知识体系,为后期软件的架构设计、重构打下夯实基础,所以开设了Android设计模式专栏,后期会投入一定的精力深入学习和总结设计模式,并把相关理论知识与实际项目中用到的设计模式结合起来记录于此,敬请关注和交流。
本文重在总结设计模式和设计原则,后期会结合具体实例代码来说明常用的设计原则和设计模式。
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的;设计模式使代码编制真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
而设计原则则是设计模式所遵循的规则,设计模式就是实现了这些原则,从而达到了代码复用、增加可维护性的目的。
一个类,只有一个引起它变化的原因。应该只有一个职责。每一个职责都是变化的一个轴线,如果一个类有一个以上的职责,这些职责就耦合在了一起。这会导致脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起,会影响复用性。例如:要实现逻辑和界面的分离。
软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
封装变化,是实现开放封闭原则的重要手段,对于经常发生变化的状态一般将其封装为一个抽象。
拒绝滥用抽象,只将经常变化的部分进行抽象,这种经验可以从设计模式的学习与应用中获得。
里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。它包含以下4层含义:
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
- 子类中可以增加自己特有的方法。
- 当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
- 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
最少知识原则又叫迪米特法则。核心思想是:低耦合、高内聚
一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。也就是说一个软件实体应当尽可能少的与其他实体发生相互作用。这样,当一个模块修改时,就会尽量少的影响其他的模块,扩展会相对容易,这是对软件实体之间通信的限制,它要求限制软件实体之间通信的宽度和深度。
接口隔离原则的含义是:建立单一接口,不要建立庞大臃肿的接口,尽量细化接口,接口中的方法尽量少。
采用接口隔离原则对接口进行约束时,要注意以下几点:
- 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
- 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
- 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
依赖倒置原则的核心思想是面向接口编程,不应该面向实现类编程。
在实际编程中,要做到下面3点:
- 低层模块尽量都要有抽象类或接口,或者两者都有。
- 变量的声明类型尽量是抽象类或接口。
- 使用继承时遵循里氏替换原则。
Single Responsibility Principle单一职责原则
Open Closed Principe开闭原则
Liskov Substitution Principe里式替换原则
Law of Demeter迪米特法则
Interface Segregation Principe接口隔离原则
Dependence Inversion Principe依赖倒置原则
把上面的六个原则的英文的首字母拿出来拼一下,就是SOLID(solid,稳定的),其代表的含义也就是把这六个结合使用的好处:建立稳定、灵活、健壮的设计,而开闭原则又是重中之重、最基础的原则,是其他五大原则的精神领袖。
除了以上六大设计原则之外。还有一些其他的设计原则,下面只做简单介绍,
当要扩展类的功能时,优先考虑使用组合,而不是继承。这条原则在 23 种经典设计模式中频繁使用,如:代理模式、装饰模式、适配器模式等。可见江湖地位非常之高!
这也是面向对象中的一个重要原则。
当 A 模块依赖于 B 模块,B 模块依赖于 C 模块,C 依赖于 A 模块,此时将出现循环依赖。在设计中应该避免这个问题,可通过引入“中介者模式”解决该问题。
应该将易变的类放在同一个包里,将变化隔离出来。该原则是“开放-封闭原则”的延生。
如果重用了包中的一个类,那么也就相当于重用了包中的所有类,我们要尽可能减小包的大小。
好莱坞明星的经纪人一般都很忙,他们不想被打扰,往往会说:Don’t call me, I’ll call you. 翻译为:不要联系我,我会联系你。对应于软件设计而言,最著名的就是“控制反转”(或称为“依赖注入”),我们不需要在代码中主动的创建对象,而是由容器帮我们来创建并管理这些对象。
不要让重复的代码到处都是,要让它们足够的重用,所以要尽可能地封装。
不要让系统变得复杂,界面简洁,功能实用,操作方便,要让它足够的简单,足够的傻瓜。
模块内部需要做到内聚度高,模块之间需要做到耦合度低。
尽量让惯例来减少配置,这样才能提高开发效率,尽量做到“零配置”。很多开发框架都是这样做的。
在定义接口时,要做到哪些是命令,哪些是查询,要将它们分离,而不要揉到一起。
将一个复杂的问题分离为多个简单的问题,然后逐个解决这些简单的问题,那么这个复杂的问题就解决了。难就难在如何进行分离。
模块或系统之间的交互,都是基于契约(接口或抽象)的,而不要依赖于具体实现。该原则建议我们要面向契约编程。
不要一开始就把系统设计得非常复杂,不要陷入“过度设计”的深渊。应该让系统足够的简单,而却又不失扩展性,这是其中的难点。
六大原则 | ||
---|---|---|
接口隔离原则 | 单一职责原则 | 依赖倒转原则 |
迪米特法则 | 里氏替换原则 | 开闭原则 |
创建型模式 | ||
---|---|---|
抽象工厂模式 | 工厂方法模式 | 建造者模式 |
单例模式 | 原型模式 |
结构型模式 | ||
---|---|---|
适配器模式 | 代理模式 | 桥接模式 |
组合模式 | 装饰器模式 | 外观模式 |
享元模式 |
行为型模式 | |||
---|---|---|---|
责任链模式 | 命令模式 | 中介者模式 | 解释器模式 |
观察者模式 | 迭代子模式 | 备忘录模式 | 访问者模式 |
状态模式 | 策略模式 | 模板方法模式 |
类型 | 口诀 | 额外 |
---|---|---|
六个原则 | 接单依赖迪里开 | 无 |
创建型模型 | 抽工建单元 | 无 |
结构型模型 | 与时代相结合,装外向 时(适配器模式)代(代理模式)结(桥接模式)合(组合模式),装(装饰模式)外(外观模式)向(享元模式); |
无 |
行为型模型 | 责令中介观叠被,防撞车 责(责任链模式)令(命令模式)中介(中介模式)观察(观察者模式)叠(迭代器模式)被(备忘录模式),防(访问者模式)撞(状态模式)车(策略模式) |
模板方法模式 |
参考资料:
1.如何一分钟记住23种设计模式
2.设计模式之六大设计原则
3.设计模式之禅【六大设计原则】有代码实例
4.参考书籍《设计模式之禅》