首页 > 编程语言 >面向对象编程的 SOLID 原则

面向对象编程的 SOLID 原则

时间:2023-07-29 16:47:08浏览次数:56  
标签:面向对象编程 原则 SOLID price class book invoice public

SOLID 原则是面向对象 class 设计的五条原则。他们是设计 class 结构时应该遵守的准则和最佳实践。

通常,这五个原则可以帮助我们了解设计模式和软件架构。这是每个开发人员都应该了解的主题。

这篇文章介绍了在项目中使用 SOLID 原则的细节。

首先我们先看一下 SOLID 原则的历史。然后我们会设计一个 class 并且逐步改善它,来亲密接触 SOLID 原则,了解为什么使用以及怎么使用各个原则。

准备一杯咖啡或者茶,让我们马上开始!

背景

SOLID 原则首先由著名的计算机科学家 Robert C·Martin (著名的Bob大叔)由 2000 年在他的论文中提出。但是 SOLID 缩略词是稍晚由 Michael Feathers 先使用的。

Bob大叔也是畅销书《代码整洁之道》和《架构整洁之道》的作者,也是 "Agile Alliance" 的成员。

因此,代码整洁、面向对象架构、设计模式彼此互补并以这种方式连接就不足为奇了。

他们达成的目标是一致的:

“创建可多人协作的、易于理解的、易读的以及可测试的代码。”

现在依次看一下各个原则,SOLID 是以下是原则的缩写:

  • S 单一职责原则
  • O 开闭原则
  • L 里氏替换原则
  • I 接口隔离原则
  • D 依赖倒置原则

单一职责原则

单一职责原则的描述是 ** 一个 class 应该只做一件事,一个 class 应该只有一个变化的原因**。

更技术的描述该原则:应该只有一个软件定义的潜在改变(数据库逻辑、日志逻辑等)能够影响 class 的定义。

这意味着如果 class 是一个数据容器,比如 Book class 或者 Student class,考虑到这个实体有一些字段,应该只有我们更改了数据定义时才能够修改这些字段。

遵守单一职责原则很重要。首先,可能很多不同的团队可能修改同一个项目,可能因为不同的原因修改同一个 class,会导致冲突。

其次,单一职责更容易版本管理,比如,有一个持久化 class 处理数据库操作,我们在 GitHub 看到某个文件上有一处修改。如果遵循 SRP 原则,根据文件就能判断这是关于存储或者数据库相关的提交。

另一个例子是合并冲突,当不同的团队修改同一个文件时,如果遵循 SRP原则,冲突很少会发生,因为文件只有一个变化的原因,即使出现冲突也会很容易解决。

常见错误和反面教材

在本节我们会看一些违背单一职责原则的常见错误。然后会探讨修复他们的方法。

我们会以一个简单的书店发票程序代码作为例子。让我们从定义一个使用发票的图书 class 开始。


class Book {
	String name;
	String authorName;
	int year;
	int price;
	String isbn;

	public Book(String name, String authorName, int year, int price, String isbn) {
		this.name = name;
		this.authorName = authorName;
		this.year = year;
        this.price = price;
		this.isbn = isbn;
	}
}

这是一个有一些字段的 book class。没什么新奇的。之所以没有把字段设置为私有的是因为想专注于逻辑而不是 getter 和 setter。

现在让我们来创建一个 invoice class,包含创建发票和计算总额的业务逻辑。目前为止,假设书店只卖书,不卖别的。


public class Invoice {

	private Book book;
	private int quantity;
	private double discountRate;
	private double taxRate;
	private double total;

	public Invoice(Book book, int quantity, double discountRate, double taxRate) {
		this.book = book;
		this.quantity = quantity;
		this.discountRate = discountRate;
		this.taxRate = taxRate;
		this.total = this.calculateTotal();
	}

	public double calculateTotal() {
	        double price = ((book.price - book.price * discountRate) * this.quantity);

		double priceWithTaxes = price * (1 + taxRate);

		return priceWithTaxes;
	}

	public void printInvoice() {
            System.out.println(quantity + "x " + book.name + " " +          book.price + "$");
            System.out.println("Discount Rate: " + discountRate);
            System.out.println("Tax Rate: " + taxRate);
            System.out.println("Total: " + total);
	}

        public void saveToFile(String filename) {
	// Creates a file with given name and writes the invoice
	}

}

这是 invoice class。它包含一些发票相关的字段以及三个方法。

  • calculateTotal 方法,计算总价格
  • printInvoice 方法,打印发票信息到控制台
  • saveToFile 方法,负责将发票写到一个文件里

在读下一段之前停下来想一想,这样的 class 设计有什么问题。

那么问题出在哪呢? 我们的 class 在多个地方都违背了单一职责原则。

第一处是 printInvoice 方法,因为里面包含了打印逻辑。SRP 描述 class 应该只有一个变化的原因,这个变化原因应该是 class 里的发票计算。

在这个架构里,如果我们想要改变打印格式,我们需要修改这个 class。我们不能把打印逻辑和业务逻辑混合在一个class 里。

在 class 里面还有一个方法违背了 SRP: saveToFile 方法。这也是一个很常见的错误,把持久化逻辑和业务逻辑混合在了一起。

这不单单是写入文件 - 也可能是存库,发起 API 调用或者其他与持久化相关的操作。

你可能会问,怎样修复这个打印函数呢?

可以为打印和持久化逻辑创造一个新 class,因此就无需因为这些原因修改 invoice class 了。

创建两个 class, InvoicePrinter 和 InvoicePersistence ,并移入相应方法。


public class InvoicePrinter {
    private Invoice invoice;

    public InvoicePrinter(Invoice invoice) {
        this.invoice = invoice;
    }

    public void print() {
        System.out.println(invoice.quantity + "x " + invoice.book.name + " " + invoice.book.price + " $");
        System.out.println("Discount Rate: " + invoice.discountRate);
        System.out.println("Tax Rate: " + invoice.taxRate);
        System.out.println("Total: " + invoice.total + " $");
    }
}


public class InvoicePersistence {
    Invoice invoice;

    public InvoicePersistence(Invoice invoice) {
        this.invoice = invoice;
    }

    public void saveToFile(String filename) {
        // Creates a file with given name and writes the invoice
    }
}

现在 class 结构遵从了单一职责原则,每个 class 为我们应用的一个部分负责。棒!

标签:面向对象编程,原则,SOLID,price,class,book,invoice,public
From: https://www.cnblogs.com/gongxianjin/p/17590035.html

相关文章

  • Python面向对象编程-学习笔记(二)
    5.类的继承classEmployee:raise_amount=1.04def__init__(self,first,last,pay):self.first=firstself.last=lastself.pay=payself.email=first+'.'+last+'@company.com'cla......
  • 面向对象编程的 SOLID 原则 - 开闭原则
    开闭原则开闭原则要求“class应该对扩展开放对修改关闭”。修改意味着修改存在class的代码,扩展意味着添加新的功能。这个原则想要表达的是:我们应该能在不动class已经存在代码的前提下添加新的功能。这是因为当我们修改存在的代码时,我们就面临着创建潜在bug的风险。因此,......
  • 定制化SOLIDWORKS插件开发服务流程解析
    SOLIDWORKS是一套三维设计软件,采用特征建模、变量化驱动可方便地实现三维建模、装配和生成工程图。SOLIDWORKS软件本身所具有的交互方式,可以使用户对已生成模型的尺寸、几何轮廓和相互约束关系随时进行修改,而不需要编程。SOLIDWORKS软件本身的方程式可以实现简单的参数逻辑变......
  • terrasolid是什么?和microstation v8i的关系?
    Terrasolid这款软件需要在MicroStationV8i这个软件的运行环境下才能使用。参考:https://www.cnblogs.com/yibeimingyue/p/15589355.html参考2:https://wenku.baidu.com/view/4f5aa22e660e52ea551810a6f524ccbff121ca1b.html参考3:https://download.csdn.net/download/hhudxy2010/......
  • 响应式网页设计应该注意的9个原则
    响应式网站越来越受到大家的欢迎,有利也有弊的因素。它没有固定的页面尺寸、没有毫米或英寸,没有任何物理限制,让人感到无从下手。下面就和大家分析如何运用响应式web设计的各项基本原则来实现。为了简单起见,就说说响应式网站的布局。希望对你有所受益。1、Web字体Vs系统字体想让自......
  • solidworks api ch04
    用默认模板新建零件,并修改用户偏爱:letnewPart(swApp:ISldWorks)=//GetthefilepathofthedefaultparttemplateletpartTemplate=swApp.GetUserPreferenceStringValue(intswUserPreferenceStringValue_e.swDefaultTemplatePart)letswModel=......
  • SOLIDWORKS PDM中如何快速生成BOM,SolidKits助您一臂之力
    在SOLIDWORKSPDM中,生成BOM操作是比较简单的,但前提条件是我们的模型必须具有相应的属性信息才可以。SolidKits.Reports企业高级报表软件给用户提供了一种更加便捷的出BOM的方式,使我们的工作效率更高,其使用方法也非常简单,我们一起来看下操作步骤吧!首先找到需要生成BOM的总成文件,然......
  • 索引的建立原则?什么是索引?如何建立一个好的索引?
    索引的本质其实就是一种排好序的数据结构。1.必须遵循唯一的索引原则,将其使用的作为索引的字段必须是唯一的,这样涉及的原则跟好处就是,唯一的索引会避免数据库去查询的时候会产生两样性,从而导致索引的查找的速率大大降低。2.索引的设计要根据where关键字跟orderby关键字还有gru......
  • 软件设计七项原则
    一、软件设计七项原则总结归纳设计原则归纳总结开闭原则对扩展开放,对修改关闭里氏替换原则不要破坏继承体系,子类重写方法功能发生改变,不应该影响父类方法的含义依赖倒置原则高层不应该依赖低层,要面向接口编程单一职责原则一个类只干一件事,实现类要单一......
  • 面向对象编程
    面向对象编程初识面向对象面向过程思想步骤清晰简单,第一步做什么,第二步做什么...面向过程适合处理一些较为简单的问题面向对象思想物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考.最后,才对某个分类下的细节进行面向过程的思......