设计模式七大设计原则及UML类图

一、设计模式七大原则

1.单一职责原则

​ 就一个类而言,应该仅有一个引起它变化的原因。应该只有一个职责。 每一个职责都是变化的一个轴线,如果一个类有一个以上的职责,这些职责就耦合在了一起。这会导致脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起,会影响复用性。例如:要实现逻辑和界面的分离。

​ 例如类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障。也就是说职责P1和P2被耦合在了一起。

​ 但是,没有任何的程序设计人员不清楚应该写出高内聚低耦合的程序,但是很多耦合常常发生在不经意之间,其原因就是:

职责扩散:因为某种原因,某一职责被分化为颗粒度更细的多个职责了。

​ 解决办法就是遵守单一职责原则,遵守单一职责原则,将不同的职责封装到不同的类或模块中,例如上述问题中可将T拆分为T1,T2分别完成职责P1和P2;

单一职责原则注意事项和细节:

  1. 降低类的复杂度,一个类只负责一项职责。
  2. 提高类的可读性,可维护性
  3. 降低变更引起的风险
  4. 通常情况下,我们应当遵守单一职责原则,只有逻辑足够简单,才可以在代码级违 反单一职责原则;只有类中方法数量足够少,可以在方法级别保持单一职责原则

2.接口隔离原则

客户端不应该依赖它不需要的接口;
一个类对另一个类的依赖应该建立在最小的接口上。
概括的说就是:建立单一接口,不要建立臃肿庞大的接口。(接口尽量细化,同时接口中的方法尽量少。)
提供给每个模块的都应该是单一接口,提供给几个模块就应该有几个接口,而不是建立一个庞大的臃肿的接口,容纳所有的客户端访问。接口是我们设计时对外提供的契约,通过分散定义多个接口,可以预防未来变更的扩散,提高系统的灵活性和可维护性。

可以简要解释为以下四点:

  1. 接口要尽量小
    这是接口隔离原则的核心定义,不出现臃肿的接口(Fat Interface),但是“小”是有限度的,首先就是不能违反单一职责原则。根据接口隔离原则拆分接口时,首先必须满足单一职责原则。
  2. 接口要高内聚
    高内聚就是要提高接口、类、模块的处理能力,减少对外的交互。具体到接口隔离原则就是,要求在接口中尽量少公布public方法,接口是对外的承诺,承诺地越少对系统开发越有利,变更的风险也就越少,同时也有利于降低成本。
  3. 定制服务
    定制服务就是单独为一个个体提供优良的服务。
  4. 接口设计是有限度的
    接口的设计粒度越小,系统越灵活,这是不争的事实。但是,灵活的同时也带来了结构的复杂化,开发难度增加,可维护性降低,这不是一个项目或产品所期望看到的,所以接口设计一定要注意适度,这个度只能根据经验和常识判断,没有一个固化或可测量的标准。

例如:现在一个接口interface1下有五个方法;类A用到了其中其中的3个,类B用到了另外的两个。这样interface1接口对于类A和类B来说就不是最小接口,应该将接口拆分为两个,A和B分别去实现对应的接口;

3.依赖倒置原则

​ 依赖倒置原则(Dependence Inversion Principle)就是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。

理解如下几点:

  1. 高层模块不应该依赖低层模块,二者都应该依赖其抽象
  2. 抽象不应该依赖细节,细节应该依赖抽象
  3. 依赖倒转(倒置)的中心思想是面向接口编程
  4. 依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在java中,抽象 指的是接口或抽象类,细节就是具体的实现类 ;
  5. 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的 任务交给他们的实现类去完成

4.里氏置换原则

​ 定义:所有引用基类的地方必须能够透明的使用其子类对象; 也就是说,有两个对象P和Sub,sub继承了P。在用到P的地方,如果将P对象改为Sub对象,代码的功能应该保持不变。这就意味着子类不能重写重写父类的方法;

1、里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能(不能重写)。

2、里氏代换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。

3、里氏代换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。

5.开闭原则

​ 开闭原则,在面向对象编程领域中,规定“软件中的对象,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。该特性在产品化的环境中是特别有价值的,在这种环境中,改变源代码需要代码审查单元测试以及诸如此类的用以确保产品使用质量的过程。遵循这种原则的代码在扩展时并不发生改变,因此无需上述的过程。

  1. 开闭原则(Open Closed Principle)是编程中最基础、最重要的设计原则
  2. 一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用 方)。用抽象构建框架,用实现扩展细节。
  3. 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已 有的代码来实现变化。
  4. 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。

6.迪米特法则

​ 迪米特法则(Law of Demeter)又叫作最少知识原则(The Least Knowledge Principle),一个类对于其他类知道的越少越好,就是说一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和陌生人说话。英文简写为: LOD。

  1. 一个对象应该对其他对象保持最少的了解
  2. 类与类关系越密切,耦合度越大
  3. 迪米特法则(Demeter Principle)又叫最少知道原则,即一个类对自己依赖的类知道的 越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的public 方法,不对外泄露任何信息
  4. 迪米特法则还有个更简单的定义:只与直接的朋友通信

直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系, 我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合 等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而 出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量 的形式出现在类的内部。

迪米特法则注意事项和细节

  1. 迪米特法则的核心是降低类之间的耦合
  2. 但是注意:由于每个类都减少了不必要的依赖,因此迪米特法则只是要求降低 类间(对象间)耦合关系, 并不是要求完全没有依赖关系

7.合成复用原则

​ 合成复用原则( Composite Reuse Principle, CRP )又叫组合/聚合复用原则( CARP)。 它要求在软件复用时,要尽量先使用组合或者聚合等关联关系来实现,其次才考虑使用继承关系来实现。如果要使用继承关系,则必须严格遵循里氏代换原则。合成复用原则同里氏代换原则相辅相成的,两者都是开闭原则的具体实现规范。

(1)通常类的复用分为继承复用和合成复用两种,继承复用虽然有简单和易实现的优点,但它也存在以下缺点。

①继承复用破坏了类的封装性。因为继承会将父类的实现细节暴露给子类,父类对子类是透明的,所以这种复用又称为“白箱”复用。
②子类与父类的耦合度高。父类的实现的任何改变都会导致子类的实现发生变化,这不利于类的扩展与维护。
③它限制了复用的灵活性。从父类继承而来的实现是静态的,在编译时已经定义,所以在运行时不可能发生变化。

(2)采用组合或聚合复用时,可以将已有对象纳入新对象中,使之成为新对象的一部分,新对象可以调用已有对象的功能,它有以下优点。

①它维持了类的封装性。因为成分对象的内部细节是新对象看不见的,所以这种复用又称为“黑箱”复用。
②新旧类之间的耦合度低。这种复用所需的依赖较少,新对象存取成分对象的唯一方 法是通过成分对象的接口。
③复用的灵活性高。这种复用可以在运行时动态进行,新对象可以动态地引用与成分对象类型相同的对象。

二、UML(Unified Modeling Language)统一建模语言之类图

uml类图用于描述系统中的类(对象)本身的组成和类(对象)之间的各种静态关系。

类之间的关系:依赖、泛化(继承)、实现、关联、聚合与组合

2.1 依赖(Dependence)

只要是在一个类中用到了另一个类,那么他们之间就存在依赖关系,是一种使用的关系,即一个类的实现需要另一个类的协助

表示方式:虚线箭头。类A需要用到类B,类A指向类B。

以下几种方式都是依赖关系

  1. 如果是类的成员属性
  2. 如果是方法的返回类型
  3. 是方法接收的参数类型
  4. 方法中使用到

2.2 泛化(generalization)

泛化关系实际上就是继承关系,他是依赖关系的特例

表示方式:实线三角形。三角形在父类那边

2.3 实现(Implementation)

实现关系实际上就是A类实现B接口,他是依赖关系的特例

表示方式:虚线三角形

2.4 关联关系(Association)

表示类与类之间的联接,它使一个类知道另一个类的属性和方法,这种关系比依赖更强、不存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的。在Java中,一个类的全局变量引用了另一个类,就表示关联了这个类,关联关系实际也是依赖关系的一种

表示方式:实线箭头

2.5 聚合(Aggregation)

​ 聚合是关联关系的一种特例,是强的关联关系。聚合强调的是整体和个体之间的关系,即has-a的关系,整体与个体可以具有各自的生命周期,部分可以属于多个整体对象,也可以为多个整体对象共享。程序中聚合和关联关系是一致的,只能从语义级别来区分。

表示方式:实线空心菱形

2.6 组合(Composition)

​ 组合也是关联关系的一种特例。组合是一种整体与部分的关系,即contains-a的关系,比聚合更强。部分与整体的生命周期一致,整体的生命周期结束也就意味着部分的生命周期结束,组合关系不能共享。程序中组合和关联关系是一致的,只能从语义级别来区分。

表示方式:实线实心菱形

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值