`
aladdin_leon
  • 浏览: 118852 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
社区版块
存档分类
最新评论

“开放-封闭”原则--OOD的基石

阅读更多

     钻研OO设计模式有一段时间了,可是天生愚笨,总是不得真谛,于是想是不是该跳出来仔细的想一想了呢?为什么需要设计模式?GoF的23设计模式的设计原则是什么呢?在查阅了一些资料后,仿佛有了一些感觉,其实设计模式的原则就是OOD的原则,或者说设计模式是为了达到OOD的远景而提出的,所以正真的想掌握OO的精髓,那么学习设计模式是最好的途径,而想真正掌握设计模式的精髓,那麽就必须好好的理解一下OOD的设计原则,这篇文章关注的只是其中的一个原则--OCP。下面通过引用CSDN上Health King的专栏的一篇我认为比较好的关于OCP原则的文章开始我们的认识OCP之旅吧!
     原文链接:http://blog.csdn.net/kxy/archive/2005/06/27/405013.aspx
     在继续《设计模式精解》这本书之前,我们来学习些OOD的一些设计原则。这些原则在提高一个系统可维护性的同时,提高这个系统的可复用性他们是一些指导原则,依照这些原则设计,我们就可以有效的提高系统的复用性,同时提高系统的可维护性。
     这些OOD原则的一个基石就是“开-闭原则”(Open-Closed Principle OCP)。这个原则最早是由Bertrand Meyer提出,英文的原文是:Software entities should be open for extension,but closed for modification。意思是说,一个软件实体应当对扩展开放,对修改关闭。也就是说,我们在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展,换句话说就是,应当可以在不必修改源代码的情况下改变这个模块的行为。
     满足OCP的设计给系统带来两个无可比拟的优越性:
     ----- 通过扩展已有的软件系统,可以提供新的行为以满足对软件的新需求,使变化中的软件系统有一定的适应性和灵活性。
     ----- 已有的软件模块,特别是最重要的抽象层模块不能再修改,这就使变化中的软件系统有一定的稳定性和延续性。
     具有这两个优点的软件系统是一个高层次上实现了复用的系统,也是一个易于维护的系统。那么,我们如何才能做到这个原则呢?不能修改而可以扩展,这个看起来是自相矛盾的。其实这个是可以做到的,按面向对象的说法,这个就是不允许更改系统的抽象层,而允许扩展的是系统的实现层。
     解决问题的关键在:抽象化。我们让模块依赖于一个固定的抽象体,这样它就是不可以修改的;同时,通过这个抽象体派生,我们就可以扩展此模块的行为功能。如此,这样设计的程序只通过增加代码来变化而不是通过更改现有代码来变化,前面提到的修改的副作用就没有了。
   “开-闭”原则如果从另外一个角度讲述,就是所谓的“对可变性封装原则”(Principle of Encapsulation of Variation, EVP)。讲的是找到一个系统的可变因素,将之封装起来。在我们考虑一个系统的时候,我们不要把关注的焦点放在什么会导致设计发生变化上,而是考虑允许什么发生变化而不让这一变化导致重新设计。也就是说,我们要积极的面对变化,积极的包容变化,而不是逃避。
     [SHALL01]将这一思想用一句话总结为:“找到一个系统的可变因素,将它封装起来”,并将它命名为“对可变性的封装原则”。
    “对可变性的封装原则”意味者两点:
     ----- 一种可变性应当被封装到一个对象里面,而不应当散落到代码的很多角落里面。同一种可变性的不同表象意味着同一个继承等级结构中的 具体子类。继承应当被看做是封装变化的方法,而不应当是被认为从一般的对象生成特殊的对象的方法(继承经常被滥用)。
     ----- 一种可变性不应当与另外一种可变性混合在一起。从具体的类图来看,如果继承结构超过了两层,那么就意味着将两种不同的可变性混合在了一起。
    “对可变性的封装原则”从工程的角度说明了如何实现OCP。如果按照这个原则来设计,那么系统就应当是遵守OCP的。但是现实往往是残酷的,我们不可能100%的遵守OCP,但是我们要向这个目标来靠近。设计者要对设计的模块对何种变化封闭做出选择。
     好了,上面就是引用的全文了。那麽在实际设计和开发之中,我们该如何重构我们的设计和代码呢?
     答案是:抽象(Astraction)、多态(Polymorphism)、继承(Inheritance)、接口(Interface)。利用这些就可以让我们去实践OCP了,这样就会让我们的设计符合OCP,符合该法则便意味着最高等级的复用性(Reusability)和可维护性(Maintainability)。当然我们也有很多的设计模式可以利用来很优美的解决如何封装变化等问题,但是不要忘了,设计模式的基础也是抽象(Astraction)、多态(Polymorphism)、继承(Inheritance)、接口(Interface)啊。还是从最简单开始吧,千里之行,始于足下...
     考虑下面某个类的方法:     但是现在每当计价策略发生改变,我们就必须修改Part 的每个子类!
     一个更好的思路是采用一个PricePolicy类,通过对其进行继承以提供不同的计价策略,那麽这里就是在运用设计模式里面的策略模式了,解决起来算是很完美了:     看起来我们所做的就是将问题推迟到另一个类中,将“变化”封装在PricePolicy类里面。但是使用该解决方案,我们可通过改变Part对象,在运行期间动态地来设定计价的策略。另一个解决方案是使每个ConcretePart从数据库或属性文件中获取其当前的价格,这样相当于把“变化”封装在了属性文件里面了。

  1. public double totalPrice(Part[] parts) {   
  2.       double total = 0.0;   
  3.       for(int i = 0;i
  4.             total += parts[i].getPrice();   
  5.       }   
  6.       return total;   
  7. }   

     以上函数的工作是在制订的部件数组中计算各个部件价格的总和。若Part是一个基类或接口且使用了多态,则该类可很容易地来适应新类型的部件,而不必对其进行修改。其将符合OCP
     但是在计算总价格时,若财务部颁布主板和内存应使用额外费用,则将如何去做。下列的代码是如何来做的呢?这符合OCP吗?

  1. public double totalPrice(Part[] parts) {   
  2.       double total = 0.0;   
  3.       for(int i = 0;i
  4.             if(parts[i] instanceof Motherboard)   
  5.                 total += (1.45*parts[i].getPrice());   
  6.             else if(parts[i] instanceof Memory)   
  7.                 total += (1.27*parts[i].getPrice());   
  8.             else    
  9.                 total += parts[i].getPrice();   
  10.       }   
  11.       return total;   
  12. }   

     当每次财务部提出新的计价策略,我们都不得不要修改totalPrice()方法!这并非“对更改是封闭的”。显然,策略的变更便意味着我们不得不要在一些地方修改代码的,因此不符合OCP,那麽我们该如何去做呢?
    为了使用我们第一个版本的totalPrice(),我们可以将计价策略合并到Part的getPrice()方法中。
    这里是Part和ConcretePart类的示例:

  1. public class Part {   
  2.        private double basePrice;   
  3.        public void setPrice(double price) {   
  4.            basePrice = price;   
  5.        }   
  6.        public double getPrice() {   
  7.            return basePrice;   
  8.        }   
  9. }   
  10. public class Motherboard extends Part {   
  11.        public double getPrice() {   
  12.            return 1.45*basePrice;   
  13.        }   
  14. }   
  15. public class Memory extends Part {   
  16.        public double getPrice() {   
  17.            return 1.27*basePrice;   
  18.        }   
  19. }   
  20.   

       但是现在每当计价策略发生改变,我们就必须修改Part 的每个子类!
       一个更好的思路是采用一个PricePolicy类,通过对其进行继承以提供不同的计价策略,那麽这里就是在运用设计模式里面的策略模式了,解决起来算是很完美了:

  1. public class Part {   
  2.        private PricePolicy pricePolicy;   
  3.        public void setPricePolicy(PricePolicy policy) {   
  4.            pricePolicy = policy;   
  5.        }   
  6.        public void setPrice(double price) {   
  7.            pricePolicy.setPrice(price);   
  8.        }   
  9.        public double getPrice() {   
  10.            return pricePolicy.getPrice();   
  11.        }   
  12. }   
  13. public class PricePolicy {   
  14.        private double basePrice;   
  15.        public void setPrice(double price) {   
  16.            basePrice = price;   
  17.        }   
  18.        public double getPrice() {   
  19.            return basePrice;   
  20.        }   
  21. }      
  22. public class SalePrice extends PricePolicy {   
  23.        private double discount;   
  24.        public void setDiscount(double discount) {   
  25.            this.discount = discount;   
  26.        }   
  27.        public double getPrice() {   
  28.            return basePrice*discount;   
  29.        }      
  30. }   
  31.   

     看起来我们所做的就是将问题推迟到另一个类中,将“变化”封装在PricePolicy类里面。但是使用该解决方案,我们可通过改变Part对象,在运行期间动态地来设定计价的策略。另一个解决方案是使每个ConcretePart从数据库或属性文件中获取其当前的价格,这样相当于把“变化”封装在了属性文件里面了。

分享到:
评论

相关推荐

    PHP面向对象五大原则之开放-封闭原则(OCP)详解

    开放-封闭原则(Open-Closed Principle,OCP)是面向对象设计(OOD)的五大原则之一,由Bertrand Meyer在1998年提出。该原则旨在指导软件系统的设计,使其能够容易地扩展新功能,同时在扩展时不影响现有代码的稳定性...

    OOD-Principles-In-Swift, 关于Bob叔叔的文章,基于OOD的原理.zip

    OOD-Principles-In-Swift, 关于Bob叔叔的文章,基于OOD的原理 import Swiftimport Foundation Swift 4中的OOD原理使用 Xcode 9游乐场( OOD-Principles-In-Swift.playground.zip )的短备忘单。 也兼

    面向对象软件开发技术(OOA-OOD-OOP)

    面向对象软件开发技术(OOA-OOD-OOP)

    图书管理系统-OOD-状态图和通信.ppt

    图书管理系统-OOD-状态图和通信.ppt 图书管理系统-OOD-状态图和通信.ppt 是一个教学课件,介绍了图书管理系统的对象导向设计(OOD)和状态图。该系统主要包括登录、办理归还、添加图书、添加用户、新办借阅证等用例...

    图书管理系统-OOD-设计准备知识.ppt

    "图书管理系统-OOD-设计准备知识" 本知识点总结了图书管理系统的OOD设计准备知识,涵盖了软件设计、模块化设计、软件设计阶段、软件设计目标、软件设计概述、软件结构设计过程、软件设计质量原则、概要设计说明书...

    OOD设计基本原则整理.doc

    开-闭原则是 OOD 设计的核心原则之一,该原则强调一个软件实体应当对扩展开放,对修改关闭。也就是说,在设计一个软件实体的时候,应当使这个软件实体可以在不修改或少修改的前提下通过扩展来实现变化。 该原则的...

    图书管理系统OOA-OOD报告.pdf

    在这份《图书管理系统OOA-OOD报告.pdf》中,我们将深入探讨如何通过面向对象的技术方法,设计并开发一个高效、智能的图书管理系统。 本报告首先从需求分析入手,针对图书管理系统的核心功能模块进行了全面梳理。...

    软件设计的七大原则(OOD)

    OCP是软件设计的七大原则之一,它的定义是:软件实体(类、模块、函数/方法等等)对于扩展应该是开放的,对于修改应该是封闭的。OCP可以提高软件模块的可重用性和可维护性,软件产品具有良好的稳定性和持久性。OCP的...

    OOD设计基本原则 面向对象设计必备

    OCP 原则(Open-Closed Principle)是 OOD 设计基本原则之一,它规定软件实体应当对扩展开放,對修改关闭。这意味着,我们应当使模块可以在不被修改的前提下被扩展,换句话说,就是应当可以在不必修改源代码的情况下...

    OOD启思录-面向对象圣典(英文版)

    《OOD启思录—面向对象圣典》提供的面向对象设计启发式原则为软件开发者提供了一套实用的方法论,帮助他们在实际项目中更好地设计和改进面向对象系统。这些原则强调了诸如封装、多态性、清晰的接口以及最小化依赖等...

    如何解释OOD及设计

    在这一阶段,应该遵循面向对象的原则,如单一职责原则、开放封闭原则等,以确保代码的质量。 7. **测试与迭代**:对软件进行测试,验证其功能和性能是否符合预期。根据测试结果进行必要的调整和优化。 8. **文档...

    OOD面试应对方法 SOLID原则.mp4

    O - Open-closed principle 开发封闭原则 L - Liskov substitution principle 里氏替换原则 I - Interface segregation principle 接口分离原则 D - Dependency Inversion Principle 依赖反转原则

    lurc-ood-desktop:LURC的OOD门户上的CentOS桌面的奇异性定义文件和Dockerfiles

    lurc-ood-desktop LURC的OOD门户上的CentOS桌面的奇异定义文件和Dockerfile

    OOD-detection-using-OECC:具有置信度控制的异常值分布,用于分布外检测

    使用OECC进行OOD检测 该存储库包含纸的的基本代码。 在2021年被Neurocomputing接受为Journal文章。 1.什么是具有信心控制的异常值暴露(OECC)? 是一种技术,可帮助深度神经网络(DNN)学习如何区分分布内(OOD)...

    OOD原则 GRASP GOF

    **OOD原则:面向对象设计(Object-Oriented Design)原则** 面向对象设计是软件开发中的一种重要方法,它强调将现实世界中的实体转化为程序中的类和对象,通过封装、继承和多态等特性来实现软件的模块化和可扩展性...

    OOD-Java

    "OOD-Java"涵盖了Java编程中的核心面向对象设计原则和实践,包括类与对象、封装、继承、多态、抽象等概念,以及如何利用设计模式解决实际问题。学习和掌握这些知识,对于提升Java编程能力,编写出高效、可扩展和易于...

    c# OOP/OOD

    OOD的原则包括: 1. **SOLID原则**:SOLID是五个面向对象设计原则的首字母缩写,包括单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则指导我们编写可维护、可扩展的代码。 2. **设计...

    ood-solid:面向对象设计的SOLID原理

    开闭原则主张软件实体(如类、模块、函数等)应对扩展开放,对修改关闭。这意味着当我们需要增加新的功能时,应该尽量避免修改已有的代码。通过抽象和多态,我们可以设计出能够适应未来需求变化的系统。 3. 里氏...

    OOD启思录 高清pdf

    本书被誉为“面向对象设计领域中的Effective C++”,它通过总结60多条面向对象设计(OOD)的指导原则,旨在帮助开发者提升面向对象设计能力,深化对设计模式的理解,从而提升软件开发质量。 首先,书中强调了面向对象...

Global site tag (gtag.js) - Google Analytics