设计基础-常用的设计模式杂记
计算机工程师做的工作某个方面和建筑师差不多,尤其是做项目的时候。
既然是做项目,必然要考虑投入产出,所以产生了软件工程的学科。软件工程告诉我们如何控制项目,包括可行性到维护等方方面面的管理过程。
不过大部分的工程师并不关心那个,他们更多是思考如何技术上实现。
但是设计师必须意识到不同的方法会带来不同的投入产出,所以有人根据前人的经验做了总结,搞出了两个东西:
1.设计原则 (指导性要求)
2.设计模式(设计套路)
后者主要是为了满足前者而存在的,少数是为了解决工程技术问题而存在。所以有必要先充分了解设计原则。
设计原则的存在也是为了保证一个目标:提升工程的质量(时间更少,成本更低)。
目前常见的原则是:
1.里氏替换换原则 -- 这个不好说。想法很好,但是让让人迷惑。
总结下,就是更加合理的设计类和类之间的关系(因为按照这个原则,override并不推荐,但不override,那么OOP的作用就弱了些)。
使得一个祖宗之法可以传递到各处,以此减少修改的必要性,但需要花费更多的心思来设计。
如果因为某些原因需要override ,那么应该思考是否改变类和类之间的关系(例如增加类的层次)。
2.迪米特原则(最少知道原则) -- 不要让我累,我不想知道那么多
3.开闭原则--简单一点,能不动就不动,动了可能会出现一些不可知的问题
4.依赖导致(接口原则)
5.单一原则
6.接口隔离原则
以上六个原则大体可以简化为三个:
a.少修改,多扩展
b.尽量简单,单纯一些,无论对内还是对外
c.尽量基于接口做开发
仔细地结合自己做过的项目,就很能够体会,尤其是维护多个他人编写的项目之后。
因为人的能力还是相当有限的,必须把东西做得尽量简单一点。只不过把复杂的东西变得简单,常常是很不简单的。我们常常说某些文章通俗易懂,其实就已经是一个较好的赞誉。
所以,个人的感觉上,这些原则都是为了较少维护而立下的。如果一个程序员不遵守这些,那么这样的人就不应该存在团队之中--要么毫无职业素养,要么能力严重欠缺。实乃害群之马。
有了这两个东西,就可以较好地配合项目经理,对项目进行管控--主要实现进度和成功控制。
不过在开始正式阐述之前,我需要说说另外一个很重要的内容:开发规范。
我们把眼界放开一点,就会发现其实前文提到的两个内容,不外乎人们的经验:无规矩不成方圆。
某些微小团体可能并不怎么关注这个,但是有个事情还是强烈建议先完成:定义属于自己团队的开发规范,让代码看起来整齐划一。
这个也可以算是某种程度的原则和模式的统一规范。
但我还是强烈建议团队的成员必须掌握这些基本的东西。毕竟大部分人都是普通得不能再普通的个体,没有天纵之才,没有发明新的工具之前,就不要妄想无招胜有招了。
在工作的时候,最烦的就是没有规范导致的一些问题,以及项目维护的时候,看一些乱起八糟的代码。
闲话少叙,本人由于工作需要,也简单地浏览了下有关设计模式的东西,发现的确是有可用之处。
这些资料主要来自于设计模式 | 菜鸟教程 (runoob.com)。
这些资料整体还是很完善,而且通俗易懂。建议可以在这里学习,以便减少不必要的支出。
菜鸟网整理的设计模式挺多的。但实际工作的时候,大部分用不着,这和大家一个道理,好用的常用的就几招。一些非常个性化的就只能使用于一些非常特殊的场景。
由于菜鸟网有详细的资料,这里就不一一重复了。下面只列出本人比较关注的一些内容
名称 介绍主要解决 优点缺点(代价)使用场景例子名称 介绍主要解决 优点缺点(代价)使用场景例子:名称 | 介绍 | 主要解决 | 优点 | 缺点(代价) | 使用场景 | 例子 |
---|---|---|---|---|---|---|
单例 |
这种模式涉及到一个单一的类,该类负责创建自己的对象, 同时确保只有单个对象被创建。 这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象 |
一个全局使用的类频繁地创建与销毁 |
在内存里只有一个实例,减少了内存的开销, 尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存) 避免对资源的多重占用(比如写文件操作) |
没有接口,不能继承,与单一职责原则冲突, 一个类应该只关心内部逻辑,而不关心外面怎么样来实例化 |
不需要属性 或者是属性必须保持唯一的时候 |
|
工厂 |
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑, 并且是通过使用一个共同的接口来指向新创建的对象 |
接口选择 简化各个需要创建类似对象的代码的编写 |
1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口 |
要维护工厂 |
有许多类似的类要创建, 简化客户端代码 |
|
代理 | 创建具有现有对象的对象,以便向外界提供功能接口 | 比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问 |
按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理 |
|||
适配器 (转换器) |
转换一个现存对象的功能以便满足另外一些要求 |
主要解决在软件系统中,常常要将一些"现存的对象"放到新的环境中,而新环境要求的接口是现对象不能满足的。 重用现有功能 |
||||
装饰 | 创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能 |
重用现有类;增加一些功能。 (某种程度上优点象代理) |
||||
观察者 | 当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式 | 一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作 |
1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。 2、如果在观察者和观察目标之间有循环依赖的话, 观察目标会触发它们之间进行循环调用,可能导致系统崩溃。 3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化 |
|||
模板 | 一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式(实际就是对象继承) | 一些方法通用,却在每一个子类都重新写了这一方法 |
如果我们认真看下已有的模式,会发现有些还是基本不用的,这些不需要刻意去理解,只需要记住有这个东西,在需要的时候,可以回来研究下。
如果您的团队主要是做一些常规的应用开发,其实不需要过分关注设计模式(虽然有的已经不自觉地使用了),因为大部分的此类应用用不着动太多的脑筋,大体简单地复制粘贴就差不多了。
话虽如此,有备无患总是好的!