第二课 设计模式的原则
今天准备讲一下设计模式中的原则。其实设计模式的存在,就是为了能够实现这些原则。这里不需要大家一次就搞懂,有点印象,有点感觉就好了。本讲里面会结合上一课中的例子。
下面,开始吧。
首先,先来看一下基本的几个原则。
1. 开闭原则。( Open - Closed Principle 缩写:OCP ),这个是基本原则哦。要注意。
2. 可变性的封闭原则。
3. 里氏代换原则
4. 依赖倒转原则
5. 迪米特法则
6. 接口隔离原则
上述6项应该是设计模式涉及的基本原则,看着很晕吧,不要被他的名字唬住哦,下面我们来解释一下。
1. 开闭原则。
所谓开闭原则,说的是对扩展开放,对修改关闭。意思也很简单,就是一个好的系统,应该有良好的扩展性,并且不应被修改。看上去好像矛盾是吧,这里我把说法改变一下。 一个好的系统,首先应通过接口定义基本方法及处理流程。方法应当能够很好的被扩展(实现),接口中定义的基本方法不应被修改。 看着还有点晕吗。那么回想下上一讲中的例子。IWork是一个接口,定义了工作中需要的行为。Worker和Manager都实现这个接口,并实现了相应的GetPay()发工资和Work()工作的方法。那么你说现在扩展性怎么体现呢。简单说我想在新加一个角色,比方说Boss吧。那么我依然可以实现IWork接口,并通过重写相应的方法来定义Boss这个角色。并且它不影响我们发工资的方法 DoWages(IWork iw)。并且由于他也有着自己Work()方法的实现,并不影响他融入系统执行自己的工作。回头看一下,我只是扩展了IWork的一个新的对象,并没有修改IWork定义的方法对不,这就是开闭原则的一个简单的例子。
总结一下,开闭原则的实现,依赖于对 对象,工作流的抽象。在"开-闭"原则中,不允许修改的是抽象的类或者接口,允许扩展的是具体的实现类。这样的话,新扩展出来的类对象,可以很简单的融入原有系统的处理方式中(接口定义的处理方式),从而避免了对处理流程的修改(接口的修改)避免了系统大规模的改动。这就是开闭原则存在的意义,也是所有设计模式的目的所在。
2. 可变性的封闭原则
可变性封装原则就是,如果系统中存在这么一个环节,他可能由于各种不同因素,存在着可变性,那么应当把这个环节的处理方式封装起来,达到对可变性进行封装的目的。即:找到系统的可变因素,将它封装起来。可变性封闭原则是对开闭原则的一个实现。这里依然可以套用上面的例子。工作这个动作,存在着可变性。一个是发工资,一个是工作内容。根据工作人员岗位的不同,这两个动作的实现是不同的。所以这里把它提出到IWork这个接口中,进行封装,将发工资与工作进行封装,从而定义了我系统的处理方法。----能够工作的对象,必须要实现IWork接口,需要执行发工资或者工作的时候,直接转化为IWork对象调用.GetPay() 或者 .Work()来进行。这样,就可以认为,我把工作这个环节的可变因素发工资和工作内容进行了封装。
可变性封闭原则的注意事项是,不要将可变因素封装到一起。封装一定要是最基本的动作,一些复杂动作可以通过调用基本动作来实现。根据逻辑关系,分块封装可变因素,可以避免超长类,超长方法的出现,同时明确逻辑关系。以上。
3. 里氏代换原则
任何基类可以出现的地方,子类也可以出现。简单的说,基类对象可以引用子类实例。接口同样适用。仔细想一下,对于类的集成,子类继承了基类所有的属性和方法;对于接口和虚类,实现接口的类必须实现接口和虚类中定义的所有方法。这就意味着,基类能执行的所有动作,子类全部都能够执行。所以把子类当作基类来用是没有任何问题的,只可能根据子类不同,对基类动作的实现不同而已。
想想Work调用Eat()方法,Manager调用Eat方法。我是不是可以Person p = new Worker();这样来使用呢?
同样 IWork iw = new Worker();也是没有任何问题的是吗。
这就是里氏代换原则。
4. 依赖倒转原则
要依赖抽象,不要依赖实现。就像开闭原则里面介绍的一样,抽象是实现开闭原则的基础。这里也可以这么说,开闭原则是我们要达到的目标,依赖倒转原则是为了实现这个目标而采取的手段一样的东西。我感觉依赖倒转是里氏代换原则的补充,都是为了实现开闭原则。大家可以结合上文,慢慢体会。
5. 迪米特法则
系统中的类,尽量不要与其他类互相作用。这就是迪米特法则的定义。即众人皆知的低耦合。在系统中,如果类之间的耦合性高的话,一旦某个类需要修改,可能会引起一系列的类都需要修改,增加了维护的难度,所以大家都知道,要降低类之间的耦合性。降低的方法呢,就是上述方法,抽象。简单举个例子(其实我也不知道合适不合适,大家领会精神),现在我们成立一家公司。公司有3个角色。Boss,Manager,Worker。正常的工作呢,我们需要3人来协作不是。Boss管理Manager,Manager管理Worker。简单来说就是 Boss.Work();Manager.Work();Worker.Worker(); 这样的调用。因为我们抽象出去了IWork这个接口。这样我们遵循了迪米特法则。现在假设我Boss对象职责扩大了,他也可以直接管理Worker对象了,怎么办呢。我们不需要改上述3句代码。我只需要在Boss类对IWork接口的实现的Work()方法进行调整即可。这样改动起来是否很简单。大家慢慢体会吧。
6. 接口隔离法则
应当为客户端提供尽可能小的单独的接口,而不要提供大的总接口。这是为了什么呢,答案,为了进一步抽象。如果每个接口定义的都是实现一个操作的最基础的方法。那么即使再复杂的方法我一可以通过各个接口的调用来实现,从而实现了减少类之间的耦合度,实现迪米特法则。
呵呵,是不是很抽象很难懂啊。这里不需要完全理解这些原则,对他有一个印象就可以了。通过下面具体设计模式的讲解,会慢慢体会到的。好的,第二课结束,下一讲咱们讨论下单态这种最常见的设计模式吧,总算要进入正题了哦。
注:本文在下第一次原创哦,转载请注明出处
作者:王文斌