《设计模式》学习笔记1——七大面向对象设计原则

前言

根据这一次的学习计划,系统学习设计模式之前,先系统学习和理解设计原则。面向对象设计原则有如下几类。

原则一:单一职责原则

这是面向对象最简单的原则,对于定义,引用书中所说:

单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因

这里最重要的地方,我个人觉得应该是一个功能领域这一句。
设计的前提是思考,只有进行了思考才能谈得上设计,所以实际设计过程中最重要的还应该是思考究竟哪些才是一个功能领域,也只有确定了这个,才能真正的遵循单一职责原则。

这个原则让我想起最近重构中一个功能设计的问题,很明显一开始的设计并没有遵循单一职责原则。
这项功能涉及到三个子系统A、B、C,我们需要从A系统向B系统发送http请求,发送过程中带了两个参数,一个是具体对象数据obj,一个是动态获取的B系统向C系统发送请求的请求url等相关信息。
我们当时是在A系统中写了一个httpService来处理向B系统发送请求,在一个方法中同时做了这样三件事:
1. 封装obj数据对象;
2. 动态获取B向C发送请求的相关请求信息;
3. 正式向B发送请求;

很明显的,这个类的这个方法看起来做的都是跟发送请求相关的事,但是仔细分析后会发现其实引起这个方法改变的原因至少会有三个,因此至少应该把这三件事分为三个方法来处理。

原则二:开闭原则

开闭原则引用书中的定义如下:

开闭原则(Open-Closed Principle, OCP):一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展

这里最重要的应该是软件实体四个字,只有正确的理解了何为软件实体,才能更好的用好开闭原则,书中对软件实体定义如下:

在开闭原则的定义中,软件实体可以指一个软件模块、一个由多个类组成的局部结构或一个独立的类。

对于开闭原则,我个人理解就是说,可以继承或实现某个类,在这个类的基础上增加功能,但是不能直接去改这个类。
然而,在实际实施的过程中显然是不太容易做到的,这通常需要一定的开发功力,可能还需要先遵循其他一些原则,这个原则才会具有实现的可能。
就比如上边说的单一职责原则,如果没有非常好的遵循单一职责原则,各种功能糅合在一起,那么必然在后期拓展的过程中难以做到很好的开闭。这时候可能能对拓展开放,却未必能对修改做到关闭,可能发现很多时候必须修改原本的类才行。

同样是上边举例的那个功能,根据单一职责原则,我们把三件事分到了三个方法中实现,但是依然存在着其他的问题。
就比如封装数据对象这件事,由于很多个业务公用一个请求,在参数个数固定的情况下,不同的业务数据使用的数据对象封装就必然会有所不同。
当我们用一个方法处理这些数据封装的时候,就必须使用若干个if/else这样的判断语句,那么一旦后边有新业务加入或者旧业务需要修改,必然需要改动这个方法和这个类,所以更好的办法应该是针对不同业务的不同数据使用不同的方法或者类来进行处理。

原则三:里氏替换原则

里氏替换原则引用书中的定义如下:

里氏代换原则(Liskov Substitution Principle, LSP):所有引用基类(父类) 的地方必须能透明地使用其子类的对象

在我目前记下的三个原则中,这个恐怕是我觉得最好理解也是最容易做到的了,因为平常开发的过程中几乎时时刻刻都在写着接口和实现类。
而这个原则简单点理解,就是说用接口或者其他类型的父类调用的任何一个方法,都必须要能用这个父类的任何一个子类进行调用;任何一个用父类作为参数的地方,要也都能用任何一个子类作为参数。
里氏替换,其实可以理解为就是用子类代替父类。

原则四:依赖倒转原则

依赖倒转原则引用书中的定义如下:

依赖倒转原则(Dependency Inversion Principle, DIP):抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程

这个原则和上一个原则乍一看起来我觉得好像是雷同了,但是仔细分析一下后发现其实并没有。
里氏替换原则更具体点理解,说的是父类和子类在各自定义的时候应该遵循的一种原则,重点在于父类和子类的定义。
而依赖倒转原则说的则应该是如何更合理使用父类和子类,重点在于如何使用。
但是这两个原则说的都是父类和子类的问题,因此很显然也有必然的联系,只有遵循里氏替换原则合理的定义了父类和子类,才可能更合理的遵循依赖倒转原则。
因此这也涉及到一个问题,子类虽然从语法上来说可以有自己的对外开放的方法,那么是否应该提供这样的方法呢?
很显然的,如果要完全遵循依赖倒转原则,子类就不应该定义自己的对外开放的方法,否则针对接口编程的时候,那子类的那些对外开放的特有方法就成了摆设。

原则五:接口隔离原则

接口隔离原则引用书中的定义如下:

接口隔离原则(Interface Segregation Principle, ISP):使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

对于这个原则,我倒觉得他更像是单一职责原则的补充,或者说是一个更小维度的单一职责原则,因为我觉得接口实际上也可以理解成单一职责原则中说的某个功能领域
而“使用多个专门的接口而不是一个总接口”,这也直接体现了单一职责,只不过这里可能是更小维度的单一职责,目的是为了避免一个接口中过多的功能造成依赖于他的客户端做出一些不必要的工作。
那么如果再结合前两个原则来说,我更觉得他们就是一个整体,首先里氏替换原则概括的说明了父类和子类应该以何种关系定义,然后依赖倒转原则又说了父类和子类应该如何使用,再然后这里的接口隔离原则就更进一步具体说明了父类接口应该如何更好的定义。

原则六:合成复用原则

合成复用原则引用书中的定义如下:

合成复用原则(Composite Reuse Principle, CRP):尽量使用对象组合,而不是继承来达到复用的目的

根据我的理解,复用一般指的是自己本身不具备的方法,但可以拿来使用,而实现方式通常是组合、聚合和继承。
继承指的是,在父类中写的方法被子类继承后,子类不需要再写一遍这个方法,子类的对象就可以调用。
组合指的是,声明一个类的时候,把另一个类以属性的方式声明,然后在这个类的对象中便包含了那个类的对象,然后这个类的对象中就可以调用那个类中的方法,从而实现自己不用定义,当能实现某些功能。
而聚合通常是说把另一个类的对象以参数的方式传进来,然后这个类的对象的方法中也就可以调用参数对象的方法,这样也实现了自己不定义,但能实现某些功能。
以上三种方式都能实现代码和功能的福永,减少了重复代码,但是继承会破坏类的封装性,把父类的实现细节暴露给子类,同时如果父类声明为不可被继承,那么还不能被复用,这些都是非必要,不建议使用继承复用的原因。
相反的,组合和聚合就更加的灵活,具体的实现也不会暴露给其他组合的类,因此建议使用组合和聚合实现代码和功能的复用,也就是合成复用原则。

原则七:迪米特法则

迪米特法则引用书中的定义如下:

迪米特法则(Law of Demeter, LoD):一个软件实体应当尽可能少地与其他实体发生相互作用

迪米特法则又称为最少知识原则、最少知道原则,说白了,就是一个类中定义的属性、方法这些应当严格定义访问权限,只暴露必须暴露出来的,而私有不必要暴露出来的。
之所以要这样做,是因为当一个类暴露出过多的内容在外边时,一方面会使引起他变化的因素变多,情况变得复杂,另一方面也会使得使用这个类的时候造成选择的困难。

时间: 2024-07-30 14:52:12

《设计模式》学习笔记1——七大面向对象设计原则的相关文章

Java程序员应当知道的10个面向对象设计原则

(设计原则)底线是永远追求高内聚.低耦合的编码或设计. Apache 和 Sun的开源代码是学习Java和OOPS设计原则的良好范例.它们向我们展示了,设计原则在Java编程中是如何使用的.Java JDK 使用了一些设计原则:BorderFactory类中的工厂模式.Runtime类中的单例模式.java.io 类中的装饰器模式.顺便说一句,如果您真的对Java编码原则感兴趣,请阅读Joshua Bloch 的Effective Java,他编写过Java API.我个人最喜欢的关于面向对象设

程序员应知道这十大面向对象设计原则

面向对象设计原则是OOPS编程的核心, 但我见过的大多数Java程序员热心于像Singleton (单例) . Decorator(装饰器).Observer(观察者) 等设计模式, 而没有把足够多的注意力放在学习面向对象的分析和设计上面.学习面向对象编程像"抽象"."封装"."多态"."继承" 等基础知识是重要的,但同时为了创建简洁.模块化的设计,了解这些设计原则也同等重要.我经常看到不同经验水平的java程序员,他们有的不

OOAD之面向对象设计原则

学习这个设计模式 真的觉得很抽象,只有自己多多的领会! 在很多时候,很多的知识都会觉得讲起来是很矛盾的. 本章目标 1 掌握内聚度和耦合度的概念 2 掌握面向对象设计原则    (一)如何衡量软件设计的质量 内聚度:表示一个应用程序的单个单元所负责的任务数量和多样性.内聚与单个类或者单个方法单元相关.(在我自己的理解就是:在一个类中完成自己所有的任务,这些任务都在自己的类中.自己的事情自己做) 耦合度:耦合度表示类之间关系的紧密程度.耦合度决定了变更一个应用程序的容易程度.在紧密耦合的类结构中,

设计模式学习笔记系列

设计模式学习笔记(二十二)-FlyWeight享元模式 设计模式学习笔记(二十一)-Composite模式 设计模式学习笔记(二十)-Visitor访问者模式 设计模式学习笔记(十九)-Chain of Responsibility职责链模式 设计模式学习笔记(十八)-Mediator中介者模式 设计模式学习笔记(十七)-Memento备忘录模式 设计模式学习笔记(十六)-Proxy模式 设计模式学习笔记(十五)-State模式 设计模式学习笔记(十四)-Command模式 设计模式学习笔记(十

设计模式学习笔记(十)—Factory Method模式

<设计模式>一书对Factory Method模式是这样描述的: 定义一个用于创建对象的接口,让子类决定实例化哪一个类.FactoryMethod使一个类的实例化延迟到其子类. 我的理解:FatoryMethod模式是一种创建型模式,定义一个用于创建对象的接口的意思是说,我们要定义一个用于创建对象的接口(或者说抽象类,实际上就是个抽象工厂abstractFactory),它的内部有一个创建对象的方法,这个方法的返回值是一个接口(或者抽象类)的类型,这个方法就是FactoryMethod:让子类

学习笔记之JAVA图形设计卷I AWT——第3章 图 形

   学习笔记之JAVA图形设计卷I AWT--第3章 图 形 前时显示器坏了,file://写前言:我觉得写的不是学习笔记,倒象教程.我是想让有所获,故详细了点.注意1:在AWT中提供的用户接口构件(如按钮.列表.菜单.对话框等)不包含一些类似的纯粹的绘制图形的对象(如Line或Circle类) 详细意思:由于原始的AWT在设计时不允许纯粹的绘制图形的对象,那么Rectangle.Polygon和Point没有任何绘制图形的能力.换句话说,Rectangle.Polygon和Point不具备d

我的设计模式学习笔记------&amp;gt;Java设计模式总概况

设计模式(Design Pattern)的概念最早起源于建筑设计大师Alexander的<建筑的永恒方法>一书,尽管Alexander的著作是针对建筑领域的,但是他的观点实际上用用于所有的工程设计领域,其中也包括软件设计领域.在<建筑的永恒方法>一书中是这样描述模式的: 模式是一条由三个部分组成的通用规则:他表示一个特定环境.一类问题和一个解决方案之间的关系.每一个模式描述了一个不断重复发生的问题,以及该问题解决方案的核心设计. 软件领域的设计模式也有类似的定义:设计模式是对处于特

(Head First 设计模式)学习笔记(3) --装饰者模式(StarBuzz咖啡店实例)

以下内容转载请注明来自"菩提树下的杨过(http://blog.sqlsky.com)" 应用概述: StarBuzz咖啡店有很多饮料,每种饮料都可以根据客户需要加一些调料,比如深培咖啡可以加摩卡(或双倍摩卡),而且某些饮料可以分为大中小杯,根据容量不同,售价不同,而且调料的价格根据饮料的容量不同而不同(比如大杯咖啡加糖要1元,中杯咖啡加糖要0.9元等) 又一设计原则: 对扩展开放,对修改关闭(本例中各种饮料都有共同的大中小杯特性--这是关闭的部分,另外各种具体子类饮料和调料的描述和价

(Head First 设计模式)学习笔记(2) --观察者模式(气象站实例)

以下内容转载请注明来自"菩提树下的杨过(http://blog.sqlsky.com)" 应用概述: 某气象站通过传感器实时测量气温/湿度/压力等数据,要求设计一个系统,能让多种类型的公告栏自动更新这些数据(本例中有二类公告板:实时显示气温/温度公告板,动态统计最高/最低气温公告板) 解释: 应用观察者模式,把气温数据做为一个主题(也称为可观察者),让其它公告板当做观察者,通过订阅主题(也称通过观察"可观察者")来得知最新的信息(当然,观察者们也可以方便的退订,从而