原文地址为:模式和原则 [原]
模式和原则
设计模式介绍
模式:每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。
“模式”这个词是不局限于软件开发行业的,它几乎无处不在,它其实就是一种经验的积累,就象大多数人的教育经历都是从小学到初中再到高中再到大学,这也是一种模式,是中国的教育模式;现在越来越火的出国热,也是另一种模式,海外留学模式。因为GOF的《设计模式:可复用面向对象软件的基础》一书描述的23种经典设计模式,奠定了模式在软件行业的地位,从此人们提到“设计模式”就是默指“面向对象设计模式”,但是如前文所述,模式绝对不局限于软件行业,即使在软件行业,也不局限于GOF描述的23种设计模式,例如最著名的Martin Flower的《企业架构模式》,还有我们常用的MVC、IOC等。
[说到这里,有必要声明一下的是,在该系列文章中,凡提到模式,都是指软件行业的基于GOF的《设计模式:可复用面向对象软件的基础》一书的面向对象设计模式,GRASP模式除外。]
因为模式是一种经验的积累和总结,所以通过模式,我们可以站在巨人的肩膀上去思考问题、解决问题,熟练使用设计模式可以提高我们的工作效率,改善产品质量,最终带来经济效益。因此对于任何想开发出灵活高效、健壮的软件产品的个人或团体,熟练掌握并正确使用设计模式都是必须掌握的基本技能。
所以,让我们开始吧……
比设计模式更重要:GRASP (职责分配原则)
要学习设计模式,有些基础知识是我们必须要先知道的,设计模式是关于类和对象的一种高效、灵活的使用方式,也就是说,必须先有类和对象,才能有设计模式的用武之地,否则一切都是空谈,那么类和对象是从那冒出来的呢时就需要比23种设计模式更重要更经典的GRASP模式登场了,嘿嘿,原来这才是老大!
GRASP(General Responsibility Assignment Software Patterns),中文名称为“通用职责分配软件模式”,GRASP一共包括9种模式,它们描述了对象设计和职责分配的基本原则。也就是说,如何把现实世界的业务功能抽象成对象,如何决定一个系统有多少对象,每个对象都包括什么职责,GRASP模式给出了最基本的指导原则。初学者应该尽快掌握、理解这些原则,因为这是如何设计一个面向对象系统的基础。可以说,GRASP是学习使用设计模式的基础。
1. Information Expert (信息专家)
信息专家模式是面向对象设计的最基本原则,是我们平时使用最多,应该跟我们的思想融为一体的原则。也就是说,我们设计对象(类)的时候,如果某个类拥有完成某个职责所需要的所有信息,那么这个职责就应该分配给这个类来实现。这时,这个类就是相对于这个职责的信息专家。
例如:常见的 上商店里的购物车(ShopCar),需要让每种商品(SKU)只在购物车内出现一次,购买相同商品,只需要更新商品的数量即可。如下图:
这里因为订单是商品的容器,也只有订单持有初始化商品的信息,所以这个耦合关系是正确的且没办法避免的,所以由订单来创建商品。
3. Low coupling (低耦合)
低耦合模式的意思就是要我们尽可能地减少类之间的连接。
其作用非常重要:
a. 低耦合降低了因一个类的变化而影响其他类的范围。
b. 低耦合使类更容易理解,因为类会变得简单,更内聚。
下面这些情况会造成类A、B之间的耦合:
a. A是B的属性
b. A调用B的实例的方法
c. A的方法中引用了B,例如B是A方法的返回值或参数。
d. A是B的子类,或者A实现了B
关于低耦合,还有下面一些基本原则:
a. Don’t Talk to Strangers原则:
意思就是说,不需要通信的两个对象之间,不要进行无谓的连接,连接了就有可能产生问题,不连接就一了百了啦!
b. 如果A已经和B有连接,如果分配A的职责给B不合适的话(违反信息专家模式),那么就把B的职责分配给A。
c. 两个不同模块的内部类之间不能直接连接,否则必招 应!嘿!
例如:Creator模式的例子里,实际业务中需要另一个出货人来清点订单(Order)上的商品(SKU),并计算出商品的总价,但是由于订单和商品之间的耦合已经存在了,那么把这个职责分配给订单更合适,这样可以降低耦合,以便降低系统的复杂性。如下图:
这里我们把两种不同的数据存储功能分别放在了两个类里来实现,这样如果未来保存到Excel的功能发生错误,那么就去检查OrderDAOExcel类就可以了,这样也使系统更模块化,方便划分任务,比如这两个类就可以分配个不同的人同时进行开发,这样也提高了团队协作和开发进度。
5. Controller (控制器)
用来接收和处理系统事件的职责,一般应该分配给一个能够代表整个系统的类,这样的类通常被命名为“XX处理器”、“XX协调器”或者“XX会话”。
关于控制器类,有如下原则:
a. 系统事件的接收与处理通常由一个高级类来代替。
b. 一个子系统会有很多控制器类,分别处理不同的事务。
关于这个模式更详细的论述,请参考《UML和模式应用》第16章。
6. Polymorphism (多态)
这里的多态跟OO三大基本特征之一的“多态”是一个意思。
例如:我们想设计一个绘图程序,要支持可以画不同类型的图形,我们定义一个抽象类Shape,矩形(Rectangle)、圆形(Round)分别继承这个抽象类,并重写(override)Shape类里的Draw()方法,这样我们就可以使用同样的接口(Shape抽象类)绘制出不同的图形,如下图:
这里我们可以看到,因为增加了纯虚构类AbstractShape,不论是哪个系统都可以通过AbstractShape类来绘制图形,我们即没有降低原来的内聚性,也没有增加过多的耦合,可谓鱼肉和熊掌兼得,哈哈哈!
8. Indirection (间接)
“间接”顾名思义,就是这个事不能直接来办,需要绕个弯才行。绕个弯的好处就是,本来直接会连接在一起的对象彼此隔离开了,一个的变动不会影响另一个。就想我在前面的低耦合模式里说的一样,“两个不同模块的内部类之间不能直接连接”,但是我们可以通过中间类来间接连接两个不同的模块,这样对于这两个模块来说,他们之间仍然是没有耦合/依赖关系的。
9. Protected Variations (受保护变化)
预先找出不稳定的变化点,使用统一的接口封装起来,如果未来发生变化的时候,可以通过接口扩展新的功能,而不需要去修改原来旧的实现。也可以把这个模式理解为OCP(开闭原则)原则,就是说一个软件实体应当对扩展开发,对修改关闭。在设计一个模块的时候,要保证这个模块可以在不需要被修改的前提下可以得到扩展。这样做的好处就是通过扩展给系统提供了新的职责,以满足新的需求,同时又没有改变系统原来的功能。关于OCP原则,后面还会有单独的论述。
比设计模式更重要:设计原则
我们生活在一个充满规则的世界里,在复杂多变的外表下,万事万物都被永恒的真理支配并有规律的运行着。模式也是一样,不论那种模式,其背后都潜藏着一些“永恒的真理”,这个真理就是设计原则。记得一次参加微软的架构师培训,期间讲到设计模式,有人问了老师一个问题:“什么东西比设计模式更重要,老师是一位有多年丰富实践经验的开发者,他毫不犹豫地回答到:“比模式更重要的是原则”。这句话我时常能够想起,越来越觉得这是一个伟大的答案。的确,还有什么比原则更重要呢像人的世界观和人生观一样,那才是支配你一切行为的根本,而对于设计模式来说,为什么这个模式要这样解决这个问题,而另一个模式要那样,它们背后都遵循的就是永恒的设计原则。可以说,设计原则是设计模式的灵魂。
对于设计原则的深入探讨我还没有那个深度,推荐大家去看《敏捷软件开发—原则、模式与实践》,下面仅对部分常用的设计原则做些简单的讲解:
1. 单一职责原则(SRP)
“就一个类而言,应该仅有一个引起它变化的原因。”也就是说,不要把变化原因各不相同的职责放在一起,因为不同的变化会影响到不相干的职责。再通俗一点地说就是,不该你管的事情你不要管,管好自己的事情就可以了,多管闲事害了自己也害了别人。(当然这里说的多管闲事跟见义勇为是两回事,我们提倡见义勇为!)
例如:参考下图中的设计,图形计算程序只使用了正方形的Area()方法,永远不会使用Draw()方法,而它却跟Draw方法关联了起来。这违反了单一原则,如果未来因为图形绘制程序导致Draw()方法产生了变化,那么就会影响到本来毫不关系的图形计算程序。
2. 开放—封闭原则(OCP)
“软件实体(类、模块、函数等)应该是可以扩展的,但是不可修改。”嘿!多么朴实的话语,第一次看这个原则的时候我都看傻了,我当时在想“这不是&#%做白日梦吗!不修改怎么扩展啊但是随着学习的深入,理解了这个“不修改”是什么意思,意思是“你可以随便增加新的类,但是不要修改原来的类”。从这个角度去理解就好多了,其实这里还是一个隔离变化的问题。
例如:如下图,有一个客户端程序通过数据访问接口操作数据,对于这套系统来说,一开始计划使用的是SQL Server或Oracle数据库,但是后来考虑到成本,改用免费的MySQL;那么对于客户端程序来说,后来数据的扩展对它没有任何影响,它在不知不觉间就用上了免费好用的MySQL数据库,这全要感谢OCP原则。
那么我们该如何来设计一个通用的开关呢考下图的设计,OK!现在我们不仅可以打开灯,还可以打开电视和音响,甚至未来任何实现了“开关接口”的任何东西。
![模式和原则 [原]](https://www.iruanshi.com/news2/wp-content/uploads/2023/02/slt.png)
4. 接口隔离原则(ISP)
“不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。”这个说得很明白了,再通俗点说,不要强迫客户使用它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!