其他分享
首页 > 其他分享> > 0x04、设计模式原则 —— 依赖倒置(倒转)原则

0x04、设计模式原则 —— 依赖倒置(倒转)原则

作者:互联网

概念

先理解下面两个概念:

依赖倒置有如下5条概念:

  1. 高层模块不应该依赖低层模块,二者都应该依赖其抽象
  2. 抽象不应该依赖细节,细节应该依赖抽象
  3. 依赖倒转(倒置)的中心思想是面向接口编程
  4. 依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。
  5. 使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成

先了解什么意思,后必须记熟这5条概念,很重要的!! (我觉得这5条很白话文了,如果你还是不理解,建议做一个 Asp.Net Core Web Api 仓储模式 项目,这仓储模式里面用到的就是:面向接口编程的,里面用的这个模式太明显了)

不理解的,先看下面演示 !

 

演示

第一版,我们很传统的写法方式:

Persion _persion = new Persion();
_persion.receive(new Email());

class Email
{
    public string getInfo()
    {
        return $"电子邮件信息:hello,world.";
    }
}

// 完成 Persion 接收消息的功能
class Persion
{
    // 这里依赖了Email这个类(即:细节、实现)
    public void receive(Email email)
    {
        Console.WriteLine(email.getInfo());
    }
}

上面代码中,Persion类中强依赖了 Email 类(细节),如果下次我换成 接收WeChat类 呢?肯定是 需要在 Persion 类中增加相应的方法了吧;

我们思考下,依赖倒置原则是:面向接口编程,依赖的是抽象,而不是具体的实现,上面代码中,我们可以把依赖的细节(),改为依赖的是一个抽象;

即:新增一个抽象接口 IReceiver,表示接收者,这样Persion 类与接口发生了依赖;

因为 Email, WeiXin 等属于接收的范围,他们各自实现IReceiver接口就ok,这样我们就符合了依赖倒转原则;

Persion _persion = new Persion();
_persion.receive(new Email());
_persion.receive(new WeChat());


interface IReceiver
{
    public string getInfo();
}

class Email : IReceiver
{
    public string getInfo()
    {
        return $"电子邮件信息:hello,world.";
    }
}
class WeChat : IReceiver
{
    public string getInfo()
    {
        return $"微信信息:hello,kiki.";
    }
}
class Persion
{
    // 这里,我们是第接口的依赖了
    public void receive(IReceiver receiver)
    {
        Console.WriteLine(receiver.getInfo());
    }
}

 

依赖关系传递的三种方式和应用案例

接口传递

class Changhong : ITV
{
    public void play()
    {
        Console.WriteLine("打开长虹电视");
    }
}
public static void Main(string[] args)
{
    OpenAndClose openAndClose =new OpenAndClose();
    openAndClose.open(new Changhong());
}

// 方式1:通过接口传递实现依赖
// 开关的接口
interface IOpenAddClose
{
    public void open(ITV tv);   // 抽象方法、接收接口
}

interface ITV
{
    public void play();
}

class OpenAndClose : IOpenAddClose
{
    // 实现接口
    public void open(ITV tv)
    {
        tv.play();
    }
}

  

构造方法传递(超常见)

class Changhong : ITV
{
    public void play()
    {
        Console.WriteLine("打开长虹电视");
    }
}
public static void Main(string[] args)
{
    OpenAndClose openAndClose =new OpenAndClose(new Changhong());
    openAndClose.open();
}

// 方式1:通过接口传递实现依赖
// 开关的接口
interface IOpenAddClose
{
    public void open();   // 抽象方法、接收接口
}

interface ITV
{
    public void play();
}

class OpenAndClose : IOpenAddClose
{
    private readonly ITV _tv;

    public OpenAndClose(ITV tv)
    {
        _tv = tv;
    }
    // 实现接口
    public void open()
    {
        _tv.play();
    }
}

 

Setter传递(不常见)

class Changhong : ITV
{
    public void play()
    {
        Console.WriteLine("打开长虹电视");
    }
}
public static void Main(string[] args)
{
    OpenAndClose openAndClose =new OpenAndClose();
    openAndClose.setTv(new Changhong());
    openAndClose.open();
}

// 方式1:通过接口传递实现依赖
// 开关的接口
interface IOpenAddClose
{
    public void open();   // 抽象方法、接收接口

    public void setTv(ITV tv);
}

interface ITV
{
    public void play();
}

class OpenAndClose : IOpenAddClose
{
    private ITV _tv;

    public void setTv(ITV tv)
    {
        this._tv = tv;
    }
    // 实现接口
    public void open()
    {
        _tv.play();
    }
}

 

注意和细节

  1. 低层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好;
  2. 变量的声明类型尽量是抽象类或接口, 这样我们的变量引用和实际对象间,就存在一个缓冲层,利于程序扩展和优化;(这句话不太好理解,看下面解释)
  3. 继承时遵循里氏替换原则 (这个下一节就说到了)

第2点 解释:假设,有 类A 继承 抽象接口B,那么存在:B b = new A();  b变量作为缓冲层,如果有 类C 继承至 抽象接口B,那么也可以: B b = new C(),即:

interface B{}
class A: B{}
class C: B{}
B b = new A();
b = new C();

// b变量就是一个缓冲层的意思,在 B 和 A 或者 B 和 C 之间

还是不懂的话,建议先放一放,做一些 面向接口编程 的项目后,在来这里回顾一下就行了;

 

这章其实有一点点难以理解,但是你迟早会看懂这个的,因为目前web的后端开发的的项目中,都用到了这个原则,比如 Asp.NET Core 的仓储模式 ;

好了,下一章,里氏替换原则 ,走起~

标签:原则,0x04,void,接口,tv,ITV,new,设计模式,public
来源: https://www.cnblogs.com/abc1069/p/16089268.html