zoukankan      html  css  js  c++  java
  • java面向对象设计的原则

    一、针对java类的6大设计原则

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

    即:对一个类而言,有且仅有一个引起它变化的原因。否则的话就应该把这个类进行拆分。在设计时让一个类只负责一种类型的责任。
    单一职责原则的核心就是控制类的粒度大小、将对象解耦、提高内聚性。如果遵循单一职责原则将有以下优点:

    • 降低类的复杂度。一个类只负责一项职责,其逻辑肯定要比负责多项职责简单得多。
    • 提高类的可读性。复杂性降低,其可读性自然会提高。
    • 提高系统的可维护性。可读性提高了,那自然更容易维护了。
    • 变更引起的风险降低。变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。

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

    软件实体(类、模块、函数等)应该是可以扩展的,即开放的;但是是不可修改的,即封闭的。也就是当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展该模块的功能,使其满足新的需求。
    开闭原则是面向对象程序设计的终极目标,它使软件实体拥有一定的适应性和灵活性的同时具备稳定性和延续性。
    具体来说,其作用如下:

    • 对软件测试的影响:软件遵守开闭原则的话,软件测试时只需要对扩展的代码进行测试就可以了,因为原有的测试代码仍然能够正常运行。
    • 可以提高代码的可复用性:粒度越小,被复用的可能性就越大;在面向对象的程序设计中,根据原子和抽象编程可以提高代码的可复用性。
    • 可以提高软件的可维护性:遵守开闭原则的软件,其稳定性高和延续性强,从而易于扩展和维护。

    3.里氏替换原则(Liskov Substitution Principle,LSP)

    子类型必须能够替换掉他们的基类型。即,在任何父类可以出现的地方,都可以用子类的实例来赋值给父类型的引用。当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有是一个(is-a)关系。
    例如:车是超类,轿车是子类,那么可以将轿车的实例赋值给车的实例,即 车 che=轿车();即满足is-a的关系,即轿车是一个车,轿车是车。车的性质,轿车都具备。
    继承必须确保超类所拥有的性质在子类中仍然成立。
    里氏替换原则主要阐述了有关继承的一些原则,也就是什么时候应该使用继承,什么时候不应该使用继承,以及其中蕴含的原理。里氏替换原则是继承复用的基础,它反映了基类与子类之间的关系,是对开闭原则的补充,是对实现抽象化的具体步骤的规范。
    里氏替换原则通俗来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。也就是说:子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。如果通过重写父类的方法来完成新的功能,这样写起来虽然简单,但是整个继承体系的可复用性会比较差,特别是运用多态比较频繁时,程序运行出错的概率会非常大。如果程序违背了里氏替换原则,则继承类的对象在基类出现的地方会出现运行错误。这时其修正方法是:取消原来的继承关系,重新设计它们之间的关系。

    4.依赖倒置原则(Dependence Inversion Principle,DIP)

    抽象不应该依赖于细节,而细节应该依赖于抽象。即高层模块不应该依赖于底层模块,二者都应该依赖于抽象。其核心思想是:要面向接口编程,不要面向实现编程。
    依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。
    其作用如下:

    • 依赖倒置原则可以降低类间的耦合性。
    • 依赖倒置原则可以提高系统的稳定性。
    • 依赖倒置原则可以减少并行开发引起的风险。
    • 依赖倒置原则可以提高代码的可读性和可维护性。
      依赖倒置原则的目的是通过要面向接口的编程来降低类间的耦合性,所以我们在实际编程中只要遵循以下4点,就能在项目中满足这个规则:
    • 每个类尽量提供接口或抽象类,或者两者都具备。
    • 变量的声明类型尽量是接口或者是抽象类。
    • 任何类都不应该从具体类派生。
    • 使用继承时尽量遵循里氏替换原则。

    5.接口分离原则(Interface Segregation Principle,ISP)

    不应该强迫客户依赖于他们不用的方法。接口属于客户,不属于它所在的类层次结构。即:依赖于抽象而不依赖于具体,同时在抽象级别不应该有对于细节的依赖。也就是要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。这样做的好处就在于可以最大限度的应对可能的变化。
    接口隔离原则是为了约束接口、降低类对接口的依赖性,遵循接口隔离原则有以下5个优点:

    • 将臃肿庞大的接口分解为多个粒度小的接口,可以预防外来变更的扩散,提高系统的灵活性和可维护性。
    • 接口隔离提高了系统的内聚性,减少了对外交互,降低了系统的耦合性。
    • 如果接口的粒度大小定义合理,能够保证系统的稳定性;但是,如果定义过小,则会造成接口数量过多,使设计复杂化;如果定义太大,灵活性降低,无法提供定制服务,给整体项目带来无法预料的风险。
    • 使用多个专门的接口还能够体现对象的层次,因为可以通过接口的继承,实现对总接口的定义。
    • 能减少项目工程中的代码冗余。过大的大接口里面通常放置许多不用的方法,当实现这个接口的时候,被迫设计冗余的代码。
      在具体应用接口隔离原则时,应该根据以下几个规则来衡量:
    • 接口尽量小,但是要有限度。一个接口只服务于一个子模块或业务逻辑。
    • 为依赖接口的类定制服务。只提供调用者需要的方法,屏蔽不需要的方法。
    • 了解环境,拒绝盲从。每个项目或产品都有选定的环境因素,环境不同,接口拆分的标准就不同,需要深入了解业务逻辑。
    • 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。

    6.最少知识原则(Least Knowledge Principle - LKP)

    最少知识原则又叫迪米特法则。核心思想是:低耦合、高内聚
    一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。这样,当一个模块修改时,就会尽量少的影响其他的模块,扩展会相对容易,这是对软件实体之间通信的限制,它要求限制软件实体之间通信的宽度和深度。

    二、针对包设计的6大原则

    对包设计的几大原则,在软件开发中有包的概念,而包可以理解为存放一些相关类的容器。通过把类组织成包,我们可以在更高层次的抽象上理解设计。我们也可以通过包来管理软件的开发和发布。一个包中的类会和其他包的类存在依赖,跨越包的边界,因此包之间也会产生依赖关系。

    1.重用发布等价原则( Release Reuse Equivalency Principle,REP)

    重用的粒度就是发布的粒度。属于包设计的范畴。包是相关的类的集合,换言之一个类基本上都和其他的一些有依赖关系。因此发布的最小单位一般认为是一个包。那么问题来了,包里面包含的所有类都是可以重用的吗?不是的,可以重用的包中不能包含不可重用的类。因为不可重用的类参照了其他组件,包含这个类的这个包就变成不能重用了。而一个包的内容应该是为了同一个重用的目的编写的,也就是说一个包中的内容都是同一种类型,为了同一种类型的功能而编写的。

    2.共同封闭原则(Common Closure Principle,CCP)

    包中的所有类对于同一类性质的变化应该是共同封闭。一个变化若对一个包产生影响,则将对该包中的所有类产生影响,而对于其他的包不造成影响。也就是说一起修改的类,应该组合在一起(同一个包里)。
    如果必须修改应用程序里的代码,我们希望所有的修改都发生在一个包里(修改关闭),而不是遍布在很多包里。
    CCP原则就是把因为某个同样的原因而需要修改的所有类组合进一个包里。如果2个类从物理上或者从概念上联系得非常紧密,它们通常一起发生改变,那么它们应该属于同一个包。
    CCP跟开闭原则(OCP: Open Closed Principle) 有着很深的渊源关系,CCP的“关闭”(closure)就是OCP所提倡的:classes should be closed for modification but open for extension. 类应该对修改关闭,对扩展开放。但我们知道,100%的“关闭”是不现实的,我们在设计系统时,只能尽量地保持对大多数可预见的修改关闭。
    CCP延伸了OCP的“关闭”概念,当因为某个原因需要修改时,把需要修改的范围限制在一个最小范围内的包里。
    CCP原则帮助我们决定哪些类应该被放到同一个包里。

    3.共同重用原则(Common Reuse Principle,CRP )

    一个包中的所有类应该是共同重用的。如果重用了包中的一个类,那么就要重用包中的所有类。
    包经常以JAR、DLL的形式出现。如果被使用的包以JAR包的形式发布,那么使用这个包的代码即使只依赖这个包的一个类,也将依赖这个包。所以如果JAR包的内容进行了修改,即使是对非依赖的类进行了修改,也会影响使用者重新验证和发布新的版本。因此我们希望,一个包中的类都是不可分开的,仅仅只依赖其中的一部分情况应尽可能不出现。

    4.无环依赖原则(Acyclic Dependencies Principle,ADP)

    在包的依赖关系图中不允许存在环,即包之间的结构必须是一个直接的无环图形。

    5.稳定依赖原则(Stable Dependencies Principle,SDP )

    朝着稳定的方向进行依赖。

    6.稳定抽象原则(Stable Abstractions Principle,SDP)

    包的抽象程度应该和其稳定程度一致。一个稳定的包应该是抽象的,这样它的稳定性就不会使其无法扩展。另外,一个不稳定的包应该是具体的,因为它的不稳定性使其内部的具体代码易于修改。

    三、其他设计原则

    1.DRY( Don't repeat yourself,即避免重复代码)

    避免重复代码原则提出,每一段代码都必须在系统中有唯一的明确的目的。

    2.KISS(Keep It Simple, Stupid ,即简单就是美)

    KISS原则传达的是:让事情变得更简单!

    3.高内聚与低耦合(High Cohesion and Low Coupling - HCLC)

    模块内部需要做到内聚度高,模块之间需要做到耦合度低。

    4.惯例优于配置(Convention over Configuration - COC)

    尽量让惯例来减少配置,这样才能提高开发效率,尽量做到“零配置”。即所谓约定优于配置。

    5.关注点分离(Separation of Concerns - SOC)

    将一个复杂的问题分离为多个简单的问题,然后逐个解决这些简单的问题,那么这个复杂的问题就解决了。

    6.YAGNI(You Ain't Gonna Need It,即我们不应该为程序编写尚未用到的功能)

    YANGI原则建议如果你找不到一个某段代码存在的理由,就必须对其进行重构或剔除。

    7.少即是多(less is more)


    四、一些代码编写原则

    1.常量放在equals左边预防空指针异常

    2.只留有用的代码,做到最优化

    只保留有用的代码,无用的变量,方法,import导入的类未用的都需要去掉。

    参考博文:
    (1) https://www.cnblogs.com/shamao/p/10875528.html
    (2) https://www.jianshu.com/p/15edb371c0b5 (多种设计模式的讲解)

  • 相关阅读:
    Linux下取代top的进程管理工具 htop
    Linux学习初步
    【程序员的吐槽】八一八那些让你感觉蠢哭了的BUG
    【学习随手记】POSIX消息队列执行报Permission denied的问题。
    【学习总结】环境高级编程源码配置
    【学习总结】UNIX网络编程使用源码配置
    【工作心得】有关主键索引
    【转】More Effective C++ (虚拟构造函数)
    【转】C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
    【学习心得】python学习心得
  • 原文地址:https://www.cnblogs.com/jasonboren/p/12305525.html
Copyright © 2011-2022 走看看