快速理解-SOLID-面向对象设计依赖倒置原则

快速理解 SOLID (面向对象设计)——依赖倒置原则在程序设计领域, SOLID(单一功能、开闭原则、里氏替换、接口隔离以及依赖反转),指代了面向对象编程和面向对象设计的五个基本原则。当这些原则被一起应用时,它们使得一个程序员开发一个容易进行软件维护和扩展的系统变得更加可能。1. 依赖倒置原则1.1 依赖倒置原则 的定义一个方法应该遵从“依赖于抽象而不是一个实例” 1.2 依赖倒置原则 解决了什么问题一开始类A依赖于类B,由于需求发生了改变。要将类A依赖于类C,则我们需要修改类A依赖于类B的相关代码,这样会对程序产生不好的影响。假如需求又发生了改变,我们又需要修改类A的代码。 1.3 依赖倒置原则 举个例子public class UserService { private Plaintext plaintext; // 明文登录注册 public void register(){ Plaintext.register(); // 调用明文的注册方法 } public void login(){ Plaintext.login(); // 调用明文的登录方法 }}上面的例子可以看出,UserService类依赖于Plaintext类。有一天,由于使用明文登录注册不安全,需求改为使用密文登录注册。我们可以怎么办? //不符合 依赖倒置原则public class UserService { // private Plaintext plaintext; private Ciphertext ciphertext; // 密文登录注册 public void register(){ // Plaintext.register(); Ciphertext.register(); // 调用密文的注册方法 } public void login(){ // Plaintext.login(); Ciphertext.login(); // 调用密文的登录方法 }}在上面的例子,修改一个需求几乎将整个UserService类都修改了一遍,这不但麻烦,而且会给程序带来很多风险。所以上面的例子不符合依赖倒置原则。 ...

September 8, 2019 · 1 min · jiezi

快速理解-SOLID-面向对象设计接口隔离原则

快速理解 SOLID (面向对象设计)——接口隔离原则在程序设计领域, SOLID(单一功能、开闭原则、里氏替换、接口隔离以及依赖反转),指代了面向对象编程和面向对象设计的五个基本原则。当这些原则被一起应用时,它们使得一个程序员开发一个容易进行软件维护和扩展的系统变得更加可能。1. 接口隔离原则1.1 接口隔离原则 的定义多个特定客户端接口要好于一个宽泛用途的接口,简单来说就是接口版的单一职责原则。 1.2 接口隔离原则 解决了什么问题类A通过接口I依赖于类B,类C通过接口I依赖于类D。而往往类B和类D都实现类A和类B不需要的方法。 1.3 接口隔离原则 举个例子 在上面的例子中,UserDataController类通过接口依赖于UserDataService类,UserAuthController类通过接口依赖于UserAuthService类。但是他们都需要实现IUserService接口的所有方法,这样使代码出现了很多不必要的代码。 而有些人说,为什么不把UserDataService类和UserAuthService类合在一起呢?因为合在一起又违反了单一职责原则。 在上面的例子中,将IUserService接口拆分为不同的小接口,需要什么功能就实现什么接口。这样就避免了很多不必要的代码。 1.4 接口隔离原则 的总结定义接口尽可能的小,需要什么功能就实现什么接口。提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。2. 关注我的微信公众号,查看更多文章,第一时间收到我的文章。 SOLID (面向对象设计)——单一职责原则,你学会了吗?

September 8, 2019 · 1 min · jiezi

快速理解-SOLID-面向对象设计里氏替换原则

快速理解 SOLID (面向对象设计)——里氏替换原则在程序设计领域, SOLID(单一功能、开闭原则、里氏替换、接口隔离以及依赖反转),指代了面向对象编程和面向对象设计的五个基本原则。当这些原则被一起应用时,它们使得一个程序员开发一个容易进行软件维护和扩展的系统变得更加可能。1. 里氏替换原则1.1 里氏替换原则 的定义里氏替换原则这个名字使很多人产生了疑惑,其实里氏替换原则是由麻省理工学院的一位姓里的女士提出来的。派生类(子类)对象可以在程式中代替其基类(父类)对象。 1.2 里氏替换原则 解决了什么问题职责P是由类A实现的,现在需要对职责P进行扩展,扩展为职责P+。而职责P+由类A的子类B实现,则在子类B完成职责P+后,有可能破坏了原有的职责P。 1.3 里氏替换原则 举个例子public class User { // 增加积分 public void addCount(){ this.count = this.count + 10; }}上面这个User类可以看作有一个职责:用户增加积分。 而现在要求VIP用户不但增加积分而且增加经验: //不符合 里氏替换原则public class VIPUser extends User{ // 增加积分而且增加经验 public void addCount(){ this.count = this.count + 10; this.experience = this.experience + 10; }}上面这个VIPUser类通过重写来实现增加积分职责的扩展,但是也破坏了原有的增加积分职责。如果将使用User类的地方替换为VIPUser类,会因为addCount函数发生改变而产生错误。所以不符合里氏替换原则。 //符合 里氏替换原则public class VIPUser extends User{ // 增加积分而且增加经验 public void addCountVIP(){ super.addCount(); this.experience = this.experience + 10; }}上面这个VIPUser类通过调用父类方法来实现增加积分职责的扩展,没有破环原有的增加积分职责。而且任何使用User类的地方都可以替换为VIPUser类。所以符合里氏替换原则。 ...

September 8, 2019 · 1 min · jiezi

快速理解-SOLID-面向对象设计单一职责原则

快速理解 SOLID (面向对象设计)——单一职责原则在程序设计领域, SOLID(单一功能、开闭原则、里氏替换、接口隔离以及依赖反转),指代了面向对象编程和面向对象设计的五个基本原则。当这些原则被一起应用时,它们使得一个程序员开发一个容易进行软件维护和扩展的系统变得更加可能。1. 单一职责原则1.1 单一职责原则 的定义不要存在多于一个导致类变更的原因。简单的讲,认为对象应该仅具有一种单一功能。 1.2 单一职责原则 解决了什么问题类A 负责两个职责P1、职责P2。当由于职责P1需求发生改变时,而需要在类A中修改职责P1。有可能使原本正常运行的职责P2发生故障。 1.3 单一职责原则 举个例子//不符合 单一职责原则public class UserService { // ...增加 User 功能 // ...删除 User 功能 // ...更新 User 功能 // ...查询 User 功能 // ...User 登录功能}上面这个UserService类可以看作有两个职责: 对 User 数据的操作。对 User 验证。根据单一职责原则应该将这两个职责分别放在两个类中: //符合 单一职责原则public class UserDataService { // ...增加 User 功能 // ...删除 User 功能 // ...更新 User 功能 // ...查询 User 功能}public class UserAuthService { // ...User 登录功能}1.4 单一职责原则 的优点降低类的复杂度,一个类只负责一种职责。提高代码的可读性。降低更改需求带来的风险,降低对其他功能的影响。2. 关注我的微信公众号,查看更多文章,第一时间收到我的文章。 ...

September 8, 2019 · 1 min · jiezi

面向对象设计的SOLID原则

1、单一职责原则考虑下面这个类 class Animal { constructor(name: string){ } getAnimalName() { } saveAnimal(a: Animal) { }}它实际上违背了单一职责原则SRP。上面的类其实有两个职责,一为动物实体的持久化管理,另外一个为动物的属性管理。那我们应该如何设计避免这种错误呢?我们可以新建另外一个类,它负责将实体对象存储到数据库上。如下所示: class Animal { constructor(name: string){ } getAnimalName() { } } class AnimalDB { getAnimal(a: Animal) { } saveAnimal(a: Animal) { } }当我们设计类时需要注意的一点是,如果功能因不同原因而发生变化,我们应该尝试将功能分开。2、开闭原则这个原则强调现有接口规范可以通过继承重用,不要修改现有已完成的接口。我们继续以动物这个类说明 class Animal { constructor(name: string){ } getAnimalName() { }}我们的需求是让列表中每个动物发出不同的声音,如下所示//... const animals: Array<Animal> = [ new Animal('lion'), new Animal('mouse')];function AnimalSound(a: Array<Animal>) { for(int i = 0; i <= a.length; i++) { if(a[i].name == 'lion') log('roar'); if(a[i].name == 'mouse') log('squeak'); }}AnimalSound(animals);上面的示例违背了开闭原则,当有新的类型需要处理时,将不得不在原有代码上进行修改,导致大量的阅读性差的IF条件语句。那我们应该怎么设计避免这种错误呢?我们可以定义一个有makeSound方法的共同类比如说Animal类,然后每个具体动物类继承并重写makeSound方法,完成个性化处理。另外真正的处理业务的AnimalSound类遍历Animal列表然后调用makeSound方法即可。当新扩展一个具体动物类时,AnimalSound类无须做任何修改。代码如下: ...

August 20, 2019 · 2 min · jiezi