设计原则学习

本文介绍了面向对象编程的设计原则,如单一职责、开闭原则等,强调以“高内聚、低耦合”为判断标准。还阐述了模式的概念,包括设计模式和架构模式。详细讲解了单例、工厂、原型等设计模式,涉及使用场景、实现方式及优缺点等信息技术相关内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

设计原则

面向对象是一种编程思维,是我们分析问题设计模型的一种思路。从本质上看,是没有绝对的对与错的。但是,不同的设计方式还有高低之分的。而判断的标准是什么呢? 1、最基本的标准是功能实现; 2、在都能够实现功能的前提下,我们的判断标准就叫做“高内聚、低耦合”。

“内聚度” --- 体现的是每一个基本模块自己本身的功能完整度。高内聚指的是一个模块本身的任务就应该在它内部完成,不要分散到别的地方。

基本模块根据粒度,可以是一个子系统,也可以是一个包,也可以是一个类,还可以是一个方法。

“耦合度” --- 体现的是模块与模块的关联关系。低耦合指的是尽量关联需要使用到的其他模块,无关模块不要关联;关联的时候尽量采用松散易解除或易修改的关联方式。

“高内聚”和“低耦合”仍然是一个范围比较大的概念,对代码设计的具体指导意义不大。所以,软件业又提出了一些设计原则,供我们在具体分析和设计的时候作为指导性原则:

单一职责

模块的职责要单一,不能将太多的职责放在一个模块中。 具体到我们能够理解的范围内: 1、一个方法只应该完成一个功能,方法名就应该是对这个功能的完整描述; 2、一个类只应该描述一种对象; 3、一个包只应该包含跟这个包描述的功能相符的功能类和接口;

开闭原则

开闭原则是其他各种原则的核心,或者说其他的原则都是为了在某一方面达到开闭效果而提出来具体原则。

Software should be opened for Extendtion, but closed for Modification。 软件应该对扩展进行开放,对修改进行关闭。

里氏替换

这是一个专门用来判断该不该做继承的原则。 我们之前判断该不该做继承,我们用的是一种叫做"is-a"(是一个)的判断方式。

可惜,is-a方式是基于我们的生活场景提出来的。但是,在软件系统中,这种经验有可能是错误的。

她提出来判断两个类是否应该做继承的标准是:凡是父类对象在本系统中能够正确工作的位置,都能够替换成子类对象且不引起额外的错误。

依赖倒转

在设计类与类的关联的时候,尽量关联对方的抽象(抽象类与接口),不要直接去关联对象的实现类。 这样做的好处是为了能够达到多态的效果。因为抽象类(接口)的引用可以指向它所有的实现子类对象。那么,我们如果需要更改实现,只需要增加新的子类或新的实现类,而不需要更改关联处的代码。

接口隔离

尽量定义职责单一的小接口,少定义职责过多的大接口。

愿义:上层接口的设计不应该污染下层接口(或实现类)的职责,要做好职责隔离。

比如:上层接口有三个行为,下层子接口或实现类只需要用到其中的两个或1个。但是,通过接口实现的语法,导致下层的接口或实现类也有3个行为,多了他们不需要的,这就是“污染”。那么在这种情况下,我们最好做三个上层接口,各自拥有一个行为,让子接口或实现类根据自己的业务需要可以自主选择。

误区一:有人会认为为了不违反接口隔离原则,那每个接口都只定义一个行为。 如果我们判断出某些行为是同时出现或同时不出现的,完全可以把它们写在一个接口当中。

误区二:很多同学到了面试阶段后,会把接口隔离原则和依赖倒转原则搞混。

在三层架构当中,我们的表示类关联业务层接口,然后通过配置去产生业务类对象交给这个接口的引用;同理,我们的业务类关联持久层接口,然后通过配置去产生持久类对象交给这个接口引用。这是典型的“上层不要关联下层的具体实现,而应该关联下层的抽象”---依赖倒转。

这个过程,我们后面还要继续通过实践来进一步讲解和领悟。

组合聚合原则

少用继承,多用组合和聚合。

继承的方式是一种硬代码的关联,一旦发生变化,我们必须去修改extends 后面的父类

组合和聚合是支持多态的,然后再配合我们的反射技术,通过配置文件和注解,可以在不改变java代码的情况下,直接绑定子类对象。

所以从动态性,以及开闭原则来看,组合聚合比继承更好。

迪米特法则

也叫“最少知识原则”。 类与类之间的绑定关系,尽量的简洁,只绑定跟你相关的类,无关的别去绑定。 因为你绑定的越多,那么引起这类变化的原因也就越多。

模式

在上面讲解当中所涉及到的设计原则,这些原则非常重要,特别是对于一个设计人员来说。但是编码实现的开发人员来说,往往局限于眼界或经验并不能完全体会到它们的实用性,或者在处理具体问题域的时候不知道该如何来设计或实现自己代码从而满足上面的原则要求。由此,产生了“模式”。

我们在编程的过程中,随着参与的项目越来越多,大家会发现:有时候很多问题并不是某一个项目中独有的,而是反反复复在不同的项目中出现。于是先人们就把这些问题总结出来,起了名字,给出了统一的标准的经过印证的解决“套路”。

所以,“模式”就是“套路”。模式在学习过程中有如下几个关键点: 1、模式要用在什么地方 2、模式的名字 --- 名字的主要目的是为了更好的在同行中进行交流 --- 名字也是对模式的精炼描述 3、当然是模式的具体解决方案 4、这个模式使用后的优缺点,特别是一个模式有多种解决方案,那更要去了解这多种方案的优缺点,才能在合适的时候选择使用合适的方案。

在软件工程当中,模式有两大类: 1、设计模式; 更偏向于某个具体的问题域的解决,是代码级别的解决方案;-- 微观

2、架构模式; 更偏向于工程的组织架构的设计,对于一个项目中拥有的众多的类和接口,如何进行分工,如何进行关联;-- 宏观

设计模式

一共有23种,分为三大类: 1、创建模式 -- 主要创建某种特殊的对象,或则在某种特殊要求下创建对象

2、结构模式 -- 主要是利用组合/聚合,或者是继承,让类与类能够形成某种关联结构,从而更适应某个问题域的解决。

3、行为模式 -- 探讨的是在某种问题域当中如何设计一个行为来适应这个场景。

单例模式 --- Singleton

当在一些问题域当中,需要我们去创建一种类,这个类能且只能产生一个对象。 单例模式有几种: 1、饿汉模式; 2、懒汉模式; 3、DCL模式; 4、内部类模式; 5、枚举的方式实现单例 --- 有兴趣的同学可以自己去看看

前面4种常常在面试中出现,要求分辨各自的优缺点,以及手工书写要求的实现方式(DCL和内部类的方式最多)。

工厂模式 --- Factory

使用场景是:将对象的使用者和对象的生产者进行分离。

在所有的工厂模式当中,都有三种角色的类,我们把它们称之为"消费者","生产者",“产品”。消费者需要用到产品对象,但是不用自己去构建这个产品对象,而是找生产者要即可; 生产者提供方法,专门返回产品对象,无需关心这个产品对象被拿来做什么。

1、简单工厂模式 这种模式考虑的变化点是,同一个工厂,可以根据不同的情况,产生不同的产品对象。 由于变化点是在产品对象上,所以这个时候我们往往会抽象产品,然后给它提供不同的实现类。

2、工厂方法模式 这种模式同一个产品,不同的工厂生产出来会有差异性。 这个时候的变化点是在工厂上,所以我们往往会抽下你给工厂。

3、抽象工厂 工厂和产品都是变化点,所以我们既要抽象出工厂父类,也要抽象出产品父类。

原型模式 --- prototype

场景是:根据一个已经存在的对象,创建一个新的跟它一摸一样的对象。 --- 克隆

利用Object中的clone()

1、首先要让被克隆的类实现Cloneable接口; 2、然后要重写clone方法,提升它的访问修饰符为public; 3、最后的效果,是浅克隆的效果。

所谓的“浅克隆”是指,被clone的对象会产生一个新的,但是它的属性对象不产生。也就是说,clone方法只克隆一层。

要解决这个问题:只能一层层去克隆,需要让我们自己去克隆每一个关联对象,然后再把它们组装起来,才能够完成“深克隆”。很明显,这么做很麻烦。

直接利用对象的序列化和反序列化实现深克隆

1、让所有的自定义类型实现Serializable接口;

2、在最外层的类身上增加一个自定义方法,完成序列化和反序列化就可以了。

总结一下

原型模式也是后面使用比较多的一种,同时也是面试官的常用问题。 1、深克隆和浅克隆的区别 2、clone方法的使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值