热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

面向对象的设计原则(一)

在面向对象的设计过程中,首先需要考虑的是如何同时提高一个软件系统的可维护性和可复用性。这时,遵从面向对象的设计原则,可以在进行设计方案时减


       在面向对象的设计过程中,首先需要考虑的是如何同时提高一个软件系统的可维护性和可复用性。这时,遵从面向对象的设计原则,可以在进行设计方案时减少错误设计的产生,从不同的角度提升一个软件结构的设计水平。同时面向对象设计原则也是用于评价一个设计模式的使用效果的重要指标之一,在设计模式的学习中,经常会看到诸如“XXX模式符合XXX原则”、“XXX模式违反了XXX原则”这样的语句,以此来评判设计模式的优势与不足。这里将针对如下的7种常见的面向对象设计原则进行阐述:

  • 单一职责原则
  • 开闭原则
  • 里氏代换原则
  • 依赖倒转原则
  • 接口隔离原则
  • 迪米特法则
  • 合成复用原则



1.单一职责原则(Single Responsibility Principle, SRP)


   

   单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大小,其定义如下:



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



    对于单一职责原则,可以理解为一个类只负责一个功能领域中的相应职责,即一个类不要负责太多“杂乱”的工作。在软件系统中,如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或抑制这个类完成其他职责的能力。这种耦合会导致脆弱的设计,当变化发生时设计或遭受到意想不到的破坏。以项目开发为例,如果项目组成员每个人的职责都很明确,可以专心开发自己负责的模块,则项目成果的质量往往很高。相反,如果职责不清晰,分工就会混乱,极有可能出现A负责N个模块,而B则可以在一旁开心地打酱油的情况。这样,如果A所负责的模块中有多个模块集中暴露问题时,A就很难高质量地将问题从容解决。

    单一职责原则可以用一句比较通俗的话来表达,即自己负责领域的事情都做,不是自己领域的事不去插手。单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则。需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关实践经验。

    下面通过一个简单的实例来对单一原则进行说明。

    公司员工每个月最盼望的日子便是发工资的那一天,与此同时,财务需要统计每个人的薪资情况并做成报表,然后以工资条的形式给到员工。针对薪资报表这一功能,给出了如下的初始方案:




   函数说明:



  • getConnection()--用于连接数据库
  • findSalaryList(intemployeeId)--根据员工的ID获取该员工本月的薪资详情,如五险一金、个税等
  • createChart()--根据员工薪资创建报表
  • displayChart()--用于显示薪资报表



    从初始设计方案来看,SalaryChart承担了数据库连接、信息查询、图表操作等多项职责。当其他类也需要进行数据库连接、信息查询、图表操作时,为满足其他类的操作需求,对应的方法都需要做出对应的修改。此时,引起该类变化的原因已经不止一个,违反了单一职责原则。为解决该问题,需要对类进行拆分,使其职责明确。重新设计如下:




   拆分类说明如下:



  • SalaryChart:负责表的生成和显示
  • SalaryDAO:负责对数据表的操作
  • DBUtil:负责数据库的连接



    此时,每个类只有一个引起其变化的原因,满足了单一职责的原则。




2.开闭原则(Open-Closed Principle, OCP)


    

   开闭原则是面向对象的可复用设计的第一块基石,它是最重要的面向对象设计原则。开闭原则由Bertrand  Meyer于1988年提出,其定义如下:



一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。



    开闭原则即对扩展开放,对修改封闭。在软件系统开发过程中,软件的需求往往会随着时间的推移而发生变化。因此,进行软件设计时需要考虑怎样的设计才能面对需求的改变却可以相对保持稳定,从而使得系统可以在第一个版本以后不断推出新的版本。这时便可以以开闭原则作为指导。如果一个软件设计符合开闭原则,那么可以非常方便地对系统进行扩展,而且在扩展时无须修改现有代码,使得软件系统在拥有适应性和灵活性的同时具备较好的稳定性和延续性。

    为了满足开闭原则,需要对系统进行抽象化设计,抽象化是开闭原则的关键。在进行软件设计时,一般先评估出最有可能发生变化的类,然后构造抽象来隔离那些变化。当变化发生时,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可,实现在不修改已有代码的基础上扩展系统的功能,达到开闭原则的要求。

    以设计一个计算器为例,假设初始设计方案如下。


   对于加、减、乘、除不同的计算方式以不同的类进行实现,然后在Calculator类中,根据用户输入的操作指令,实例化不同的处理类进行处理并显示结果,其displayResult代码片段如下:



if (operate.equals("+")) {OperationAdd oper = new OperationAdd();result = oper.getResult();
} else if (operate.equals("-")) {OperationSub oper = new OperationSub();result = oper.getResult();
} else if (operate.equals("*")) {OperationMul oper = new OperationMul();result = oper.getResult();
} else if (operate.equals("/")) {OperationDiv oper = new OperationDiv();result = oper.getResult();
} else {System.out.println("操作符输入有误,请重新输入");
}
System.out.println("Result = "+result);





   在该实例中,如果需要添加新的运算,如开方,则除了需要增加一个新的开方运算类外,还需要Calculator类中displayResult方法增加分支判断,明显违反了开闭原则。这时引入抽象化设计,重新设计如下。增加抽象操作类AbstrcatOperation,使加、减、乘、除等操作类成为AbstrcatOperation的子类。而Calculator则通过setOperation方法来由客户端来设置实例化的具体操作类。此时,如果要增加新的运算OperationSqrt,只需要将OperationSqrt作为AbstrcatOperation的子类,并在客户端向Calculator注入一个OperationSqrt对象即可,无需修改现有类库的源代码。


参考文献:
1、大话设计模式

2、http://blog.csdn.net/lovelion/article/details/17517213

【作者:墨叶扶风http://blog.csdn.net/yefufeng




推荐阅读
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了C++中省略号类型和参数个数不确定函数参数的使用方法,并提供了一个范例。通过宏定义的方式,可以方便地处理不定参数的情况。文章中给出了具体的代码实现,并对代码进行了解释和说明。这对于需要处理不定参数的情况的程序员来说,是一个很有用的参考资料。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 本文介绍了Linux系统中正则表达式的基础知识,包括正则表达式的简介、字符分类、普通字符和元字符的区别,以及在学习过程中需要注意的事项。同时提醒读者要注意正则表达式与通配符的区别,并给出了使用正则表达式时的一些建议。本文适合初学者了解Linux系统中的正则表达式,并提供了学习的参考资料。 ... [详细]
author-avatar
手机用户2702932415_836
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有