设计模式 - 面向对象

2022-04-17  本文已影响0人  Zeppelin421

面向过程

什么是面向过程编程

相较于面向对象编程以类为组织代码的基本单元,面向过程编程则是以过程(或方法)作为组织代码的基本单元。它最主要的特点就是数据和方法相分离。相较于面向对象编程语言,面向过程编程语言最大的特点就是不支持丰富的面向对象编程特性,比如继承、多态、封装。

面向对象

什么是面向对象编程和面向对象编程语言

如何判定一个编程语言是否是面向对象编程语言

只要某种编程语言支持类或对象的语法概念,并且以此作为组织代码的基本单元,那就可以被粗略地认为它就是面向对象编程语言了。至于是否有现成的语法机制,完全地支持了面向对象编程的四大特性、是否对四大特性有所取舍或优化,可以不作为判定的标准。

面向对象编程和面向对象编程语言之间的关系

面向对象编程一般使用面向对象编程语言来进行,但是不用面向对象编程语言,照样可以进行面向对象编程。反过来讲,即使我们使用面向对象编程语言,写出来的代码也不一定是面向对象编程风格的,也有可能是面向过程编程风格的。

什么是面向对象分析和面向对象设计

面向对象分析(OOA,Object Oriented Analysis)就是要搞清楚做什么,面向对象设计(OOD,Object Oriented Design)就是要搞清楚怎么做。这两个阶段最终的产出是类的设计,包括程序被拆解为哪些类,每个类有哪些属性方法、类与类之间如何交互等等。

面向对象软件开发要经历的三个阶段:OOA就是要搞清楚做什么;OOD就是要搞清楚怎么做;OOP就是将分析和设计的结果翻译成代码的过程

面向过程 VS 面向对象

面向对象编程相比面向过程编程的优势

哪些代码设计看似面向对象,实际是面向过程的

抽象类 VS 接口

特性

抽象类实际上就是类,只不过是一种特殊的类,这种类不能被实例化为对象,只能被子类继承,表示一种 is-a 的关系。接口表示一种 has-a 的关系,表示具有某些功能。对于接口,有一个更加形象的叫法,那就是协议(contract)

意义

应用场景

基于接口而非实现编程

“Program to an interface, not an implementation”
这条原则最早出现在 1994 年 GoF 的《设计模式》一书中,它先于很多编程语言,是一条比较抽象、泛化的设计思想。

此处的“接口”二字从本质上讲,就是一组“协议”或“约定”,是功能提供者提供给使用者的一个“功能列表”。落实到具体的编码中,可以理解为编程语言中的接口或抽象类。

“基于接口而非实现编程”这条原则的另一个表述是“基于抽象而非实现编程”。在软件开发中,最大的挑战之一就是需求的不断变化。越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性,越能应对未来的需求变化。好的代码设计,不仅能应对当下的需求,而且在将来需求发生变化的时候,仍然能够在不破坏原有代码设计的情况下灵活应对。抽象就是提高代码扩展性、灵活性、可维护性最有效的手段之一。

public class AliyunImageStore {
  //...省略属性、构造函数等... 
  public void createBucketIfNotExisting(String bucketName) {
    // ...创建bucket代码逻辑...
    // ...失败会抛出异常.. 
  }
  public String generateAccessToken() {
    // ...根据accesskey/secrectkey等生成access token
  }
  public String uploadToAliyun(Image image, String bucketName, String accessToken) {
    //...上传图片到阿里云...
    //...返回图片存储在阿里云上的地址(url)...  
  }
  public Image downloadFromAliyun(String url, String accessToken) {
    //...从阿里云下载图片...
  }
}

遵从“基于接口而非实现编程”的原则,需要做到以下三点:

在软件开发的时候,一定要有抽象意识、封装意识、接口意识。在定义接口的时候,不要暴露任何实现细节。接口的定义只表明做什么,而不是怎么做。

是否需要为每个类定义接口

做任何事情都要讲一个“度”,过度使用这条原则,非得给每个类都定义接口,也会导致不必要的开发负担。

这条原则的设计初衷是,将接口和实现分离,封装不稳定的实现,暴露稳定的接口。如果在业务场景中,某个功能只有一种实现方式,未来也不可能被其他实现方式替换,那我们就没有必要为其设计接口,也没有必要基于接口编程,直接使用实现类就可以了。

组合优于继承

public interface Flyable {
  void fly();
}
public class FlyAbility implements Flyable {
  @Override
  public void fly() { //... }
}
//省略Tweetable/TweetAbility/EggLayable/EggLayAbility

public class Ostrich implements Tweetable, EggLayable {//鸵鸟
  private TweetAbility tweetAbility = new TweetAbility(); //组合
  private EggLayAbility eggLayAbility = new EggLayAbility(); //组合
  //... 省略其他属性和方法...
  @Override
  public void tweet() {
    tweetAbility.tweet(); // 委托
  }
  @Override
  public void layEgg() {
    eggLayAbility.layEgg(); // 委托
  }
}

基于MVC贫血模式 VS 基于DDD充血模式

什么是基于贫血模型的传统开发模式

在MVC三层架构中,UserEntity 和 UserRepository 组成了数据访问层;UserBO 和 UserService 组成了业务逻辑层;UserVO 和 UserController 组成接口层。UserBO 是一个纯粹的数据结构,只包含数据,不包含业务逻辑。业务逻辑集中在 UserService 中。

像 UserBO 这样只包含数据,不包含业务逻辑的类,就叫作贫血模型(Anemic Domain Model)。这种贫血模型将数据与操作分离,破坏了面向对象的封装特性,是一种典型的面向过程的编程风格。

什么是基于充血模型的DDD开发模式

充血模型(Rich Domain Model)与之相反,数据和对应的业务逻辑被封装到同一个类中。因此充血模型满足面向对象的封装特性,是典型的面向对象编程风格。

DDD(领域驱动设计)主要是用来指导如何解耦业务系统,划分业务模块,定义业务领域模型及其交互。

基于贫血模式的传统开发中,Service 层包含 Service 类和 BO 类,基于充血模型的 DDD 开发模式中,Service 层包含 Service 类和 Domain 类两部分。Domain 就相当于 BO。不过 Domain 与 BO 的区别在于它是基于充血模型开发的,既包含数据,也包含业务逻辑。总结一下就是,贫血模型重 Service 轻 BO;充血模型轻 Service 重 Domain。

为什么基于贫血模式的传统开发受欢迎

什么项目应该考虑使用充血模型的DDD开发模式

对于业务不复杂的系统来说,基于贫血模型的传统开发模式简单够用。
对于业务复杂的系统开发来说,基于充血模型的DDD开发模式,因为前期需要在设计上投入更多时间和精力,来提高代码的复用性和可维护性,所以相比于贫血模型的开发模式,更加有优势。

Controller 层和 Repository 层有必要也进行充血领域建模吗?

Controller 层主要负责接口的暴露,Repository 层主要负责与数据库打交道,这两层包含的业务逻辑并不多,即便是设计成充血模型,类也非常单薄,看起来也很奇怪,所以没必要进行充血领域建模。

尽管这样的设计是一种面向过程的编程风格,但只要控制好面向过程编程风格的副作用,一样可以开发出优秀的软件。

上一篇 下一篇

猜你喜欢

热点阅读