设计模式(二)——面向对象设计原则一

时间:2024-03-13 18:33:18

一、面向对象设计原则概述

面对对象设计的目标之一在于支持可维护性复用:一方面需要实现设计方案或者源代码的复用;另一方面要确保系统能够易于扩展和修改,具有良好的可维护性。

  • 可复用性(Reusability):指软件能够被重复使用的难以程度
  • 可维护性(Maintainability):指软件能够被理解、改正、适应及扩展的难易程度

为了支持可维护性复用,面对对象设计原则应运而生。不过,千万要记住这些设计原则是指导性原则,并非强制性原则。
每一个设计模式都符合一个或多个面向对象设计原则,面向对象设计原则是用于评价一个设计模式的使用效果的重要指标之一

以下为七大设计原则的基本定义与使用频率:
设计模式(二)——面向对象设计原则一

二、单一职责原则

1、单一职责原则定义

  • 单一职责原则是最简单的面向对象设计原则,用于控制类的粒度大小

单一职责原则:一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中。
Single Responsibility Principle (SRP): Every object should have a single responsibility, and that responsibility should be entirely encapsulated by the class.

  • 就一个类而言,应该仅有一个引起它变化的原因

2、单一职责原则分析

  • 一个类(大到模块,小到方法)承担的职责越多,它被复用的可能性就越小
  • 当一个职责变化时,可能会影响其他职责的运作
  • 将这些职责进行分离,将不同的职责封装在不同的类中
  • 将不同的变化原因封装在不同的类
  • 单一职责原则是实现高内聚、低耦合的指导方针

3、单一职责原则实例

1)实例说明
  • 某基于Java的C/S系统的“登录功能”通过如下登录类(Login)实现:
    设计模式(二)——面向对象设计原则一
  • 现在使用单一职责原则对其进行重构
2)实例解析

Login类把实现登录能够的所有操作都集成在自身,根据单一职责原则,我们根据操作类型与操作职责将其划分为:启动类(MainClass)、登录表单类(LoginForm)、数据库操作类(UserDAO)与工具类(DBUtil)。具体划分如下图所示:
设计模式(二)——面向对象设计原则一

三、开闭原则

1、开闭原则定义

  • 开闭原则是面向对象的可复用设计的第一块基石,是最重要的面向对象设计原则

开闭原则:软件实体应当对扩展开放,对修改关闭
Open-Closed Principle (OCP): Software entities should be open for extension, but closed for modification.

2、开闭原则分析

开闭原则由Bertrand Meyer于1988年提出,在开闭原则的定义中,软件实体可以是一个软件模块一个由多个类组成的局部结构一个独立的类。开闭原则是指软件实体应尽量在不修改原有代码的情况下进行扩展

  • 抽象化是开闭原则的关键
  • 相对稳定的抽象层 + 灵活的具体层
  • 对可变性封装原则(Principle of Encapsulation of Variation,EVP):找到系统的可变因素并将其封装起来

3、开闭原则实例

1)实例说明
  • 某图形界面系统提供了各种不同形状的按钮,客户端代码可针对这些按钮进行编程,用户可能会改变需求要求使用不同的按钮,原始设计方案如图所示:
    设计模式(二)——面向对象设计原则一
  • 现对该系统进行重构,使之满足开闭原则的要求。
2)实例解析

要使系统满足开闭原则,则需要使系统更改需求时不能修改源代码,但可以通过扩展新的类来实现需求更改。因此,我们首先引入按钮类的抽象类(AbstractButton),让圆形按钮(CircleButton)跟长方形按钮(RectangleButton)都继承于抽象类,并实现抽象类中的抽象方法。其次我们在登录表单类(LoginForm)中关联抽象类的对象,将抽象类子类的名字放到配置文件(config.xml)中,通过反射的方法让子类来覆盖抽象类(这里涉及我们后面所讲的里氏代换原则)。最后我们只需要通过实现新的抽象类子类便可添加新的按钮类,并且只需要修改配置文件中的子类名更换不同按钮。(注意噢,修改配置文件并不是修改源代码)
设计模式(二)——面向对象设计原则一

四、里氏代换原则

1、里氏代换原则定义

里氏代换原则:所有引用基类的地方必须能透明地使用其子类的对象。
Liskov Substitution Principle (LSP): Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

2、里氏代换原则分析

里氏代换原则由2008年图灵奖得主、美国第一位计算机科学女博士、麻省理工学院教授Barbara Liskov和卡内基.梅隆大学Jeannette Wing教授于1994年提出。

  • 在软件中将一个基类对象替换成它的子类对象程序将不会产生任何错误和异常
  • 反过来则不一定成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象
  • 在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型

3、里氏代换原则实例

1)实例说明
  • 某系统需要实现对重要数据(如用户密码)的加密处理,在数据操作类(DataOperator)中需要调用加密类中定义的加密算法,系统提供了两个不同的加密类,CipherA和CipherB,它们实现不同的加密方法,在DataOperator中可以选择其中的一个实现加密操作。如图所示:
    设计模式(二)——面向对象设计原则一
  • 如果需要更换一个加密算法类或者增加并使用一个新的加密算法类,如将CipherA改为CipherB,则需要修改客户类Client和数据操作类DataOperator的源代码,违背了开闭原则。
  • 现使用里氏代换原则对其进行重构,使得系统可以灵活扩展,符合开闭原则。
2)实例解析

里氏代换的原则是一个父类对象可以被子类对象所替换,根据这个思路,我们可以将两个加密算法类中的一个作为父类(图中是CipherA类),另一个类作为该类的子类(图中是CipherB类)【注:由于里氏代换原则,当我们需要用到其他加密算法类,只需继承于父类并重载加密方法便可被替换】。让数据操作类(DataOperator)和客户端(Client)与父类进行关联,将要使用的算法类的类名放在配置文件中,通过反射的方式让子类覆盖父类。从而实现修改配置文件中类名加密类的更换。
设计模式(二)——面向对象设计原则一