在《敏捷软件开发--原则、模式与实践》书中给出了多个OO设计原则,例如单一职责、开闭原则、依赖倒置原则等。在这些原则中,绝大多数都很容易理解,最难理解的恐怕算开闭原则(对扩展开放,对修改关闭),主要原因是它太抽象,是一个比较本质比较基础的设计原则,超出了初学者的理解范围,如果能有一个实际的具体例子来说明就容易理解了。
其实在设计模式中,就有这样的一些模式很好的直接体现了开闭原则。
先暂时岔开一下说说设计模式,设计模式的流行应该是归功和发端于四人帮的《设计模式--可复用面向对象软件的基础》一书的出版,自此设计模式才开始为IT大众所知晓。
对设计模式的学习,不仅要知其然还要知其所以然,也就是不仅要了解常用的设计模式,还要在思想上升华对设计模式的理解,要对设计模式有更高层次的理解。高层次的理解:设计模式是对系统需求变化的一种优雅封装手段。唯一不变的就是变化,变化是客观的,通常是很难避免的,通过这种优雅的封装,也提高了代码的可维护性。
怎么应对变化?其实在日常工作生活中就可以找到应对变化的手段。对各种气体(如气体喷雾剂)和液体(如水),由于它们没有固定的形状,也就是容易变化,所以我们需要用容器(瓶瓶罐罐)将它们封装起来,隔离屏蔽起来,否则任由它们四处蔓延扩散,肯定会把周围的环境污染得一滩糊涂,难以收拾。为了防范洪水猛兽犯人,人们修建各种设施(水库、铁笼子、监狱、篱笆栅栏)将它们关起来,局限隔离起来,约束起来。
类推到软件中也是这样,软件中的变化类似洪水猛兽,也需要进行封装隔离,如果让变化任意到处蔓延,污染其他的代码,那么受污染的代码就和容易变化的代码产生了较强的耦合,耦合太强太多,就变成意大利面条了,导致有新的变化时,代码难以维护,一旦后面要拥抱变化,那就悲剧了:开发人员要到处查找受污染的代码进行修改,少修改一处就出bug,除了修改原来的代码之外,有时还要增加很多分支逻辑和方法,导致整个代码没有条理和秩序,很凌乱,难以维护。
因此我们应追求低耦合高内聚,减少依赖。对容易变化的代码,就像日常生活中那样,将变化封装隔离起来,对它进行管束&限制,隔离起来,不让变化到处扩散,减少或尽量屏蔽它和其余部分之间的耦合。我们为了封装各种类型各种维度的变化,隔离变化,所以我们在设计中要拆分系统、拆分模块、定义类和接口、定义方法和函数,包括使用设计模式,都是一种封装变化的手段,当然封装变化不是拆分系统、拆分模块的唯一目的。
设计模式的主要目的就是优雅的封装变化,也就是不只是单纯封装变化,减少变化的影响范围,还要优雅封装,也就是提高代码可维护性,让代码有条理有秩序,低耦合,易于扩展。掌握设计模式是开发人员的重要技能之一。
设计模式学起来不太难,一个对设计模式一无所知的的开发人员,把四人帮的设计模式一书认真读两遍基本可掌握。但要注意学习方法,要带着问题去读,对书中的每个设计模式,在读完它要解决的问题时,先停下来,问问自己,碰到这样的问题如何优雅的解决。思考完再继续读下去,再反思下自己为何没想到答案,再对照书中的类图和序列图、代码仔细揣摩体会下该设计模式的精妙。这样才有可能在自己的思想中产生较为深刻的理解,否则就是浮光掠影,没有效果。最后一定要在自己的开发工作中找合适的机会实践一下,不一定都用到,首先是要找到变化点,深入到变化点中去,再对照具体的问题场景,选择对应的模式。我的实践经验是在较多场景中都会用到模板方法(框架中用的更多)、代理模式、策略模式、命令模式、facade、工厂方法等。只有在潜意识中留下设计模式的烙印才算真正掌握了设计模式的精髓,以后一碰到问题,从直觉上就能较快知道应该运用哪些设计模式。
由于变化的多样性,也就是有不同类型和不同维度导致的变化,所有就要有多个不同的设计模式来应对相应的变化。除了四人帮书中所讲的3种类型(创建型、结构性、行为型)的23种设计模式,其实还有很多其它的设计模式,也不只有3种类型,还有其他类型的设计模式,例如分布式系统领域、资源管理领域、应用集成领域这些类型。
回到正题,四人帮书中的哪个设计模式直接体现了开闭原则?说的是直接,很多模式都间接体现了该原则。
开闭原则(扩展开放,对修改关闭)的完整意思是需求变化时要能通过增加代码来实现,这样就扩展了新的功能(对扩展开放),但不要修改先前的模块代码或底层框架核心层代码(对修改关闭),多优雅。显然如果修改核心层代码,很可能会引入风险,还有一种可能是核心层如果是二进制库(第二方或三方dll、jar包),你还无法修改,没源码啊,除非进行反向工程,反编译。这样如果增加功能需要修改核心层,就很难办到了。而遵照开闭原则的设计就不必担忧此问题,因为只需在核心层之外的外围模块(有源码控制权)中增加新代码实现扩展,不需涉及到核心层,核心要保持稳定。
答案是Visitor模式,该模式的类图就不画了。对照该模式的类图,可以发现有两个大的类层次,一个是Visitor层次(Visitor基类&接口和它的众多子类&实现类),另一个是数据元素层次(Element/Node和它的众多子类)。
采用该模式,如果要增加新的算法操作,只需要增加一个外围的Visitor子类即可,先前的核心代码(Visitor基类和Element基类)不用修改也不允许修改,这不正直接体现了开闭原则!
正如四人帮的书中指出,该模式不是万能的,任何模式都有适用范围。如果变化点在数据元素层次(Element/Node层次)该模式就不太管用了。
模板方法、策略模式等也比较好地体现了开闭原则。很多框架也使用这些模式来提供扩展点,通过回调这些扩展点中的方法,以便拥抱具体应用中的变化。
.
题外:对设计模式之间的关系,不想单独再写博客,这里补充下对设计模式关系的理解。我们学知识掌握概念,不仅要了解其内涵/外延、适用场景和不适用的场景,还要注意掌握它和其他知识点、概念之间的区别与联系。学设计模式也是这样,例如学习工厂方法,除了单纯掌握它的内在之外,还要知晓它和其他设计模式之间的区别和联系,它们之间有什么相同、不同、有什么关系联系,相互之间比较有什么优缺点。这里讲解下设计模式之间的关系,如下图,是23种设计模式的关系图。
万事万物都是相互联系,都存在关系,不是孤立存在的。软件设计中的类之间通常也存在关系联系,例如订单和它包含的订单项,业务服务和它依赖的数据访问服务(DAO类),如果画类图对象图,这些关系一般在类图上要有所体现,类图中在有关系的类(对象)之间画线,写上具体的关系名称。于此类似,上图也体现了设计模式之间的关系,例如上图右下方Template Method模板方法模式和Factory Method工厂方法模式有联系,也就是在使用模板方法设计模式时我们通常要一起结合使用工厂方法模式来创建模板方法子类对象。
在使用模板方法设计模式时,定义模板基类,再定义几个模板子类。一般是使用基类对象类型来引用这些子类实例,在运行时调用的是这些子类实例。这些子类实例怎么来的,肯定要创建要new出模板子类对象。大多数情况下这些子类实例一般是单例,如何优雅的封装这种创建中的变化因素(根据某些参数来生成对应的模板子类),这里就用工厂方法模式来创建模板子类,来封装创建时的变化因素。也就是单例模式得到单个工厂实例,工厂实例得到模板实例。
理解了上图,就明白在软件设计中通常是综合使用多种设计模式,它们不一定是互斥关系,例如不同类型的设计模式之间。
相关推荐
设计模式6大原则:开闭原则
开闭原则是面向对象设计中的一个核心原则,它在JAVA设计模式中占据着重要的地位。这一原则由格里·贝斯提出,旨在指导开发者如何设计可维护和可扩展的软件系统。开闭原则(Open-Closed Principle,OCP)的核心思想是...
- **设计模式的应用**:策略模式、工厂模式、建造模式等多种设计模式都是开闭原则的具体实践。它们通过提供灵活的组件装配机制,使得系统能够容易地适应变化,而不需修改核心代码。 - **重构与优化**:在软件维护...
此外,工厂模式、建造者模式、桥接模式、门面模式、调停者模式、访问者模式和迭代子模式等设计模式也是遵循开闭原则的有效手段。 在 Java 中,单方法接口常用于实现函数指针或委托功能,这允许在不修改原有类结构的...
该怎么使用 Java 设计模式编程中的 OCP 开闭原则? 在软件开发中,开闭原则是面向对象设计中最基础的设计原则之一,它指导我们如何建立稳定灵活的系统。开闭原则定义:一个软件实体如类、模块和函数应该对扩展开放...
Java 设计模式中的 OCP 开闭原则 在软件设计中,OCP 开闭原则是其中一个非常重要的设计原则。该原则定义了一个软件实体,如类、模块和函数应该对扩展开放,对修改关闭。也就是说,当软件需要变化时,应该尽量通过...
在C#编程中,设计模式的应用能够提高代码的可读性、可维护性和扩展性。本文将深入探讨“开放封闭原则”这一核心设计原则,并结合C#语言环境进行解析。 开放封闭原则(Open-Closed Principle,OCP)由Bertrand Meyer...
面向对象设计原则:面向对象设计原则、开闭原则、里氏替换原则、里氏替换原则、里氏替换原则
面向对象设计原则与设计模式是软件工程领域的重要组成部分,它们为构建高质量、可维护和可扩展的软件系统提供了指导方针。下面将详细阐述面向对象设计原则及其如何促进软件的复用,以及设计模式的概念。 ### 面向...
总之,开闭原则是软件设计的重要指导思想,它提倡通过合理的抽象和多态性来实现代码的灵活性和稳定性。在Java Web开发中,理解并遵循OCP原则,可以显著提升系统的可扩展性和可维护性,从而为项目带来长期的益处。
读书笔记:java 23种设计模式 开闭原则 依赖倒转原则 迪米特法则 设计模式思想 Java入门demo
在Java设计模式中,开闭原则通常通过以下几种方式实现: 1. **抽象化接口**:设计时应尽量使用抽象接口而不是具体实现。例如,定义一个抽象的`Animal`接口,然后创建`Dog`和`Cat`等具体的动物类实现这个接口。当...
1、开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和...
详细介绍了设计模式六大原则,配有示例代码和图片,有开闭原则,单一职责原则,里氏替换原则,依赖倒置原则,接口隔离原则,迪米特法则等等。
6. **模块化和插件化**:为了进一步实现开闭原则,可以将图片缓存系统设计为可插拔的模块。每个模块(如缓存策略或处理逻辑)都有自己的接口和实现,用户可以根据需求选择启用或禁用特定的模块,而不会影响整体架构...
在这些设计模式和原则中,策略模式是一个非常重要的行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以相互替换使用。策略模式让算法的变化独立于使用算法的客户端。 以提供的文档内容为例,...
本资源首先介绍了设计模式的六大原则,包括单一责任原则、开闭原则、里氏替换原则、接口隔离原则、合成复用原则和最少知道原则。然后,资源对23种设计模式进行了分类和总结,包括创建型模式、结构型模式和行为型模式...
在Android开发中,设计模式和设计原则是提升代码质量、可维护性和可扩展性的重要工具。以下是关于"Android 24种设计模式介绍与6大设计原则"的详细阐述: 一、六大设计原则 1. **单一职责原则(Single ...