定义 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。 原则 第一点 子类必须实现父类的抽象方法,但不得重写(覆盖)父类的非抽象(已实现)方法。 value = num1 + num2 +num2; System.out.println("子类计算结果:" + value); } } 总结 通过上面的描述相信大家都对里氏替换原则有了一个基本的概念 然而在实际开发中我们在很多时候还是会违背该原则的,虽然表面上没有什么特别大的问题,但是这样做会大大增加代码的出错率。
我们只要将新的DLL覆盖到原有的DLL即可,并不影响现有程序的正常运行,但每次出现新情况都要找出类文件,添加新的实现细节,这个类文件不断扩大,以后维护起来就变的越来越困难,也并不满足我们以前说的单一职责原则 如果我们在设计这个类的时候坚持了OCP的话,把工资税的公共方法抽象出来做成一个接口,封闭修改,在客户端(使用该接口的类对象)只依赖这个接口来实现对自己所需要的工资税,以后如果系统需要增加新的工资税,只要扩展一个具体国家的工资税实现我们先前定义的接口 ; 2、两种安全的实现开闭原则的设计模式是:Strategy pattern(策略模式),Template Methord(模版方法模式); 3、依据开闭原则,我们尽量不要修改类,只扩展类,但在有些情况下会出现一些比较怪异的状况 对于行为,如果是基本不变的,则可以直接作为对象的方法,否则考虑抽象或者封装这些行为; 5、在许多方面,OCP是面向对象设计的核心所在。 遵循这个原则可带来面向对象技术所声称的巨大好处(灵活性、可重用性以及可维护性)。然而,对于应用程序的每个部分都肆意地进行抽象并不是一个好主意。应该仅仅对程序中呈现出频繁变化的那部分作出抽象。
优点:ToggleSwitch依赖于抽象类Light,具有更高的稳定性,而BulbLight与TubeLight继承自Light,可以根据"开放-封闭"原则进行扩展。 三、DIP优点: 使用传统过程化程序设计所创建的依赖关系,策略依赖于细节,这是糟糕的,因为策略受到细节改变的影响。依赖倒置原则使细节和策略都依赖于抽象,抽象的稳定性决定了系统的稳定性。
Dog)animal; Dog.Decription(); Dog.Bark(); } } 通过上面的代码,我们可以看到虽然客户端的依赖是对抽象的依赖,但依然这个设计的扩展性不好 现在看来,一个系统或子系统要拥有良好的扩展性和实现运行期内绑定,有两个必要条件:第一是依赖倒置原则;第二是里氏替换原则。这两个原则缺一不可。 ,但这远远不够,因为它不满足依赖颠倒原则和里氏替换原则。 契约式编程有利于系统的分析和设计,指我们在分析和设计的时候,定义好系统的接口,然后再编码的时候实现这些接口即可。在父类里定义好子类需要实现的功能,而子类只要实现这些功能即可。 5、从派生类抛出异常:如果在派生类的方法中添加了其基类不会抛出的异常。如果基类的使用者不期望这些异常,那么把他们添加到派生类的方法中就可以能会导致不可替换性。
二、举例说明: 参考下图的设计,在这个设计里,取款、存款、转帐都使用一个通用界面接口,也就是说,每一个类都被强迫依赖了另两个类的接口方法,那么每个类有可能因为另外两个类的方法(跟自己无关)而被影响。 参考下图的设计,为每个类都单独设计专门的操作接口,使得它们只依赖于它们关系的方法,这样就不会互相影了! ? 三、实现方法: 1、使用委托分离接口 2、使用多重继承分离接口
小谈设计模式(5)—开放封闭原则 专栏介绍 主要对目前市面上常见的23种设计模式进行逐一分析和总结,希望有兴趣的小伙伴们可以看一下,会持续更新的。 开放封闭原则 开放封闭原则是面向对象设计中的一个重要原则,它指导我们编写可扩展、可维护和可复用的代码。 核心思想 软件实体(类、模块、函数等)应该对扩展开放,对修改封闭。 需要预留扩展点 开放封闭原则需要在设计时预留扩展点,这可能会增加设计的难度。如果没有正确地预留扩展点,可能需要修改已有的代码。 可能引入过度设计 开放封闭原则可能会导致过度设计。 总结 开放封闭原则是面向对象设计中的一个重要原则,它的核心思想是对扩展开放,对修改封闭。通过定义抽象类或接口,并实现新的子类或接口,可以在不修改已有的代码的情况下,增加新的功能。 然而,开放封闭原则也可能增加代码的复杂性和设计难度,需要在实际应用中权衡利弊。总的来说,开放封闭原则是一种有助于构建可扩展、可维护和可复用的系统的重要原则。
什么是开闭原则? 在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展,即应当可以在不必修改源代码的情况下改变这个模块的行为。 如何运用开闭原则? 开闭原则解决问题的关键在于抽象化,把系统所有可能的行为抽象成一个抽象底层,这个抽象底层规定出所有的具体实现必须提供的方法的特征,给系统定义出一个一劳永逸,不再修改的抽象设计,此设计允许有无穷尽的行为在实现层被实现 在JAVA中可以定义一个或多个抽象Java类或Java接口,规定出所有的具体类必须提供的方法的特征作为系统设计的抽象层。 作为系统设计的抽象层,要预见所有可能的扩展,因此在任何扩展情况下系统抽象底层不需要修改。同时,由于抽象层导出一个或多个新的具体类可以改变系统的行为,因此系统的设计对扩展是开放的。 遵守开闭原则进行如下改变 打折类: public class OffNovelBook extends NovelBook { public OffNovelBook(String name
所谓职责,我们可以理解他为功能,就是设计的这个类功能应该只有一个,而不是两个或更多。也可以理解为引用变化的原因,当你发现有两个变化会要求我们修改这个类,那么你就要考虑撤分这个类了。 二、举例说明: 违反SRP原则代码: modem接口明显具有两个职责:连接管理和数据通讯; interface Modem { public void dial(string pno); ; } 三、SRP优点: 消除耦合,减小因需求变化引起代码僵化性臭味 四、使用SRP注意点: 1、一个合理的类,应该仅有一个引起它变化的原因,即单一职责; 2、在没有变化征兆的情况下应用SRP或其他原则是不明智的 ; 3、在需求实际发生变化时就应该应用SRP等原则来重构代码; 4、使用测试驱动开发会迫使我们在设计出现臭味之前分离不合理代码; 5、如果测试不能迫使职责分离,僵化性和脆弱性的臭味会变得很强烈,那就应该用
而在面向对象的设计里面,可维护性复用都是以面向对象设计原则为基础的,这些设计原则首先都是复用的原则。遵循这些设计原则可以有效地提高系统的复用性,同时提高系统的可维护性。 面向对象设计原则和设计模式也是对系统进行合理重构的指导方针。 为了交互对象之间的松耦合设计而努力 前5个原则组合称为:SOLID 固定原则 分类总结就是: 一、解藕原则:解决耦合性问题,尽少依赖外部。 1、单一职责 2、开闭原则 3、迪米特法则 二、接口原则 4、依赖倒置:依赖接口编程。 5、接口隔离:接口分类和专职。 三、继承父子原则:既有解藕又有接口。 2、原则分析: 1)如果说开闭原则是面向对象设计的目标,依赖倒转原则是到达面向设计"开闭"原则的手段..如果要达到最好的"开闭"原则,就要尽量的遵守依赖倒转原则.
类应该对扩展开发,对修改关闭 依赖倒置原则 要依赖抽象,不要依赖具体类 依赖倒置,倒置在哪? 在依赖倒置原则中的倒置指的是和一般的OO设计的思考方式完全相反。 如果说设计一个比萨店,我们应该从上往下思考,先要有一个比萨店,然后比萨点根据要求生产出具体类型的比萨。 (具体方式可以是简单工厂,也可以是工厂方法模式) 本来的设计方式: ? 依赖倒置的设计方式: ? 最少知识原则 不要让太多类耦合在一起,免得修改系统的一部分,会影响到另外一部分。 ? ? 内聚 当来一个类或者一个模块被设计成只支持一组相关功能的时候,我们说它具有高内聚。反之,当被设计成支持一组不相关的功能时,我们说它具有低内聚。 里氏替换原则为继承定义的规范: 子类必须完全实现父类的方法 子类可以有自己的新方法、新属性
所谓对扩展开放,对修改关闭,其实是设计模式里面所重点提倡的,后续所有涉及模式的介绍其实都是为了程序能够更好的扩展,提倡设计模式的本质就是为了减少 增加一点功能而修改系统的主要逻辑! StringFormatUtil.stringFormat(MSG)); } } 程序必须首先让人类理解,然后顺便让机器能执行^_^xxxx Process finished with exit code 0 总结 通过上述代码可以知道,开闭原则是是为了避免过多的修改原有的代码逻辑 ,用扩展代替修改而衍生的一个原则,不可否认,他也是所有的设计模式都想表达的一个结果,高扩展性。 开闭原则也并不是免费的。有些情况下,代码的扩展性会跟可读性相冲突。比如,我们之前举的 StringFormat格式化的例子。
这种耦合会导致脆弱的设计,当发生变化时,设计会遭受到意想不到的破坏。 为什么要遵循此原则? 我们要遵循OCP原则,OCP背后的机制是抽象和多态,支持抽象和多态的关键机制是继承(比如C#是这样),那么是什么设计规则支配着这种继承用法?最佳的继承层次特征是什么? //具体实现 } public void Update(T entity) { //具体实现 } } 5 该原则是框架设计的核心。 为什么要遵守此原则? 如果高层模块依赖于低层模块,那么对低层模块的改动会直接影响到高层模块,从而迫使他们一次做出改动。 违反原则的情形 高低层组件通过具体类来实现交互。 三、控制反转(IoC) 控制反转是基于面向对象的原则,提倡松耦合理念的设计原则,允许独立开发应用程序的各个组件。 实现方式 实现方式有两种:依赖注入,服务定位。
——《敏捷软件开发原则、模式与实践》 好的代码永远是需要设计的。一名高级程序员,更应该有设计师的潜质,不只是关注怎么用代码实现业务,更关注的是代码的设计。 JavaScript用得上设计原则有单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、合成复用原则和最少知识原则等。本文将选取三个常用的阐述之。 需要明确的是:设计原则只是一种指导,没有哪条原则是在实际开发中必须遵守的。但善用原则,可以帮助更好地设计代码。 1 单一职责原则(srp) 概述 定义:就一个类而言,应该仅有一个引起它变化的原因。 document.createElement('div'); div.innerHTML=item; document.body.appendChild(div); }) } appendDiv([1,2,3,4,5] 在面向对象的程序设计中,开放封闭原则(OCP)是最重要的一条原则。很多时候,一个程序具有良好的设计,往往说明它是符合开放封闭原则的。
这些操作都是通过「修改」来实现新功能的,不符合「开闭原则」。 如果我们要遵循「开闭原则」,必须对修改关闭,对扩展开放。 其次,「开闭原则」的定义是软件实体(模块、类、方法等)应该对扩展开放,对修改关闭。 所有的设计原则都只有一个最终归宿——不破坏原有代码的正常运行,方便扩展。 但是想识别出所有可能的扩展点既不可能也没必要,最合理的做法是对一些比较确定的、短期内可能会发生的需求进行扩展设计。 还是那句话,设计原则和设计模式不是金科玉律,只要适合当前需求,并具备一定弹性的设计就是好设计。要平衡代码扩展性和可读性,切勿滥用设计原则和设计模式,牺牲代码的可读性。
终极目的 稳定、灵活、健壮 实现手段 低耦合、高内聚 设计原则 [设计原则.PNG] 单一职责 & 接口隔离 单一职责 侧重于职责 接口隔离 侧重于业务逻辑 开闭原则 Define: Software 上面的定义描述的很虚,不像另外五条原则一样,有比较实际的描述。 但是却是比较基础的原则之一,他的影子在其他原则的实践中也总是可以看到,笔者的理解,他就是一个精神领袖,是最基本的原则,也是所有原则的集大成的体现。 更多 实现拥抱变化的方法远不止于上面所述的6种原则,但是这这6条原则可以应对大部分情况;更重要的是,脱离业务的设计都是耍流氓,严格死扣某一条原则,是一条不归路 书籍推荐 《设计模式之禅》
设计模式-设计原则 单一职责原则 单一职责原则:一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中。 开闭原则:软件实体应当对扩展开放,对修改关闭。 里氏替换原则 里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象。 接口隔离原则:客户端不应依赖那些它不需要的接口。 { return "电脑"; } @Override public String getMemory() { return "32G DDR5"
这本书中主要讲了六种设计原则: “开-闭”原则 里氏替换原则 依赖倒置原则 接口隔离原则 单一职责原则 迪特米法则 这些设计原则首先都是复用的原则,遵循这些原则可以有效的提高系统的复用性,同时也提高了系统的可维护性 1.为什么会有这样一个原则来作为程序设计的一种约束呢? 那么这个时候就需要在设计之初用到我们的开闭原则来做一个约束了。 依赖倒转原则 实现“开闭”原则的关键是抽象化,并且从抽象化导出具体化实现。如果说开闭原则是面向对象设计的目标的话,依赖倒转原则就是面向对象设计的主要机制(java与模式)。 接口隔离原则要求在设计接口的时候要精简单一; 5. 迪米特法则要求要降低耦合; 6. 开闭原则是总纲,要求对扩展开发,对修改关闭
设计原则 程序开发不仅要知道设计模式还要知道设计的原则,尽最大能力按照原则设计开发,对于代码review或者修改后期项目以及项目交接都会很方便。 三、依赖倒置原则 高层模块不应该依赖底层模块,两者都应该依赖其抽象,抽象不应该依赖细节,细节应该依赖抽象。 四、接口隔离原则 客户端不应依赖它不需要的接口,对接口进行细化;类建的依赖关系应该建立在最小的接口上。建立单一接口,不要建立臃肿庞大的接口。而且要满足单一职责原则。 六、开闭原则 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。开闭原则可以提高复用性,提高维护性。 六大设计原则主要是Java面向对象编程设计的原则,降低项目耦合,分清职责。方便开发和继续维护。 ----
开闭原则(Open Closed Principle)是Java世界里最基础的设计原则,它指导我们如何建立一个稳定的、灵活的系统。 定义: 一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。 软件实体包括以下几个部分: 项目或软件产品中按照一定的逻辑规则划分的模块 抽象和类 方法 开闭原则是为软件实体的未来事物而制定的对现行开发设计进行约束的一个原则。 变化的类型: 逻辑变化 子模块变化 可见试图变化 一个项目的基本路径应该是这样的:项目开发、重构、测试、投产、运维,其中的重构可以对原有的设计和代码进行修改,运维尽量减少对原有代码修改,保持历史代码的纯洁性 开闭原则的重要性: 开闭原则对测试的影响 开闭原则可是保持原有的测试代码仍然能够正常运行,我们只需要对扩展的代码进行测试就可以了。 开闭原则可以提高复用性 在面向对象的设计中,所有的逻辑都是从原子逻辑组合而来的,而不是在一个类中独立实现一个业务逻辑。只有这样代码才可以复用,粒度越小,被复用的可能性就越大。
依赖倒置原则 依赖倒置原则表示高层模块不应该依赖低层模块,两者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。也就是说,要针对接口编程,而不是针对实现编程。 依赖倒置原则是面向对象设计的重要原则之一,它体现了面向对象的思想和封装的特性。如果一个软件能够遵循依赖倒置原则,那么它就具有以下两个优点: 降低了类之间的耦合性,提高了系统的稳定性。 keyboard.input(); mouse.click(); System.out.println("电脑工作"); } } 这个类违反了依赖倒置原则 这样的设计有以下几个缺点: 类之间的耦合度高,如果 Keyboard 类或者 Mouse 类发生变化,就需要修改 Computer 类的代码。 为了遵循依赖倒置原则,我们应该将 Keyboard 类和 Mouse 类设计成实现一个共同的接口 Component。