目录
前言
本篇文章将具体的阐述依赖倒置原则的概念,然后再介绍如何使用具体方法(依赖注入)实现依赖倒置原则。
一、原则理解
1.概念阐释
依赖倒置原则是程序要依赖于抽象接口,不要依赖于具体实现。
依赖就是一种使用关系
为什么要这样做呢?
因为一般在设计程序的时候,使用的是面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变动时上层也要跟着变动,这就会导致模块的复用性降低而且大大提高了开发的成本。
所以使用了面向对象的开发很好的解决了这个问题,一般情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即使实现细节不断变动,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序与实现细节的耦合度。
2.详细说明
在实现依赖倒置原则的过程中,应该遵循以下要求:
1)高层模块(调用者)不应该依赖于低层模块(被调用者),两个模块都应该依赖于抽象,这样就不会依赖于具体的实现。
2)抽象不应该依赖于细节,细节(内存条)应该依赖于抽象(主板)
什么是细节呢?我们可以这样思考:
内存条的接口具有一个标准的规范,而主板上会设计好接口形状,这就是抽象,让内存条按照接口规范设计就是细节,也就是具体实现。
依赖倒置原则本质就是通过抽象使得每个类或者模块的实现彼此独立,互不影响,实现模块间的松耦合
3. 具体实现
在设计程序的时候,其实可以将对象分为两种:客户类和服务类,客户类承担管理功能的作用,服务类承担具体实现的作用。
而在依赖倒置原则中,需要程序依赖于抽象接口,不依赖于具体实现,所以实际上的要求是:
客户端不依赖于服务类
我们可以进行一下推导:
->客户类不直接依赖于服务类
->客户类不可以直接实例化服务类,但是客户类又需要服务类的服务
那么如何实现这一点呢?
可以在客户类中定义一个注入点,用于服务类的注入,而客户类的客户类(main主要的管理类)负责根据情况,实例化服务类,注入到客户类(只负责管理当前的功能)中,然后再在客户类中进行服务类逻辑的使用
在代码中实现起来就是:main中实例化服务类,然后将继承了服务接口的服务类直接传入客户类中,最终实现对应逻辑
那如何注入呢?
在这里我们使用依赖注入的方法,而这个方法,也会在文章之后进行具体介绍。
4.原则之间的关系
依赖倒置原则是开闭原则和单一职责的核心,是实现开放封闭的一个基石
实现依赖倒置原则的一个基础是里式替换原则-里氏替换原则通俗来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能
二、实现方式
下面将介绍实现依赖注入的3种方式
1.通过接口传递
定义客户接口IPlayer,将服务端接口IWeapon作为参传入具体的方法中。
实质:顾名思义,就是在接口中传递
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace DevelopmentClosurePrinciple
{
public class DependPrinciple : MonoBehaviour
{
private void Start()
{
Anon anon = new Anon();
anon.Attack(new Sword());
}
}
public interface IWeapon
{
void Judge();
}
public interface IPlayer
{
void Attack(IWeapon weapon);
//在接口类中,将服务对象以参数值的形式,直接注入,称之为接口注入
}
//分别实现
public class Sword : IWeapon
{
public void Judge()
{
Debug.Log("剑已经抬起在判断");
}
}
public class Anon : IPlayer
{
public void Attack(IWeapon weapon)
{
weapon.Judge();
}
}
}
2.构造方法传递
在构造继承客户接口IPlayer的Anon类中,将服务端接口IWeapon作为参数传入构造函数中
实质:在继承接口的类中传递
public class DependPrinciple : MonoBehaviour
{
private void Start()
{
Anon anon = new Anon(new Sword());
anon.Attack();
}
}
public interface IWeapon
{
void Judge();
}
public interface IPlayer
{
void Attack();
}
//分别实现
public class Sword : IWeapon
{
public void Judge()
{
Debug.Log("剑已经抬起在判断");
}
}
public class Anon : IPlayer
{
private IWeapon weapon;
public Anon(IWeapon weapon)
{
this.weapon = weapon;
}
public void Attack()
{
weapon.Judge();
}
}
3.通过set方法传递
与构造方法类似,区别是将服务端接口IWeapon作为参数传入继承类Anon一个具体的函数中
实质:在继承接口的类中传递
public class DependPrinciple : MonoBehaviour
{
private void Start()
{
Anon anon = new Anon();
anon.SetWeapon(new Sword());
anon.Attack();
}
}
public interface IWeapon
{
void Judge();
}
public interface IPlayer
{
void SetWeapon(IWeapon weapon);
void Attack();
}
//分别实现
public class Sword : IWeapon
{
public void Judge()
{
Debug.Log("剑已经抬起在判断");
}
}
public class Anon : IPlayer
{
private IWeapon weapon;
public void SetWeapon(IWeapon weapon)
{
this.weapon = weapon;
}
public void Attack()
{
weapon.Judge();
}
}