当前位置: 首页 > news >正文

网站登录接口怎么做上海专业做网站排名

网站登录接口怎么做,上海专业做网站排名,网站开发吗和APP软件一样吗,网页传奇排行如何同时提高一个软件系统的可维护性 和 可复用性是面向对象对象要解决的核心问题。 通过学习和应用设计模式#xff0c;可以更加深入地理解面向对象的设计理念#xff0c;从而帮助设计师改善自己的系统设计。但是#xff0c;设计模式并不能够提供具有普遍性的设计指导原则。…  如何同时提高一个软件系统的可维护性 和 可复用性是面向对象对象要解决的核心问题。     通过学习和应用设计模式可以更加深入地理解面向对象的设计理念从而帮助设计师改善自己的系统设计。但是设计模式并不能够提供具有普遍性的设计指导原则。在经过一段时间的对设计模式的学习和使用之后就会觉得这些孤立的设计模式的背后应当还有一些更为深层的、更具有普遍性的、共同的思想原则。     比如“开-闭”原则这样的面向对象设计原则就是这些在设计模式中不断地显现出来的共同思想原则它们隐藏在设计模式背后的比设计模式本身更加基本和单纯的设计思想。 目录 一、软件与产品 1.1、可维护性 1.2、可复用性 1.3、可维护性与复用性的关系 二、接口 2.1 什么是接口 2.2 为什么使用接口 2.3 接口常见的用法 三、抽象类 3.1 什么是抽象类 3.2 为什么使用抽象类 3.2 抽象类常见的用法 3.3 哪些设计模式使用抽象类 四、软件设计原则 4.1 单一职责原则SRP 4.1.1 如何做到单一职责原则 4.1.2 与其它设计模式的关系 4.1.3 示例 4.2 开闭原则OCP 4.2.1 如何做到开闭原则 4.2.2 与其它设计模式的关系 4.2.3 示例 4.3 里氏代替原则LSP 4.3.1 如何做到里氏代替原则 4.3.2 与其它设计模式的关系 4.3.3 示例 4.4 依赖倒转原则DIP 4.4.1 如何做到依赖倒转原则 4.4.2 与其它设计模式的关系 4.4.3 示例 4.5 接口隔离原则ISP 4.5.1 如何做到接口隔离原则 4.5.2 与其它设计模式的关系 4.5.3 示例 4.6 合成/聚合复用原则CARP 4.6.1 如何做到合成/聚合复用原则 4.6.2 与其它设计模式的关系 4.6.3 示例 4.7 迪米特法则LoD 4.7.1 如何做到迪米特法则 4.7.2 与其它设计模式的关系 4.7.3 示例 一、软件与产品 生命周期 软件分析、设计、开发、测试、部署、维护和退役。产品概念、产品研发、成长阶段、成熟阶段、衰退阶段 和 终结阶段。 关系 软件作为产品的一部分软件可以作为产品的一部分进行开发。许多产品都需要软件来实现其功能和特性。例如智能手机的操作系统、汽车的车载娱乐系统、智能家居设备的控制应用程序等都是软件作为产品的一部分而开发的。在这种情况下软件的开发和产品的开发密不可分软件贡献了产品的核心功能和用户体验。 软件作为独立产品软件本身也可以作为独立的产品进行开发和销售。这种情况下软件的开发和产品的开发是独立的过程。例如办公软件、图像处理软件、游戏等都是作为独立的产品开发的。软件产品可以通过直接销售、订阅模式、广告等方式获得盈利并满足用户的特定需求。 软件驱动和增强产品软件可以在产品中起到驱动和增强的作用。通过软件的不断升级和优化产品可以获得新的功能、性能提升和改进的用户体验。例如智能家居设备通过软件更新获得新的智能控制功能汽车通过车载软件升级获得新的驾驶辅助功能。软件的升级可以延长产品的寿命周期并提升产品的竞争力。 软件支持和服务软件在产品生命周期中通常需要提供支持和服务。这包括技术支持、软件更新、bug修复、安全补丁等。产品的使用者需要软件供应商提供及时的支持和服务来确保软件的正常运行。这些支持和服务对于产品的用户满意度和产品的市场声誉至关重要。 共同点 阶段划分软件生命周期和产品生命周期都可以划分为多个不同的阶段。例如软件生命周期可以包括规划、设计、开发、测试、部署和维护等阶段而产品生命周期可以包括市场导向、产品开发、增长、成熟和衰退等阶段。这些阶段的划分都有助于管理和控制产品的不同阶段的活动和目标。 目标导向软件生命周期和产品生命周期都以实现特定的目标为导向。在软件生命周期中目标可能包括开发高质量、稳定的软件系统并在市场上取得成功而在产品生命周期中目标可能包括通过不同阶段的活动实现产品的成功上市、增加市场份额并获取利润。 迭代与优化在软件和产品的生命周期过程中都存在迭代和优化的机会。软件开发团队和产品管理团队都会根据用户反馈和市场需求进行持续改进和优化。软件开发过程中可能会有多个版本的发布和升级以满足不断变化的用户需求产品生命周期中也可能会有产品的升级、特性增加和市场推广等举措以适应竞争压力和市场变化。 维护与退役软件和产品都需要进行维护和最终退役。在软件生命周期中维护阶段涉及缺陷修复、升级和性能优化等工作退役阶段则包括软件的退市、替代或停止支持。在产品生命周期中维护阶段可能包括产品技术支持、售后服务等而退役阶段则可能涉及产品的下架、关闭或转型。 1.1、可维护性 系统可维护性指的是一个系统在部署后能够便捷、有效地进行维护的能力。一个具有良好可维护性的系统能够降低维护成本提高系统的可靠性和可用性同时保证系统能够快速响应和适应后续的变化和需求。 软件退役根本原因 过于僵硬很难在一个软件系统里加入一个新的性能哪怕是很小的都很难。这是因为加入一个新性能不仅仅意味着建造一个独立的新模块而且因为这个新性能会波及很多其他模块最后变成跨越几个模块的改动。使得一个起初只需要几天的工作最后需要几个月才能完成。过于脆弱软件系统在个性已有代码时过于脆弱。对一个地方个性往往会导致看上去没有什么关系的另一个地方发生故障。尽管在个性之前设计师们会竭尽所能预测可能故障点但是在个性完成之前系统的原始设计师们甚至都无法确切预测到可能会波及到的地方。一碰就碎的情况造成软件系统过于脆弱。利用率低复用指一个软件的组成部分可以在同一个项目的不同地方甚至另一个项目中重复使用。每当程序员发现一段代码、函数、模块所做的事情是可以在新的模块、或者新系统中使用的时候他们总是发现这些已有的代码依赖于一大堆其他的东西以至于很难将它们分开。最后他们发现最好的办法就是不去碰这些已有的东西而是重新写自己的代码。他们可能会使用源代码剪贴的办法以最原始的复用方法节省一些时间。这样的系统就有复用低的问题。黏度过高有时一个改动呆以以保存原始设计意图和原始设计框架的方式进行也可以以破坏原始意图和框架的方式进行。第一种办法无疑会对系统的未来有利第二种办法是权宜之计可以解决短期的问题但是会牺牲中长期利益。第二种办法比较容易且快速。一个系统的设计如果使用第二种办法比第一种办法很多的话就叫做黏度过高。一个黏度过高的系统会诱使维护它的程序员采取错误的维护方案并惩罚采取正确维护方案的程序。 设计目的 一个软件有良好的维护性在软件设计之初和实现过程中要做到如下几个理念     可扩展性         新的性能可以很容易地加入到系统中去就是可扩展性。与“过于僵硬”的属性相反     灵活性         可以允许代码个性平稳地发生而不会波及到很多其它的模块这就是灵活性。与“过于脆弱”的属性相反     可插入性         可以很容易地将一个类抽出去同时将另一个有同样接口的类加入进来这就是可插入性。与“黏度过高”的属性相反              通过考虑和提升系统的可维护性可以减少系统维护过程中的风险和工作量同时促进系统的持续演化和升级。在软件开发过程中考虑和优化系统的可维护性是非常重要的它有助于提高开发效率、降低维护成本最终提升系统的整体质量和用户满意度。 1.2、可复用性 系统可复用性是指系统中的软件组件、模块或功能能够在多个不同的场景或系统中被重复利用的能力。这种能力可以帮助开发人员在不同的项目中共享和重复利用已有的代码和功能从而提高开发效率、降低成本并且可以带来更高的质量和一致性。 可复用性通常包括以下几个方面 算法的复用各种算法比如排序算法得到了大量的研究。现在几乎不会有人在应用程序编程时试图建立自己的排序算法通常的做法是在得到了很好的研究的各种算法中选择一个。这就是算法的复用。 数据结构复用与算法的复用相对的是数据结构的复用。如队、栈、队列、列表等数据结构得到了十分透彻的研究所有的计算机教学都要详细描述这些数据结构。这就是数据结构的复用。 模块化设计系统应该具有明确定义的模块化结构不同的功能模块之间通过清晰的接口进行连接。每个模块应该有自己独立的功能和责任以便于被其他系统或项目所复用。 标准化接口系统中的模块和组件应该提供标准化的接口以确保与其他组件的兼容性和可替换性。常见的接口标准包括 API、规范文件、数据格式等。 文档和示例系统中的复用组件应该配备完善的文档和示例帮助其他开发人员理解和正确使用这些组件。文档可以包括 API 文档、使用指南、示例代码等。 独立性可复用的组件应当尽可能地与系统的其余部分解耦降低对具体上下文的依赖性以便于在不同的环境中被引入和使用。 兼容性可复用组件应当能够在不同的系统环境中被无缝集成和使用不论是技术架构、操作系统还是开发语言都应当尽量具有通用性。 1.3、可维护性与复用性的关系 可维护性与可复用性之间存在密切的关系 设计影响软件的设计对于可维护性和可复用性都有着重要的影响。一个良好的软件设计不仅能够提高软件的可维护性还能够提高其可复用性。模块化的设计、清晰的接口定义和低耦合的架构都有利于提高软件的可维护性和可复用性。 目标一致在设计阶段提高软件的可维护性和可复用性的目标是一致的。例如通过提高模块间的独立性和接口的规范化既可以使得软件更易于维护又可以使得模块更容易被其他系统或项目复用。 共同影响因素软件的可维护性和可复用性都受到诸如模块化、文档化、标准化接口、独立性等因素的影响。这些因素对于两者的提升都是有益的。 适用范围可复用的组件通常具有良好的接口定义和独立性这也同时使得这些组件更容易维护。而在维护过程中发现的一些通用性问题和bug的修复也可以促进组件的可复用性。     软件的可维护性和可复用性之间是相辅相成的关系。通过提高软件的可维护性可以使得软件更易于维护和变更从而增强了软件的可复用性。而一个具有高可复用性的软件组件也通常会具有良好的可维护性因为它必须能够在不同的环境和场景下被重复利用。因此在软件工程中需要综合考虑提高软件的可维护性和可复用性将有助于构建高质量、易维护和可持续演进的软件系统。 二、接口 2.1 什么是接口 在Java编程语言中接口Interface是一种特殊的引用类型它是一组没有方法体的抽象方法的集合。接口定义了一个规范所有实现该接口的类都必须实现接口中定义的所有方法。接口在Java中扮演了重要的角色用于定义类之间的契约实现了面向对象编程中的接口隔离原则和多态特性。 特点 完全抽象接口中的方法都是抽象方法没有方法体只有方法签名没有具体的实现。接口只定义了方法的规范具体的实现由实现接口的类来完成。 多实现一个类可以实现多个接口通过关键字 implements 来实现。这种多实现的特性使得Java支持了接口的多继承一个类可以具有多个接口的行为。 接口间的继承接口也可以继承其他接口通过关键字 extends 来实现。这种接口间的继承关系可以帮助组织和继承接口的行为形成更复杂的接口体系。 规范契约接口用于定义类之间的契约描述了类应该具有的行为和特征。实现接口的类必须提供接口中定义的所有方法的具体实现。 常量定义接口中可以定义常量常量默认为 public static final表示一旦定义后不允许修改。 默认方法从Java 8开始接口中可以定义默认方法使用关键字 default 来标识。默认方法是一种带有方法体的方法可以在接口中提供一些默认的实现而不需要实现类重新实现。 接口变量变量可以声明为接口类型即接口变量。通过接口变量可以引用实现了接口的类的对象实现了接口的多态特性。 接口的应用接口在Java中广泛应用用于实现回调函数、定义API规范、实现插件系统等各种场景。 2.2 为什么使用接口 实现多态接口提供了多态性允许使用接口类型的引用来引用实现了该接口的任何类的对象。这样可以根据具体对象的类型来调用相应的方法从而实现多态性提高代码的灵活性和扩展性。 降低耦合接口可以将实现类与接口的使用者解耦实现了代码的分离。实现类在实现接口的方法时只需遵循接口规范而不用关心具体的调用方从而降低了模块之间的依赖关系提高了代码的可维护性和灵活性。 定义规范接口是对行为的规范化描述定义了类应该具有的行为。通过接口可以清晰地定义出系统的接口或规范使得系统更加清晰方便团队协作开发。 多继承接口可以被多个类实现因此接口在一定程度上弥补了Java单继承的不足。一个类可以实现多个接口从而获得多个不同接口的特性增强了类的灵活性。 实现回调接口常常用于实现回调机制例如事件监听器、观察者模式等。通过接口可以定义回调方法然后由其他类来实现这些接口从而实现灵活的回调逻辑。 适用于插件开发接口可用于插件式开发即定义一个接口规范然后由插件来实现这个接口系统可以动态加载这些插件实现了系统的可扩展性和灵活性。     接口是面向对象编程中非常重要的概念它具有多种优点包括提高代码的灵活性和可维护性、降低耦合度、定义规范和契约、支持多继承等。在软件设计中合理地使用接口可以提高代码的质量、可扩展性和复用性是一种非常有用的工具和编程思想。 不足 不支持方法实现接口只能定义方法签名无法提供默认的方法实现。这意味着每个实现接口的类都必须自己实现接口中的所有方法即使这些方法在多个实现类中代码是相同的也无法进行代码复用。 局限于公共接口接口的方法默认都是公共的无法定义私有方法。这可能会导致对一些实现类不应该暴露的方法也需要在接口中进行定义。 无法包含状态和变量接口只能包含静态常量而无法包含实例变量和非静态方法。这意味着无法在接口中保存状态也无法定义实例方法来访问或修改状态。 不支持多继承与抽象类不同接口可以实现多继承一个类可以实现多个接口。然而这也可能导致类之间的接口过于复杂代码难以维护和理解。 接口版本兼容性问题在接口中新增方法或修改方法签名后所有实现该接口的类都需要做相应的改动以适应新的接口。这可能导致对现有代码的修改破坏已有的稳定状态。 容易出现过多接口接口的设计应遵循高内聚低耦合的原则但有时为了满足不同的需求容易在系统中出现过多的接口增加了代码的复杂性和理解难度。     综上所述接口在软件开发中具有许多优点但也有一些缺点和限制。在使用接口时应权衡利弊根据具体需求进行选择并结合抽象类或其他设计模式来实现代码的灵活性和可维护性。 2.3 接口常见的用法 接口是一种定义行为的方法即定义了某个类或模块需要实现的方法而不需要关心具体的实现细节。 常见用法 定义 API 规范接口通常被用来定义类之间的契约或规范描述类应该具有的行为和特征。通过定义接口可以明确规定类应该实现哪些方法并提供给其他开发者使用以便在不知道具体实现类的情况下使用接口定义的方法进行编程。 实现回调函数接口经常在实现回调机制时使用。定义一个接口其中包含回调方法然后其他类可以实现这个接口以提供具体的回调行为。通过回调函数实现类可以在特定的事件发生时通知调用方。 多态性接口实现了多态性的特性使得可以使用接口类型的引用来引用实现了该接口的任何类的对象。这样可以根据具体对象的类型来调用相应的方法实现多态操作。 插件机制接口可用于实现插件系统通过定义接口规范不同的插件可以实现这个接口并在系统中使用。这种插件式开发方式使得系统具有良好的扩展性和灵活性。 实现策略模式接口可以用于实现策略模式其中定义一个策略接口多个具体策略实现这个接口并被用来实现不同的算法或策略。在运行时可以根据需要动态切换策略实现。 组织代码接口可以用于组织代码将具有相似功能的方法定义在一个接口中然后不同的类实现这个接口来提供具体的功能。这样可以更清晰地组织和管理代码。 简化单元测试接口可以用于简化单元测试。通过使用接口来定义类的依赖可以更容易地创建模拟对象进行单元测试提高代码的可测试性。 扩展性接口具有良好的扩展性即可以在不修改原有代码的基础上增加新的方法和属性。这样当需要增加新的功能时只需要实现新的接口而不需要修改原有的代码。依赖注入接口可以用于依赖注入的实现。通过接口可以将不同的依赖注入到类或模块中使得代码更加灵活和可测试。     利用接口可以提高代码的可扩展性、灵活性和可维护性增强程序的可读性和可测试性。合理地使用接口可以帮助我们更好地组织代码规范开发流程并促进更好的代码复用和扩展。 示例 当定义一个接口时可以为接口中的方法提供一个约定而具体的类可以根据需要来实现这些方法。以下是一个简单的 Java 接口使用示例   首先定义一个接口 Shape public interface Shape {double getArea(); // 计算图形的面积double getPerimeter(); // 计算图形的周长 }然后我们可以创建实现这个接口的具体类比如 Circle 和 Rectangle public class Circle implements Shape {private double radius;public Circle(double radius) {this.radius radius;}Overridepublic double getArea() {return Math.PI * radius * radius;}Overridepublic double getPerimeter() {return 2 * Math.PI * radius;} }public class Rectangle implements Shape {private double length;private double width;public Rectangle(double length, double width) {this.length length;this.width width;}Overridepublic double getArea() {return length * width;}Overridepublic double getPerimeter() {return 2 * (length width);} }接着我们可以使用这些具体类来创建对象并调用接口中定义的方法 public class Main {public static void main(String[] args) {Shape circle new Circle(5.0);System.out.println(Circle Area: circle.getArea());System.out.println(Circle Perimeter: circle.getPerimeter());Shape rectangle new Rectangle(4.0, 6.0);System.out.println(Rectangle Area: rectangle.getArea());System.out.println(Rectangle Perimeter: rectangle.getPerimeter());} }在上面的示例中我们定义了 Shape 接口并且创建了两个实现了 Shape 接口的具体类 Circle 和 Rectangle。然后在 Main 类中我们创建了 Circle 和 Rectangle 的对象并调用了接口中定义的方法。这样通过接口我们可以对不同的形状对象使用相同的方法进行操作从而实现了接口的多态特性。     这个简单的示例展示了接口的使用通过接口可以定义一组类的共同行为规范并实现这些规范的具体方法从而提高代码的灵活性和可维护性。 三、抽象类 3.1 什么是抽象类 抽象类是Java中一种特殊的类它不能被实例化只能被子类继承。抽象类通过使用关键字 abstract 来声明并可以包含抽象方法和具体方法。 特点 不能被实例化抽象类不能直接创建对象只能被继承后才能使用。由于抽象类包含抽象方法没有具体实现因此无法直接实例化对象。 可以包含抽象方法和具体方法抽象类可以包含抽象方法和具体方法。抽象方法是没有实现体的方法只有方法的声明。具体方法是有具体实现的方法。子类继承抽象类时必须实现所有的抽象方法而具体方法可以被继承也可以在子类中进行重写。 用于定义规范和共享代码抽象类常常被用于定义类之间的共同行为和特征作为一种规范或模板。它可以定义抽象方法作为规范要求具体子类提供方法的实现。同时抽象类中的具体方法可以被多个子类共享和复用。 支持单继承与接口不同抽象类只能被一个类继承即Java只支持单继承。一个类只能继承一个抽象类但可以实现多个接口。 具有继承特性抽象类可以被其他类继承子类继承了抽象类后可以继承和访问抽象类中的成员变量和方法。 3.2 为什么使用抽象类 定义模板和规范抽象类可以定义一些方法的框架结构让子类去实现具体的细节。这样可以为子类提供一种模板和规范确保子类都具备一定的基本行为有助于统一代码风格提高代码的一致性和可读性。 提高代码复用抽象类可以包含一些通用的方法和属性这些通用内容可以被多个子类继承和复用从而避免了重复编写相同的代码提高了代码的重用性。 封装共同行为抽象类可以封装一些子类共同的行为将公共的部分抽象到抽象类中有助于降低代码的耦合度提高代码的内聚性增强了系统的可维护性和扩展性。 定义共同接口抽象类可以定义抽象方法要求继承它的子类必须实现这些方法这样可以定义一组类的共同接口确保继承类具备特定的行为和功能。 实现多态性抽象类允许多态性的应用子类可以向上转型为其抽象类类型的引用从而通过统一的接口来处理不同的子类对象提高了程序的灵活性和可扩展性。 方便后续扩展通过抽象类可以很容易地向系统中添加新的功能和行为通过新增具体子类来扩展系统的功能不需要修改抽象类本身符合开闭原则。     总的来说抽象类提供了一种优雅的方式来定义类之间的共同行为和关联通过创建抽象类可以简化代码的设计和维护提高代码的可读性和可维护性从而更好地满足软件开发中的需求。 不足 限制了单继承Java 只支持单继承因此如果一个类继承了某个抽象类就无法再继承其他类。这会限制类的灵活性特别是在需要使用或继承多个类的情况下可能会受到限制。 增加了类的耦合度因为子类必须继承抽象类这意味着子类和抽象类之间存在一定的耦合关系导致子类的实现与抽象类的定义紧密相连。这种紧耦合可能会增加代码的复杂性并影响代码的灵活性。 对新功能的扩展可能会受限一旦一个抽象类被创建并投入使用如果后续需要为其添加新的方法将会影响所有的子类因为它们都必须实现新添加的方法。这可能导致现有子类需要做修改破坏已有的稳定状态。 难以对现有抽象类进行修改在现有的抽象类中修改方法签名或删除已存在的方法会对所有的子类造成影响因为它们都必须相应地修改。这可能导致修改波及现有代码的大规模变更。 复杂性增加随着应用的扩展和发展抽象类体系可能变得越来越复杂。难以管理的复杂度可能导致代码维护和理解的困难。     考虑到这些缺点在使用抽象类时需要认真权衡利弊根据具体需求来选择是否使用抽象类或者考虑使用其他实现接口等方式来弥补抽象类的缺陷。 3.2 抽象类常见的用法 常见用法 定义规范和模板抽象类可以定义一些方法的框架结构让子类去实现具体的细节。这种用法常见于设计模式中的模板方法模式通过定义抽象类中的算法流程然后让子类根据实际情况进行具体实现。 封装共同行为抽象类可以封装一组子类的共同行为将公共的部分抽象到抽象类中。这样可以避免重复编写相同的代码提高代码的复用性和可维护性。 定义共同接口抽象类可以定义一组子类必须实现的方法形成共同的接口。这种用法常见于设计模式中的策略模式通过定义抽象类中的方法签名让不同的子类提供不同的实现以实现不同的策略。 实现多态性抽象类可以作为父类允许子类向上转型为其抽象类类型的引用从而通过统一的接口来处理不同的子类对象。这种用法常见于多态性的应用场景可以提高程序的灵活性和可扩展性。 作为框架基类抽象类常被用作框架的基类提供框架的核心结构和基本行为。子类可以继承抽象类并进行扩展以实现具体的业务逻辑。 为子类提供默认实现抽象类可以为一些方法提供默认实现这样子类可以选择性地覆盖这些方法而不是强制全部重新实现。这种用法可以减少子类的工作量并提供一些通用的默认行为。 组织相关方法当有一组相关的方法需要定义时可以使用抽象类将这些方法组织在一起。这样其他类可以实现这个抽象类并重写这些方法以满足自己的需求。这有助于提高代码的组织性和可维护性。代码复用通过使用抽象类可以在不同的类之间共享一些通用的行为和属性。子类可以继承抽象类并覆盖抽象类中定义的方法来实现自己的行为。这样可以避免代码的重复编写提高代码的复用性。设计模式在许多设计模式中抽象类都起着重要的作用。例如在工厂模式中可以使用抽象类来定义一个通用的工厂接口其他工厂类可以实现这个接口来创建不同的对象。这有助于提高代码的可扩展性和可维护性。     总的来说抽象类具有许多实用的用法可以提供模板、规范、共同接口和共享代码等功能。这些用法可以帮助开发者更好地组织和设计代码提高代码的可读性、可维护性和可扩展性。 示例 假设我们正在开发一个几何图形的应用程序其中有多种不同类型的几何图形如圆形、矩形和三角形等。我们希望通过抽象类定义一个共享的接口并在具体的子类中实现不同的几何图形。 // 定义抽象类Shape abstract class Shape {// 抽象方法获取图形的面积public abstract double getArea();// 抽象方法获取图形的周长public abstract double getPerimeter(); }// 具体的子类Circle class Circle extends Shape {private double radius;public Circle(double radius) {this.radius radius;}public double getArea() {return Math.PI * radius * radius;}public double getPerimeter() {return 2 * Math.PI * radius;} }// 具体的子类Rectangle class Rectangle extends Shape {private double length;private double width;public Rectangle(double length, double width) {this.length length;this.width width;}public double getArea() {return length * width;}public double getPerimeter() {return 2 * (length width);} }// 使用示例 public class Main {public static void main(String[] args) {Circle circle new Circle(5);System.out.println(Circle Area: circle.getArea()); // 输出圆形的面积Rectangle rectangle new Rectangle(3, 4);System.out.println(Rectangle Perimeter: rectangle.getPerimeter()); // 输出矩形的周长} }在上述示例中我们定义了一个抽象类Shape其中包含了两个抽象方法getArea()和getPerimeter()用于获取图形的面积和周长。然后我们通过具体的子类Circle和Rectangle来继承抽象类并实现这两个抽象方法。     在Main类中我们创建了一个Circle对象和一个Rectangle对象并分别调用它们的getArea()和getPerimeter()方法来获取圆形的面积和矩形的周长并打印输出结果。     通过使用抽象类我们可以定义图形对象的公共接口并在具体的子类中实现不同的几何图形的操作。这样我们可以以统一的方式处理不同类型的几何图形对象提高代码的复用性和可扩展性。 3.3 哪些设计模式使用抽象类 抽象类在设计模式中的作用 定义公共接口抽象类用于定义一组共享的方法或属性形成公共接口。这些方法或属性可以被子类继承和实现确保在不同的子类中具有一致的行为和约束。 提供默认实现抽象类可以为一些方法提供默认的实现这样子类可以选择性地覆盖它们而不是强制全部重新实现。这样可以减少子类的工作量并提供一些通用的默认行为。 促进代码复用抽象类可以定义一些通用的实现供多个相关的子类共享。通过使用抽象类可以减少代码的重复编写提高代码的复用性和维护性。 实现多态性抽象类作为父类允许子类向上转型为其抽象类类型的引用从而通过统一的接口来处理不同的子类对象。这种多态性的应用可以提高程序的灵活性和可扩展性。 框架的基类抽象类经常被用作框架的基类提供框架的核心结构和基本行为。子类可以继承抽象类并进行扩展以实现具体的业务逻辑。 用作模板方法模式的骨架抽象类可以作为模板方法模式的关键组成部分。抽象类中定义了一个算法的骨架将具体的实现延迟到子类中以实现算法的定制化。     抽象类在设计模式中扮演着重要的角色通过定义共享接口、提供默认实现、促进代码复用、实现多态性等方式帮助开发者设计和组织更加灵活、可维护和可扩展的代码结构。 常见的设计模式 模板方法模式Template Method Pattern模板方法模式使用抽象类定义一个算法的骨架将具体的实现延迟到子类中。抽象类中的模板方法定义了算法的流程而具体实现则交给子类去实现。 工厂方法模式Factory Method Pattern工厂方法模式使用抽象类作为工厂的基类定义一个创建对象的接口。每个具体的子类工厂继承抽象类并实现工厂方法来创建不同的对象。 策略模式Strategy Pattern策略模式使用抽象类定义一组算法族通过继承抽象类并实现其中的方法来提供不同的具体算法。客户端根据需要选择不同的策略来完成任务。 状态模式State Pattern状态模式使用抽象类定义一组状态并使用子类继承并实现这些状态。通过切换不同的状态对象可以改变对象的行为和状态。 桥接模式Bridge Pattern桥接模式使用抽象类作为桥梁将抽象类和实现类分离开来。抽象类定义了抽象方法而实现类负责具体的实现通过组合的方式实现抽象类和实现类的解耦。 装饰器模式Decorator Pattern装饰器模式使用抽象类作为装饰器的基类通过继承抽象类并进行装饰来扩展对象的功能。装饰器模式允许动态地给对象添加新的功能而无需修改其原始类。 适配器模式Adapter Pattern适配器模式使用抽象类作为适配器的基类通过继承抽象类并实现适配器接口的方法来将不兼容的接口进行转换。适配器模式将两个不兼容的接口之间的转换工作放在适配器类中。     这些设计模式都是基于抽象类和继承的概念通过使用抽象类来定义接口、提供默认实现以及实现多态性和代码复用。它们帮助开发者在设计和组织代码时更加灵活、可维护和可扩展。 四、软件设计原则 设计原则 单一职则原则Single Responsibility PrincipleSRP“开-闭”原则Open-Closed PrincipleOCP里氏替换原则Liskov Substitution PrincipleLSP依赖倒转原则Dependency Inversion ProncipleDIP接口隔离原则Interface Segregation PrincipleISP组合/聚合复用原则Composition/Aggregation PrincipleCARP迪米特法则Law of DemeterLoD 4.1 单一职责原则SRP 定义 单一职责原则Single Responsibility PrincipleSRP是面向对象设计中的重要原则之一它指导着我们设计和组织类、模块和函数。单一职责原则的核心思想是一个类或模块应该只有一个引起它变更的原因即应该只有一个职责。              具体来说单一职责原则要求一个类或模块只负责一项特定的功能或职责它应该只有一个改变的原因。换句话说一个类内部的代码应该实现一种类型的责任如果一个类承担的职责过多就等于给这个类增加了变更的原因使得类变得复杂、难以维护和扩展。 优点 降低类的复杂性每个类只负责单一的功能使得类的职责更加清晰明确避免了类的职责过于复杂和混乱。 提高代码的可读性类的职责单一使得类的结构更加清晰易于理解提高了代码的可读性和可维护性。 提高代码的可维护性当类的职责单一时当需求发生变化或 bug 需要修复时代码变更的影响范围更加集中维护和修改起来更加方便。 降低耦合度类的职责单一减少了类与类之间的依赖关系降低了代码的耦合度使得系统更加灵活易于扩展和维护。 支持单元测试类的职责单一易于编写和执行单元测试因为每个类的功能更加明确测试范围更加集中和清晰。     通过遵循单一职责原则可以设计出更加健壮、可维护和可扩展的系统有助于提高软件质量和开发效率。 缺点和挑战 类的数量增多遵循单一职责原则可能会导致类的数量增多。如果每个功能都要创建一个独立的类可能会导致类的数量庞大增加了系统的复杂性。 代码重复将功能分离到不同的类中可能会导致代码的重复。因为不同的类需要处理不同的职责可能会有一些共享的代码逻辑需要在多个类中重复编写。 跨类协作复杂性增加当类的职责被细分为多个单一职责时不同的类之间需要进行协作。这可能导致类之间的交互复杂化增加了设计和调试的难度。 可能引入额外的接口和依赖关系为了实现单一职责原则可能需要定义更多的接口和依赖关系。这可能增加了代码的耦合度和维护的复杂性。     需要权衡单一职责原则的利弊并结合具体的项目需求和设计目标来进行决策。在某些情况下追求单一职责原则可能会使代码更加清晰、可维护和灵活但在其他情况下过度分割职责可能会导致代码冗余和复杂性增加。在实际应用中需要根据项目特点、团队的技术水平和业务要求来平衡设计和代码组织的复杂性。 4.1.1 如何做到单一职责原则 明确定义类的职责在设计类时明确定义该类的职责范围确保每个类只负责一项特定的功能或职责。 关注领域内的功能确保类内部的方法和属性都与该类的职责相关避免将不相关的功能混合到同一个类中。 精简类的函数和方法每个函数和方法应该只实现单一功能避免函数和方法包含过多的业务逻辑。如果一个函数或方法需要实现多个功能考虑将其拆分为多个单一职责的函数或方法。 避免跨界操作避免类与类之间进行过多的交互尽量保持类的独立性减少类之间的耦合。 应用设计模式在实际设计中可以使用一些常见的设计模式如工厂模式、策略模式、观察者模式等来帮助实现单一职责原则将不同的职责分配到不同的类中并通过接口抽象来降低类之间的依赖关系。 持续重构在开发过程中保持对代码的持续审查和重构确保每个类的职责都得到了恰当的划分避免职责蔓延和功能耦合。 遵循设计原则除了单一职责原则还需要结合其他设计原则如开闭原则、依赖倒置原则等来保持代码的灵活性、可扩展性和可维护性。     通过遵循以上指导可以更好地实现单一职责原则设计出清晰、灵活且易于维护的代码结构。 4.1.2 与其它设计模式的关系 工厂模式Factory Pattern工厂模式可以帮助将对象的创建逻辑单独封装到工厂类中实现了对象创建和具体职责的分离符合单一职责原则。 策略模式Strategy Pattern策略模式定义了一系列算法并将每个算法封装到具有单一职责的类中。使用策略模式可以使得算法的变化独立于使用算法的客户符合单一职责原则。 观察者模式Observer Pattern观察者模式定义了一种一对多的依赖关系当一个对象的状态发生变化时所有依赖它的对象都得到通知并自动更新。观察者模式中观察者和被观察者各自有各自的职责符合单一职责原则。 装饰器模式Decorator Pattern装饰器模式可以动态地为对象添加额外的职责而且还能够避免类的职责蔓延。装饰器模式通过将职责分割到单一的装饰类中符合单一职责原则。 命令模式Command Pattern命令模式将请求封装成对象从而使你可以用不同的请求对客户进行参数化对请求排队或记录请求日志以及支持可撤销的操作。命令模式中命令对象负责封装命令执行的操作符合单一职责原则。     这些设计模式帮助将类的职责进行有效分离使得每个类都具有清晰的单一职责从而满足了单一职责原则。使用这些设计模式有助于编写结构清晰、易于维护和扩展的代码。 4.1.3 示例 可以通过以下几个步骤来实现单一职责原则 明确类的职责在设计类时明确确定该类的职责范围并确保该类只负责一项特定的功能。 拆分多余职责如果存在一个类包含多个不相关的职责将其拆分为多个单一职责的类。每个类都负责一个具体的职责。 定义接口定义接口来描述每个类的职责。接口可以帮助明确类的功能并提供一致的契约。 封装数据和行为为每个类封装相应的数据和方法。确保类的属性和方法与其职责相关并且不包含其他职责的逻辑。 下面是一个简单的示例 // 定义接口来描述职责 interface EmployeeManagerInterface {void addEmployee(Employee employee);void removeEmployee(Employee employee);void calculateSalary(Employee employee); }// 实现具体的职责 class EmployeeManager implements EmployeeManagerInterface {Overridepublic void addEmployee(Employee employee) {// 添加员工的逻辑}Overridepublic void removeEmployee(Employee employee) {// 移除员工的逻辑}Overridepublic void calculateSalary(Employee employee) {// 计算员工薪水的逻辑} }// 定义员工类 class Employee {// 员工属性和方法 }public class Main {public static void main(String[] args) {EmployeeManagerInterface manager new EmployeeManager();Employee employee new Employee();// 使用 manager 对象进行员工管理的操作manager.addEmployee(employee);manager.calculateSalary(employee);manager.removeEmployee(employee);} }     如上示例中我们使用接口 EmployeeManagerInterface 描述了员工管理的职责并提供了相应的方法。具体的职责则由 EmployeeManager 类来实现包括添加员工、移除员工和计算薪水等操作。同时我们还定义了 Employee 类来表示员工的属性和方法。     通过将不同的职责分离为不同的类和接口我们实现了单一职责原则使得每个类都具有明确的职责便于代码的维护和扩展。 4.2 开闭原则OCP 定义 软件设计的开闭原则Open-Closed PrincipleOCP是面向对象设计中的重要原则之一由勃兰特·梅耶Bertrand Meyer提出。该原则的核心思想是“对扩展开放对修改关闭”。              具体来说开闭原则要求一个软件实体类、模块、函数等应该对扩展开放即在不修改原有代码的情况下可以通过扩展来增加新功能或修改旧功能。同时对修改关闭意味着一旦软件实体的设计完成后就不应该再修改其源代码以避免对系统其他部分造成影响。 优点 可扩展性开闭原则要求系统对扩展是开放的可以通过添加新的代码来增加新的功能或模块。这使得系统更容易适应变化和支持新的需求同时降低了向现有功能添加新功能时的风险。 可维护性由于开闭原则鼓励使用扩展而不是修改现有代码这使得维护工作更加简化。通过增加新代码来实现变化可以避免对已有功能可能产生的潜在错误或导致其他不必要的修改。 可测试性遵守开闭原则使得代码更具可测试性。由于不需要修改现有代码来实现新功能可以更方便地编写针对新增代码的单元测试确保新功能的正确性和稳定性而不会对现有功能造成意外影响。 代码复用性开闭原则鼓励通过扩展已有的抽象概念和接口来实现新功能这样可以使得代码更具有复用性。当需要添加类似的功能时可以直接使用已有的抽象类或接口减少重复编写代码的工作量。 系统稳定性由于开闭原则要求对现有代码的修改尽量降低这有助于维持系统的稳定性和正确性。通过扩展而不是修改现有代码可以减少引入错误的风险降低系统出错的概率。     总的来说遵守开闭原则可以提高软件系统的可扩展性、可维护性、可测试性并提升代码的复用性同时也有助于保持系统的稳定性。这些优点使得开闭原则成为设计高质量、可持续发展的软件系统的重要指导原则。 缺点和挑战 抽象设计的复杂性为了实现开闭原则需要预先设计良好的抽象层次结构和接口这可能增加了系统的复杂性。正确地确定和定义抽象概念可能需要更多的时间和精力。 维护成本在长期维护过程中系统可能需要频繁地进行扩展和变化。遵守开闭原则要求增加新功能而不是修改现有代码这可能导致系统的代码量增加增加了对代码的维护成本。 非充分性虽然开闭原则的目标是尽量避免修改现有代码但现实情况下可能会有一些特殊情况无法完全符合开闭原则。有时候对现有代码进行一些必要的修改可能是更有效的解决方案。 引入复杂性为了遵守开闭原则可能需要引入更多的抽象概念、接口和设计模式从而增加了系统的复杂性。在某些情况下这些复杂性可能会对开发人员的理解和维护造成困难。 对扩展的需求无法预见在系统设计初期很难准确地预见未来可能的扩展需求。过度地设计抽象层次结构和接口可能会带来不必要的复杂性和开销。     开闭原则是一种高层次的设计原则它提供了更灵活和可扩展的系统设计方案。然而遵守开闭原则可能需要权衡其他方面的考虑并需要根据具体的项目需求和环境来判断是否适用。在实践中需要综合考虑开闭原则的优点和缺点合理地应用和权衡以求达到系统设计的最佳平衡点。 4.2.1 如何做到开闭原则 采用以下设计方法 利用抽象类和接口通过定义抽象类或接口可以让实现类对扩展开放同时限制了对源代码的修改。使用多态性通过多态性可以在不修改原有代码的情况下改变对象的行为。使用设计模式许多设计模式如工厂模式、策略模式、观察者模式等都是为了帮助我们设计满足开闭原则的系统结构。这些设计模式可以帮助我们将系统的不同部分相互解耦以便进行灵活的扩展。 参数化配置将系统的行为参数化配置使得系统的行为可以通过配置而不是修改代码来改变。 代码重构当需要修改现有代码时可以考虑使用代码重构的方式将代码结构重组或抽取出通用部分从而使得系统更加符合开闭原则。     遵守开闭原则的关键在于设计具有良好扩展性和灵活性的系统架构使得系统的不同部分可以相互独立地扩展和变化而不影响其他部分的稳定性和正确性。 4.2.2 与其它设计模式的关系 与开闭原则密切相关设计模式 工厂模式Factory Pattern工厂模式通过定义一个公共的接口和抽象类来创建对象使得系统能够面向接口编程而不是具体实现类。这样当需要添加新的产品时只需扩展工厂类和产品类而不需要修改现有的代码。 策略模式Strategy Pattern策略模式通过将一组可替换的算法封装成独立的类并通过一个公共接口进行调用。这样系统的行为可以在运行时动态地更改和选择实现了开闭原则的要求。 观察者模式Observer Pattern观察者模式定义了一种一对多的依赖关系当一个对象状态发生变化时其他依赖的对象都能够接收到通知并做出相应响应。这样可以通过添加/移除观察者来扩展系统的功能而不需要修改被观察者的代码。 装饰器模式Decorator Pattern装饰器模式通过包装和增强已有对象的功能而不需要修改原始对象的代码实现了开闭原则。可以通过添加装饰器类来扩展对象的功能同时保持现有代码的稳定性。 适配器模式Adapter Pattern适配器模式用于将一个类的接口转换成客户端所期望的接口。通过适配器可以在不修改现有代码的情况下将已有的类和新的接口进行适应实现了开闭原则的要求。     还有许多其他的设计模式如模板方法模式、享元模式、状态模式等它们在不同的情况下都可以帮助我们实现开闭原则并提高系统的灵活性和可扩展性。根据具体的需求和设计情境选择合适的设计模式可以更好地满足开闭原则的要求。 4.2.3 示例 通过创建接口和抽象类来实现开闭原则并且使用多态和依赖倒置原则来保持系统的灵活性。     假设有一个图形绘制系统需要支持绘制不同形状的图形比如圆形和矩形。我们通过接口和抽象类来实现开闭原则   首先定义一个抽象的图形接口 Shape并且定义一个抽象方法 draw public interface Shape {void draw(); }然后创建实现这一接口的具体图形类比如 Circle 和 Rectangle public class Circle implements Shape {Overridepublic void draw() {System.out.println(绘制圆形);} }public class Rectangle implements Shape {Overridepublic void draw() {System.out.println(绘制矩形);} }接下来我们定义一个图形绘制器 ShapeDrawer它接收一个 Shape 对象并能够绘制不同的图形 public class ShapeDrawer {public void drawShape(Shape shape) {shape.draw();} }现在如果需要添加新的图形比如三角形我们只需创建一个新的实现 Shape 接口的类并实现 draw 方法而无需修改已有的代码。这样系统保持了对修改关闭的同时对扩展开放符合开闭原则。通过遵循开闭原则我们可以更容易地扩展系统的功能同时保持较低的修改成本和风险。 4.3 里氏代替原则LSP 定义 里氏代换原则Liskov Substitution Principle是面向对象设计中的重要原则之一由计算机科学家Barbara Liskov提出。     该原则是对继承和子类型化的一个准则它阐述了子类型派生类或子类应当能够替换其基类型父类或超类而不影响程序的正确性。换句话说只要程序中使用基类的地方都应当能够用其子类来替换而不产生任何错误或异常行为。 优点 提高代码的可复用性遵循LSP原则可以使得基类和子类之间的关系更加清晰和稳定使得代码更容易被复用。 降低系统的耦合度通过LSP原则子类可以替换父类而不影响系统的行为从而减少了模块间的耦合使得各个模块可以更加独立地开发、测试和维护。 便于功能的扩展和修改当需要引入新的子类时遵循LSP原则可以更容易地进行系统扩展不需要对已有的代码做出修改降低了引入新功能时的风险。 增强程序的健壮性和可靠性符合LSP原则的代码能够更好地避免因为子类替换父类导致的意外错误提高了软件的健壮性和可靠性。 促进代码的可理解性和可维护性遵循LSP原则可以使得代码结构更加清晰和易于理解也更容易进行维护和重构从而降低了代码的复杂性。     遵循里氏代换原则可以帮助我们设计出更加稳定、可靠、可维护和可扩展的软件系统使得软件设计更加符合面向对象设计的原则和思想。 缺点和挑战 增加设计和开发的复杂性严格的LSP要求子类能完全替换父类这对继承结构和接口设计提出更高的要求可能会增加设计和开发的复杂性。 可能会产生过度设计为了满足LSP可能需要对类设计进行过度的抽象和泛化导致出现过于复杂和冗余的设计甚至在某些情况下会降低代码的可读性和可维护性。 可能会限制一些特定的优化和实现方式有时为了满足LSP可能会限制一些特定的优化和实现方式导致性能上的一些损失。 可能会引发“类爆炸”问题为了满足LSP原则可能会产生大量微小的子类导致继承体系变得过于庞大和复杂。 可能会增加系统的耦合度虽然LSP有助于降低模块间的耦合度但过于严格地依赖LSP也可能使得类与类之间的依赖关系过于紧密导致了一定程度的耦合。     虽然里氏代替原则有利于提高系统的设计质量和稳定性但在实际应用中需要权衡好遵循LSP原则和系统的复杂度、灵活性等因素不应盲目追求LSP而导致过度设计或者对系统性能造成不必要的影响。 4.3.1 如何做到里氏代替原则 采用以下设计方法 子类可以扩展父类的功能但不应该改变父类原有的功能确保子类可以完全替代父类在所有的地方。子类应该在不改变父类原有行为的基础上提供特定的功能扩展。 子类可以增加自己特有的方法子类可以拥有自己的特有方法但不能重写父类的非抽象方法。 子类的方法重载父类的方法时方法的入参类型、出参类型和异常类型需要保持一致或者更宽松。尽量不要重写父类的方法而是通过子类扩展的方式来实现新的功能。父类的抽象方法可以让子类有多样性的实现但子类不应该覆盖父类的非抽象方法。     通过遵循上述原则可以确保子类能够无缝地替代父类并且在保持系统稳定性的基础上实现功能的扩展。 4.3.2 与其它设计模式的关系 与里氏代替原则密切相关设计模式 模板方法模式Template Method Pattern模板方法模式通过定义一个算法的骨架将具体步骤的实现延迟到子类中。里氏代替原则可以确保子类在实现具体步骤时不会改变骨架的逻辑从而实现算法的复用和扩展。 工厂方法模式Factory Method Pattern工厂方法模式通过将对象的创建延迟到子类以便子类可以决定实例化哪个具体类。里氏代替原则可以确保子类创建的对象能够替代父类对象保持系统的灵活性和可扩展性。 策略模式Strategy Pattern策略模式定义了一系列算法将每个算法封装起来并使它们可以相互替换。里氏代替原则可以确保新的算法能够替代现有的算法而不会影响系统的其他部分。 装饰者模式Decorator Pattern装饰者模式通过动态地给一个对象添加一些额外的职责来扩展该对象的功能。里氏代替原则可以确保装饰者子类可以替代被装饰的对象以便实现透明地扩展对象的功能。     总的来说里氏代替原则与设计模式密切相关可以确保子类与父类之间的替代关系从而帮助设计出灵活而稳定的面向对象系统。 4.3.3 示例 实现里氏代替原则需要遵循以下几点 子类必须保证可以替换父类并且不影响原有功能。子类可以扩展父类的功能但不能修改父类已有的功能。父类中的抽象方法由子类去实现但实现过程中不应该改变父类行为的基本逻辑。     假设有一个图形类 Shape包括获取面积的方法 area()然后有一个矩形类 Rectangle 继承自 Shape 类。我们来看看如何保证里氏代替原则 // 定义图形类 public class Shape {public double area() {return 0.0;} }// 定义矩形类 public class Rectangle extends Shape {private double width;private double height;public Rectangle(double width, double height) {this.width width;this.height height;}Overridepublic double area() {return width * height;} }     在这个示例中Rectangle 类继承自 Shape 类并且重写了父类的 area() 方法但并没有改变原有的功能而是在原有的基础上进行了扩展。     另外可以结合接口来实现里氏代替原则确保子类可以完全替代父类在所有的场景中。在软件设计中继承并不是唯一的实现里氏代替原则的方式还可以通过组合、接口实现等方式来达到同样的效果。 4.4 依赖倒转原则DIP 定义 依赖倒转原则Dependency Inversion Principle简称DIP是面向对象设计的一条重要原则之一它强调高层模块不应该依赖于低层模块而是应该依赖于抽象。同时抽象不应该依赖于具体细节而是具体细节应该依赖于抽象。              换句话说依赖倒转原则主张要通过抽象来解耦程序的各个部分高层模块和低层模块都应该依赖于抽象的接口或者抽象类而不是依赖于具体的实现。这样可以提高系统的灵活性、可扩展性和可维护性。 优点 降低耦合性依赖倒转原则可以减少高层模块对低层模块的依赖。高层模块只需要依赖于抽象接口而不需要依赖于具体实现类从而降低了模块之间的耦合性。 提高可扩展性通过依赖倒转原则系统的各个模块都依赖于抽象接口当需要新增或者修改功能时通过添加新的实现类或者修改现有的实现类而不需要修改高层模块的代码从而提高了系统的可扩展性。 增加灵活性依赖倒转原则可以使得系统更加灵活可以方便地切换不同的具体实现类满足不同的业务需求而不需要修改高层模块的代码。 提高可维护性通过依赖倒转原则将模块之间的依赖关系解耦使系统的各个模块独立变化当一个模块需要修改时不会对其他模块造成影响从而提高了系统的可维护性。 促进代码重用依赖倒转原则通过抽象接口进行编程可以使得模块的功能更加独立和可重用。不同的模块可以共享同一个抽象接口从而实现代码的重用。     依赖倒转原则可以提高系统的灵活性、可扩展性、可维护性降低模块之间的耦合度从而提高整个系统的质量和可靠性。它是面向对象设计中非常重要的原则之一。 缺点和挑战 复杂性增加引入依赖倒转原则需要引入抽象接口和依赖注入等机制这可能会使得代码结构变得更加复杂增加了开发和维护的难度。 学习成本增加对于团队中没有经验的开发人员来说理解和应用依赖倒转原则可能需要较长的学习周期增加了学习成本和上手难度。 过度设计有时为了满足依赖倒转原则可能会过度设计接口和抽象类导致系统结构变得过于复杂甚至出现“设计模式过度使用”的问题。 性能开销依赖注入等方式会带来额外的性能开销尤其是在一些性能要求较高的场景下可能需要权衡性能和设计规范之间的关系。 增加代码量引入抽象接口和依赖注入可能会增加代码量使得代码变得更加冗长增加了阅读和维护的复杂度。     虽然存在这些缺点但在大多数情况下依赖倒转原则的优点仍然能够为软件系统带来更多的长期利益。在实际应用中需要根据具体情况和需求权衡利弊合理应用依赖倒转原则避免过度设计和过度使用。 4.4.1 如何做到依赖倒转原则 识别依赖关系首先要明确识别出模块之间的依赖关系确定哪些模块是高层模块哪些模块是低层模块。 创建抽象接口将高层模块所需的功能抽象成接口或者抽象类。这个接口应该是相对稳定、通用的而且要符合单一职责原则。 低层模块实现接口低层模块需要实现高层模块所定义的抽象接口。这样高层模块就可以通过接口来使用低层模块而不直接依赖于具体的实现类。 高层模块依赖注入在高层模块中通过依赖注入Dependency Injection将具体的实现类注入进来而不是直接实例化具体的实现类。这样可以动态地切换具体实现类提高系统的灵活性。 使用依赖注入容器可选可以使用依赖注入容器来管理对象的创建和依赖注入。依赖注入容器可以帮助自动实现依赖注入减少手动配置的工作。 遵循开闭原则依赖倒转原则和开闭原则Open-Closed Principle相辅相成。要严格遵循开闭原则即模块应该对扩展开放对修改关闭。当需要新增功能时应该通过添加新的实现类来扩展而不是修改原有代码。     通过以上步骤可以实现依赖倒转原则将模块之间的依赖关系解耦提高系统的灵活性、可扩展性和可维护性。同时在应用过程中也要根据具体情况合理应用和调整依赖倒转的策略以满足项目需求。 4.4.2 与其它设计模式的关系 工厂模式Factory Pattern工厂模式可以用来实现依赖倒转原则。通过工厂模式高层模块可以依赖于抽象的工厂接口由工厂负责创建具体的实例从而将高层模块与具体实现类解耦。 策略模式Strategy Pattern策略模式可以帮助实现依赖倒转原则。通过定义一组策略接口并将不同的策略实现注入到高层模块中高层模块可以根据需要动态切换不同的策略实现实现了高层模块与具体策略的解耦。 观察者模式Observer Pattern观察者模式也与依赖倒转原则有关。通过定义抽象的观察者接口和被观察者接口高层模块可以依赖于抽象接口具体的观察者可以通过实现观察者接口注入到被观察者中实现了高层模块与具体实现类的解耦。     除了以上几种设计模式还有其他一些设计模式也与依赖倒转原则相关如策略工厂模式、代理模式等。这些设计模式都有助于实现依赖倒转原则提高系统的灵活性和可维护性并支持解耦模块之间的依赖关系。 4.4.3 示例 下面使用构造函数注入来实现依赖倒转原则。   假设有以下接口和实现类 // 服务接口 public interface Service {void execute(); }// 具体服务实现类 public class ConcreteService implements Service {Overridepublic void execute() {System.out.println(Executing ConcreteService);} }// 高层模块 public class HighLevelModule {private final Service service;// 通过构造函数注入public HighLevelModule(Service service) {this.service service;}public void doWork() {// 使用注入的服务service.execute();} } 在这个示例中通过构造函数注入的方式将具体的服务实现类注入到高层模块中实现了高层模块对具体实现类的解耦。 然后可以在应用的入口处进行依赖的注入和组装 public class Application {public static void main(String[] args) {// 创建具体的服务实现类对象Service concreteService new ConcreteService();// 将具体的服务实现类注入到高层模块中HighLevelModule highLevelModule new HighLevelModule(concreteService);// 执行高层模块的业务逻辑highLevelModule.doWork();} }     通过这种方式高层模块依赖于抽象的服务接口具体的服务实现类通过构造函数注入的方式被注入到高层模块中。这样就实现了依赖倒转原则高层模块不依赖于具体实现类而是依赖于抽象接口从而提高了系统的灵活性和可扩展性。     以上示例演示了如何在 Java 中通过构造函数注入的方式实现依赖倒转原则。当然实际应用中也可以使用其他依赖注入的方式如方法注入、属性注入或者利用依赖注入容器如Spring Framework来管理对象的创建和依赖注入。 4.5 接口隔离原则ISP 定义 接口隔离原则Interface Segregation Principle简称ISP是面向对象设计中的一条重要原则由罗伯特·C·马丁在他的著作《敏捷软件开发原则、模式与实践》中提出。              该原则指导我们设计接口时应该将庞大臃肿的接口拆分成更小、更具体的接口以便客户端只需要依赖于其需要使用的接口而不用依赖于多余的接口。 优点 降低耦合性遵循接口隔离原则可以将庞大的接口拆分成更小、更具体的接口从而降低类与接口之间的耦合度。客户端只需要依赖于自身需要使用的接口而不用依赖于不必要的接口降低了类之间的依赖关系提高了系统的灵活性和可维护性。 促进代码重用当接口被精心设计并分离出单一的职责时可以更容易地被其他模块或服务所重用这有利于系统的拓展和维护。 便于测试和调试拆分成小而专一的接口意味着更小的单元测试范围和更清晰的功能定义方便进行测试和调试提高了软件质量。 降低修改的风险精简的接口代表更小的变更范围若需要对某个功能进行修改只需关注受影响的接口而不会牵扯到其他无关的接口降低了修改代码带来的风险。 符合单一职责原则ISP 的遵循有利于类拥有单一的职责一个类只需要实现与其业务逻辑相关的接口不需要实现不相关的接口符合单一职责原则。     遵循接口隔离原则有助于提高系统的灵活性、可维护性和扩展性降低代码的复杂度和耦合性并促进系统的健壮性和可测试性。 缺点和挑战 接口的细粒度可能过分分散遵循接口隔离原则会导致接口的细粒度变得更小可能会造成接口数量的增加。如果接口过于细分可能会增加代码的复杂度和理解难度增加维护成本。 引入更多的抽象层次拆分接口可能需要引入更多的抽象层次这会导致代码结构的复杂化。过多的抽象可能增加了学习成本和理解难度尤其是对于新加入的团队成员。 实现类的数量可能增加拆分接口意味着某个功能可能需要由多个实现类来分别实现这会增加实现类的数量。如果实现类过多可能会增加代码的复杂性和系统的维护成本。 需要更多的接口管理和协调拆分接口后需要更多的接口管理和协调工作包括接口的版本管理、兼容性调整等这可能会增加项目的开发和维护工作量。     尽管遵循接口隔离原则可能会带来上述的一些缺点但在大多数情况下其优点远远超过了缺点。需要权衡考虑业务需求、系统的复杂性和团队的实际情况以找到合适的划分接口的方法。另外合理的代码结构和良好的设计规范也可以帮助解决和缓解接口隔离原则可能带来的一些缺点。 4.5.1 如何做到接口隔离原则 分析需求和功能首先仔细分析系统的需求和功能了解各个模块或类的职责和功能明确它们之间的关系和依赖。 拆分庞大接口根据需求和功能分析的结果将庞大的接口拆分为更小、更具体的接口每个接口只包含与其职责相关的方法。避免把不相关的功能强制放在一个接口中。 接口要小而精不要臃肿接口应该是精简的不应该包含太多的方法。一个接口应该满足一个单一职责不将过多的职责塞入一个接口中。 精心设计接口设计拆分后的接口时应该关注接口的单一职责确保每个接口都只包含一组高内聚的方法。接口命名要具有清晰和准确的表达力。 避免接口的冗余和重复仔细审查已有的接口避免接口之间的重复和冗余。确保每个接口只包含必要的方法避免无效的方法声明。 使用抽象类和接口继承根据接口隔离原则可以使用抽象类和接口继承来帮助实现合理的接口设计。抽象类和接口的使用可以对相似的接口进行抽象和分类以提高代码的复用性和灵活性。 评估接口设计的灵活性和可扩展性在设计接口时要考虑系统的灵活性和可扩展性预留必要的扩展点避免频繁修改接口导致的影响范围扩大。 测试和验证接口设计在设计完接口后进行充分的测试和验证确保接口设计与实际需求一致并符合接口隔离原则。 客户端不应该被迫依赖于它不使用的接口一个类对另外一个类的依赖应该建立在最小的接口上这样就降低了客户端与之耦合的可能性。 接口设计优于继承ISP原则也暗示了接口设计要优于继承因为接口设计更加灵活能够更好地满足不同类的实际需求。     通过遵循接口隔离原则可以使接口设计更加灵活和可维护降低类之间的耦合性提高系统的可扩展性和可维护性从而更好地满足软件设计的开闭原则和单一职责原则。 4.5.2 与其它设计模式的关系 适配器模式Adapter Pattern适配器模式可以帮助遵循ISP因为它允许客户端通过特定接口与适配器进行交互而无需了解适配器是如何与其他类进行交互的。 桥接模式Bridge Pattern桥接模式将抽象部分与它的实现部分分离这符合ISP的理念可以帮助避免庞大接口的出现同时有助于避免不相关的接口方法导致耦合性的增加。 观察者模式Observer Pattern观察者模式允许主题对象与观察者对象之间的松耦合联系观察者只需要实现一个接口这符合ISP的原则每个观察者只需要关注自己感兴趣的事件。 策略模式Strategy Pattern策略模式定义了一系列算法将每个算法封装到具有共同接口的独立类中。这有利于遵循ISP因为它可以确保每个算法只关注自己的功能比如一个计算税金的算法不需要关心其他算法。     这些设计模式可以帮助支持接口隔离原则的实施并在实际编程中有助于解决ISP所涉及的设计挑战。结合这些设计模式可以更好地设计出遵循ISP的接口并确保系统具有良好的灵活性、可维护性和扩展性。 4.5.3 示例 实现接口隔离原则ISP涉及以下几个方面 定义接口根据ISP的原则需要定义符合单一职责的接口。在Java中可以使用interface关键字来定义接口例如 public interface Animal {void eat(); }public interface Flyable {void fly(); }实现接口根据实际需求创建实现接口的类。每个类只需实现与自己相关的接口方法而不需要实现不相关的方法。例如 public class Bird implements Animal, Flyable {Overridepublic void eat() {System.out.println(Bird is eating);}Overridepublic void fly() {System.out.println(Bird is flying);} }public class Dog implements Animal {Overridepublic void eat() {System.out.println(Dog is eating);} }使用接口在使用对象时尽可能使用接口类型引用对象而不是具体类的引用。这样做可以降低代码的耦合度增加灵活性。例如 public class Main {public static void main(String[] args) {Animal bird new Bird();bird.eat();if (bird instanceof Flyable) {((Flyable) bird).fly();}Animal dog new Dog();dog.eat();} }通过以上方式在Java中可以实现接口隔离原则确保接口的单一职责和高内聚性。这样的设计使得系统更具灵活性和可维护性能够更好地应对变化和扩展。 4.6 合成/聚合复用原则CARP 定义 合成/聚合复用原则Composite/Aggregate Reuse PrincipleCARP也被称为合成/聚合原则它是面向对象设计中的一个重要原则强调应该尽量使用合成/聚合关系Composition/Aggregation而不是继承来实现代码的复用。              CARP 的主要思想是更倾向于通过将对象组合成更大的对象来达到复用的目的而不是依赖于继承的层次结构。通过合成/聚合关系一个对象可以包含其他对象作为其组成部分或成员而不是通过继承来继承其行为。 优点 灵活性使用合成/聚合关系可以更灵活地组合和替换对象因为对象之间的耦合度更低。这使得系统更容易应对变化和扩展更具灵活性。 可维护性合成/聚合关系使得代码更具模块化易于理解和维护。每个独立的对象都只负责自己的职责使得在对系统进行修改和维护时更加容易。 松耦合由于不依赖于继承组成对象之间的耦合度更低。这意味着各个对象可以更独立地进行开发、测试和维护而不会因为一个对象的改动而影响其他对象。 复用性通过合成/聚合关系可以更灵活地复用对象因为对象的组合可以根据需求进行调整而不会受到继承层次结构的限制。 降低继承的缺点继承层次结构会引入一些固有的问题如“脆弱基类”问题等。合成/聚合复用原则通过减少对继承的依赖有助于避免这些问题的产生。     合成/聚合复用原则有利于增加系统的灵活性、可维护性和复用性帮助设计出模块化、低耦合度的系统。这些优点使得合成/聚合复用原则成为面向对象设计中的重要原则之一。 缺点和挑战 增加设计复杂性使用合成/聚合关系可能会增加设计的复杂性。在组合对象时需要考虑对象之间的关系和交互这可能需要更多的代码和设计。 增加代码量使用合成/聚合关系可能会增加代码量。相比于简单的继承关系合成/聚合关系需要创建和维护更多的对象并且涉及更多的交互和调用。 引入间接性使用合成/聚合关系引入了更多的间接性。当一个对象使用其他对象的方法时需要通过组合对象进行间接调用可能导致额外的开销和复杂性。 难以确定组成对象的生命周期合成/聚合关系下对象的生命周期管理变得更复杂。如果一个对象包含其他对象作为组成部分需要确保正确处理其生命周期避免可能出现的对象泄露或内存泄漏问题。 可能降低性能使用合成/聚合关系可能会导致一定的性能损失。相比于直接继承对象之间的交互和间接调用可能会引入额外的开销导致性能下降。     尽管存在这些缺点但在面对应对变化、增强灵活性和可维护性的需求时合成/聚合复用原则仍然是一种有价值的设计原则。它可以帮助设计出更模块化、可复用和易于维护的系统。在实际应用中需要根据具体情况权衡使用合成/聚合关系的利弊找到合适的设计方案。 4.6.1 如何做到合成/聚合复用原则 Identify对象的组成关系首先需要识别出对象之间的组成关系。确定哪些对象是整体对象的组成部分以及它们之间的关系是合成强关联还是聚合弱关联关系。 封装对象的组成关系使用合成/聚合关系时需要将对象之间的关系封装起来。这意味着在整体对象中包含成员对象并且对外部提供统一的访问接口隐藏内部组成结构的具体细节。 注重对象间的交互在设计时需要思考对象之间的交互方式。合成/聚合关系下整体对象与其部分对象之间可能会有交互和协作需要合理设计对象之间的消息传递和调用方式。 管理对象的生命周期特别要注意管理组成对象的生命周期确保整体对象的创建和销毁不会导致组成对象的不当操作或泄漏。合成对象通常应该负责管理其组成对象的生命周期。 强调接口而非实现在整体对象与其部分对象之间的交互时应该强调接口而不是具体的实现。通过定义清晰的接口可以降低对象之间的耦合度增强灵活性。 灵活地调整组成关系合成/聚合关系下对象之间的组成关系应该是灵活可调的。需要设计出可以轻松替换、增加或移除组成部分对象的结构。 避免过度设计在应用合成/聚合复用原则时需要避免过度设计。根据实际需求和场景来灵活运用合成/聚合关系避免引入不必要的复杂性。     通过遵循以上指导原则可以帮助设计出符合合成/聚合复用原则的对象组成结构从而实现代码的高复用性、可维护性和灵活性。 4.6.2 与其它设计模式的关系 组合模式Composite Pattern组合模式使用合成/聚合复用原则通过将对象组织成树形结构来表示部分-整体关系。这种关系允许客户端统一处理单个对象和对象组合从而实现了透明地处理对象的组合。 桥接模式Bridge Pattern桥接模式也使用了合成/聚合复用原则通过将抽象部分与其实现部分分离使它们可以独立地变化。这样的设计遵循了合成/聚合复用原则的思想通过组合关系将抽象部分和实现部分进行解耦。 装饰者模式Decorator Pattern装饰者模式利用合成/聚合复用原则以动态、透明的方式给单个对象添加功能。通过将对象进行包装和组合装饰者模式可以灵活地扩展对象的功能同时保持对象的接口不变。 策略模式Strategy Pattern策略模式利用合成/聚合复用原则定义一系列算法家族分别封装起来并使它们可以互相替换。这样的设计使得算法的变化独立于使用算法的客户符合合成/聚合复用原则的灵活组合和替换特性。 适配器模式Adapter Pattern适配器模式使用合成/聚合复用原则通过组合关系将不兼容的接口转换为可兼容的接口。这样的设计保持了两个接口的独立性遵循了合成/聚合复用原则的思想。     这些设计模式与合成/聚合复用原则紧密相关都是为了提高代码的灵活性、可维护性和可复用性而设计的。通过结合设计模式和合成/聚合复用原则可以更好地应对软件开发中的变化和需求帮助构建出更加模块化、低耦合度的系统。 4.6.3 示例 实现合成/聚合复用原则可以通过以下方式进行 组合关系的实现 在 Java 中实现合成/聚合复用原则的一种简单方式就是通过组合关系来包含其他对象。这通常涉及将一个类的实例作为另一个类的成员变量。例如 public class Engine {// 引擎的相关属性和方法 }public class Car {private Engine engine;public Car() {this.engine new Engine(); // 组合关系} }在这个例子中Car 类包含一个 Engine 对象作为其成员实现了组合关系。 构造函数注入实现聚合关系 通过在类的构造函数中接受其他对象作为参数实现聚合关系让外部对象可以注入一个对象到另一个对象中。例如 public class Car {private Engine engine;public Car(Engine engine) {this.engine engine; // 聚合关系} }接口的应用 使用接口定义对象之间的交互而不是依赖于具体的实现类可以帮助降低对象之间的耦合度。例如 public interface Engine {void start();void stop(); }public class GasEngine implements Engine {// GasEngine 的实现 }public class ElectricEngine implements Engine {// ElectricEngine 的实现 }public class Car {private Engine engine;public Car(Engine engine) {this.engine engine; // 聚合关系}public void startEngine() {engine.start(); // 通过接口进行交互} }通过上述方式可以在 Java 中实现合成/聚合复用原则提高代码的灵活性和可维护性。这些技术可以帮助将对象组织成更灵活、可复用的结构符合软件设计的良好实践。 4.7 迪米特法则LoD 定义 迪米特法则Law of DemeterLoD又称最少知识原则Principle of Least Knowledge是面向对象设计中的一个重要原则。迪米特法则指导着如何降低系统中各对象之间的耦合度以提高代码的灵活性、可维护性和复用性。              迪米特法则的核心思想可以总结为一个对象应该对其他对象有尽可能少的了解即一个对象应该对其它对象尽可能少的暴露接口。 优点 降低耦合度迪米特法则通过限制对象之间的交互降低了对象之间的直接依赖关系。这样可以减少对象间的耦合使得系统的各个模块之间更加独立修改一个模块不会对其他模块产生太大的影响。 增强模块的独立性迪米特法则使得对象只需与直接朋友进行通信对象不需要了解它们之间的详细实现从而提高了模块的独立性。当一个模块变化时只需关注与之直接交流的模块而不需要关注其他模块的变化降低了系统的复杂度。 提高代码的可维护性迪米特法则提倡减少对象之间的依赖降低了对象之间的关联从而使得代码更加清晰和简洁。当系统需要进行维护时定位问题和修改代码将会更加容易。 促进代码的复用性通过减少对象之间的耦合迪米特法则可以提高代码的复用性。当某个对象需要替换或者重用时由于对象之间关联的减少它的影响范围会更小因此代码的复用性也会更高。 提升系统的扩展性迪米特法则降低了模块之间的依赖关系使得系统更加灵活和可扩展。当需要增加新的功能或模块时迪米特法则使得代码的修改范围变小减少了对原有代码的影响提高了系统的扩展性。     迪米特法则通过限制对象之间的耦合度增强模块的独立性提高代码的可维护性和复用性同时促进系统的扩展性。这些优点使得应用迪米特法则的代码更加灵活、可维护和可扩展有助于构建高质量的软件系统。 缺点和挑战 可能导致过多的中间类严格遵循迪米特法则可能导致需要引入大量的中间类来传递消息使得系统中存在过多的简单委托方法。这可能增加类的数量使得系统变得复杂同时也增加了维护成本。 可能引入不必要的间接性迪米特法则要求对象对于所调用的对象的朋友只能进行有限的了解这可能导致需要引入一层层的间接方法调用从而引入不必要的间接性。这样导致了代码的冗余和复杂性可能影响系统的性能。 可能增加代码组织的难度严格遵循迪米特法则可能会导致需要更多的类和接口使得代码组织和管理变得更加困难。特别是在大型项目中过多的中间类和接口可能增加了项目的复杂度使得代码的理解和维护变得更加困难。 可能导致过度设计迪米特法则的严格遵循可能导致过度设计的问题过分将注意力放在降低对象之间的直接交流上而忽视了系统的实际需求和功能。这可能会增加开发和维护的成本同时也使得系统的设计变得过于复杂。 可能牺牲了效率严格遵循迪米特法则可能会导致需要增加额外的方法调用和对象之间的交互从而牺牲了一定的效率。特别是在对性能要求较高的系统中过度遵循迪米特法则可能会带来一定的性能损失。     虽然迪米特法则有一些潜在的缺点但在实际应用中需要根据具体的业务需求和系统情况来权衡避免盲目地追求原则而导致过度设计或者牺牲效率和可理解性。合理地应用迪米特法则有助于降低系统的耦合度提高代码的灵活性和可维护性。 4.7.1 如何做到迪米特法则 封装对象的内部细节对象应该尽量隐藏其内部的实现细节只暴露必要的公共方法。通过封装可以减少对象之间的直接依赖关系降低耦合度。 限制对象间的交互对象之间的交互应该通过少量的“朋友”来进行对象只与自身直接关联的对象通信。不直接与陌生对象进行交互避免链式调用。 使用中介者或者外观模式中介者模式或者外观模式可以作为对象之间通信的桥梁在中介者或外观对象的中部分隔对象之间的直接联系降低耦合度。 遵循依赖倒置原则依赖倒置原则要求针对抽象进行编程而不是针对具体实现。通过面向接口编程可以减少对具体类的依赖降低耦合度。 合理划分模块和责任合理划分模块和责任尽量使得每个模块独立、高内聚低耦合。每个模块只负责自己的业务逻辑实现并尽量减少模块之间的直接交互。 避免暴露不必要的信息对于对象的方法参数和返回值应该尽量只传递和返回必要的信息避免暴露对象的内部状态和实现细节。 注意设计和代码的简洁性在遵循迪米特法则的前提下尽量保持设计和代码的简洁性。避免过度设计关注系统的功能和实际需求。     遵循迪米特法则需要注意对象之间的交互、信息封装和模块划分等方面。合理应用迪米特法则可以降低系统的耦合度提高代码的可维护性、复用性和扩展性。 4.7.2 与其它设计模式的关系 中介者模式Mediator Pattern中介者模式通过引入一个中介者对象将对象之间的复杂交互转移到中介者对象中进行管理。中介者模式符合迪米特法则的原则将对象之间的依赖关系限制在中介者对象上降低了对象之间的耦合度。 观察者模式Observer Pattern观察者模式是一种对象间的一对多依赖关系当被观察对象状态发生改变时会自动通知依赖于它的观察者对象。观察者模式符合迪米特法则的原则被观察对象只需要与观察者对象进行通信而不需要了解观察者对象的具体实现。 外观模式Facade Pattern外观模式提供了一个统一的接口将子系统的复杂性进行封装使得客户端只需要与外观对象进行交互。外观模式符合迪米特法则的原则将客户端与子系统的耦合度降低客户端只需与外观对象进行通信。 适配器模式Adapter Pattern适配器模式将一个类的接口转换成客户端所期望的接口使得原本不兼容的类能够协同工作。适配器模式符合迪米特法则的原则适配器作为两个不相关的对象之间的中间类限制了对象之间的直接交互。     这些设计模式在实现过程中都注重降低对象之间的耦合度符合迪米特法则的原则。它们通过引入中间对象、定义统一接口、限制对象之间的交互等方式实现了系统的解耦和模块的独立性提高了系统的灵活性、可维护性和扩展性。 4.7.3 示例 迪米特法则要求一个对象应该对其他对象有尽可能少的了解也就是说一个对象不应直接调用其他对象的内部方法而应通过以下方式来实现 只与直接的朋友通信一个对象的直接朋友包括成员变量、方法参数、方法返回值等。根据迪米特法则一个对象应当只与其直接的朋友通信不应该与间接朋友朋友的朋友通信。 尽量不在方法内部调用其他对象的方法一个对象的方法中不应该直接调用其他对象的方法而是应当通过参数、返回值等间接途径。   实现迪米特法则的简单示例: // 课程类 class Course {private String name;public Course(String name) {this.name name;}public String getName() {return name;} }// 学生类 class Student {private String name;private Course course;public Student(String name, Course course) {this.name name;this.course course;}public String getName() {return name;}// 课程信息通过方法参数传递public void studyCourse(Course course) {System.out.println(name is studying course.getName());} }// 学校类 class School {private String name;public School(String name) {this.name name;}// 学生信息通过方法参数传递public void registerCourse(Student student, Course course) {System.out.println(student.getName() registered at name for course.getName());// 学校不直接调用课程的方法} }public class Main {public static void main(String[] args) {Course math new Course(Math);Student student new Student(Alice, math);School school new School(ABC School);school.registerCourse(student, math);} }     上面的示例中通过将课程信息通过方法参数传递的方式实现了迪米特法则。学生对象不直接调用课程对象的方法而是通过参数传递的方式与间接的朋友通信。这样设计遵循了迪米特法则减少了对象之间的耦合提高了代码的灵活性和可维护性。
http://www.w-s-a.com/news/992478/

相关文章:

  • 医院网站建设的目标wordpress中英文网站模板
  • 门户型网站开发难度网站导航栏有哪些
  • 推荐做任务网站软件定制开发哪家好
  • 邯郸兄弟建站第三方仓储配送公司
  • 商丘家具网站建设wordpress 添加代码
  • 基础建设的网站有哪些内容成都科技网站建设咨询电话
  • 券多多是谁做的网站招聘网站开发模板
  • 网站主机一般选哪种的企业数字展厅
  • 网站建设该如何学衡水建设局网站首页
  • 高校网站建设工作总结番禺网站开发哪家好
  • 苏州 网站的公司wordpress主页代码
  • 怎么用html做图片展示网站外贸网站建设推广费用
  • 可以做本地生活服务的有哪些网站中油七建公司官网
  • 如何建设谷歌网站网站建设优点
  • 做网站的目标是什么产品宣传片制作公司
  • 柳州建设公司网站辽宁建设工程信息网评标专家入库
  • 合肥建设学校官方网站excel导入wordpress
  • 禹城网站设计做网站需要考虑哪些
  • 深圳做营销网站建设wordpress添加文章封面
  • 阿里云的网站建设方案织梦和wordpress哪个安全
  • 聊城网站建设公司电话wordpress怎么重新配置文件
  • 创业如何进行网站建设泰州公司注册
  • 免费网站建设培训学校手机百度高级搜索入口在哪里
  • 建站经验安徽六安发现一例新冠阳性检测者
  • 滨州内做网站系统的公司汕头网络营销公司
  • 苏州制作网站的公司哪家好wordpress google搜索
  • c语言做项目网站wordpress博客被书为什么还
  • 企业建站用什么系统网站建设补充协议模板
  • 常州网站关键字优化淘客网站怎么做排名
  • 全flash网站制作教程网站做进一步优化