设计模式之六大原则之依赖倒置原则

1. 定义

        依赖倒置原则(Dependence Inversion Principle    DIP):在程序设计时,高层模块不应该依赖于低层模块,二者应该通过抽象依赖,即依赖抽象,而不是依赖细节,换言之,程序设计应对接口编程,而不是针对实现编程。即包含以下三层含义:

        1)高层模块不应该依赖低层模块,两者都应该依赖其抽象;

        2)抽象不应该依赖细节;

        3)细节应该依赖抽象

        每一个逻辑的实现都是由原子逻辑组成的,不可分割的原子逻辑就是低层模块,原子逻辑的再组装就是高层模块

        抽象就是指接口或抽象类,两者都是不能直接被实例化的;细节就是实现类,实现接口或继承抽象类而产生的类就是细节,其特点就是可以直接被实例化,也就是可以加上一个关键字new产生一个对象。

        依赖倒置原则在编程语言中表现就是:

        1)模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;

        2)接口或抽象类不依赖于实现类;

        3)实现类依赖接口或抽象类

2. 为什么要实现依赖倒置

        2.1 实现代码重用,避免大量重构代码,比如:当切换数据库时,我们无需考虑ui层和bll层,只需考虑dal层,无需重构代码
        2.2 可扩展性强,架构稳定
        2.3 类间的耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性

3.依赖的三种写法

3.1 构造函数传递依赖对象

        在类中通过构造函数声明依赖对象,按照依赖注入的说法,这种方式叫做构造函数注入

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace helloworld
{
    class Program
    {
        static void Main(string[] args)
        {
            biuck biuck = new biuck();
            Driver driver = new Driver(biuck);
            driver.drive();
        }

    }
    public interface IDriver
    {
        public void drive();
    }
    public interface ICar
    {
        //是汽车就应该能跑
        public void run();
    }
    public class Driver : IDriver
    {
        private ICar car;
        //构造函数注入
        public Driver(ICar _car)
        {
            this.car = _car;
        }
        //司机的主要职责就是驾驶汽车
        public void drive()
        {
            this.car.run();
        }
    }
    public class biuck : ICar
    {
        public void run()
        {
            Console.WriteLine("run");
        }
    }
}

3.2 Setter方法传递依赖对象

        在抽象中设置Setter方法声明依赖关系,依照依赖注入的说法,这是Setter依赖注入

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
namespace helloworld
{
    class Program
    {
        static void Main(string[] args)
        {
            biuck biuck = new biuck();
            Driver driver = new Driver();
            driver.setCar(biuck);
            driver.drive();
        }
    }
    public interface IDriver
    {
        public void drive();
        public void setCar(ICar car);
    }
    public interface ICar
    {
        //是汽车就应该能跑
        public void run();
    }
    public class Driver : IDriver
    {
        private ICar Car;
        public void drive()
        {
            this.Car.run();
        }

        public void setCar(ICar car)
        {
            this.Car = car;
        }
    }
    public class biuck : ICar
    {
        public void run()
        {
            Console.WriteLine("run");
        }
    }
}

3.3 接口声明依赖对象

        在接口的方法中声明依赖对象,该方法也叫做接口注入。

4.最佳实践

        依赖倒置原则是6个设计原则中最难以实现的原则,它是实现开闭原则的重要途径,依赖倒置原则没有实现,就别想实现对扩展开放,对修改关闭。在项目中,大家只要记住是“面向接口编程”就基本上抓住了依赖倒置原则的核心。

        依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合。需要遵循以下几个规则:

4.1 每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备

        这是依赖倒置的基本要求,接口和抽象类都是属于抽象的,有了抽象才可能依赖倒置。

4.2 变量的表面类型尽量是接口或者是抽象类

4.3 任何类都不应该从具体类派生

4.4 尽量不要覆写基类的方法

4.5 结合里氏替换原则使用

4. 如何实现依赖倒置

   3.1 从实现类与抽象类的角度进行分析,在运用具体实现类与实现抽象类时,需要保证引用“基类”之处可以修改成其子类;
   3.2 从层次关系角度进行分析,需要定义清晰的层次关系,使每个层次通过接口的方式进行;
   3.3 从对象构造角度进行分析,如果创建的是动态的对象,则使用依赖倒转,如果创建的是一些静态的具体类并且变化率很低,则无须创建基类去继承,换言之,当细节多变化时,则要使用依赖倒置,反之,后者。                       

4. 代码实现【来源于网络教程】

4.1 设计

4.2 DIP
 

using System;
using IBLL;
using Factory;
using IDAL;

namespace DIP
{
    class Program
    {
        static void Main(string[] args)
        {
            IStudentService studentService = SimpleFactory.CreateStudentService();
            AbstractPhone iphone = SimpleFactory.CreatePhoneService();
            studentService.Study();
            studentService.Play(iphone);
            Console.ReadKey();
        }
    }
}

4.3 BLL
 

using IBLL;
using IDAL;
using System;

namespace BLL
{
    /// <summary>
    /// 业务逻辑层,完成对业务逻辑的封装 
    /// </summary>
    public class StudentService : IStudentService
    {
        public override void Play(AbstractPhone phone)
        {
            phone.Call();
            phone.Text();
        }

        public override void Study()
        {
            Console.WriteLine("学习DIP,依赖倒置原则!");
        }
    }
}

4.3 DAL
 

using IDAL;
using System;

namespace DIP.DAL
{
    public class Honer:AbstractPhone
    {
        public override void Call()
        {
            Console.WriteLine("使用华为打电话");
        }

        public override void Text()
        {
            Console.WriteLine("使用华为写作业");
        }
    }
}
using IDAL;
using System;

namespace DIP.DAL
{
    public class Iphone : AbstractPhone
    {
        public override void Call()
        {
            Console.WriteLine("使用iphone打电话");
        }

        public override void Text()
        {
            Console.WriteLine("使用iphone写作业");
        }
    }
}

IBLL
 

using IDAL;

namespace IBLL
{
    public abstract class IStudentService
    {
        /// <summary>
        /// 学习
        /// </summary>
        public abstract void Study();
        /// <summary>
        /// 玩
        /// </summary>
       public abstract void Play(AbstractPhone phone);
    }
}

IDAL
 

namespace IDAL
{
    public abstract class AbstractPhone
    {
        public abstract void Call();
        public abstract void Text();
    }
}

SimpleFactory
 

using IBLL;
using System;
using System.Reflection;
using System.Configuration;
using IDAL;

namespace Factory
{
    /// <summary>
    /// 工厂类
    /// </summary>
    public class SimpleFactory
    {
        //读取配置文件
        private static string IStudentServiceAssembly = ConfigurationManager.AppSettings["IStudentServiceAssembly"];
        private static string PhoneServiceAssembly = ConfigurationManager.AppSettings["AbstractPhoneAssembly"];

        /// <summary>
        /// 反射
        /// </summary>
        /// <returns></returns>
        public static IStudentService CreateStudentService()
        {
            //加载程序集
            Assembly assembly = Assembly.Load(IStudentServiceAssembly.Split(',')[1]);
            Type type = assembly.GetType(IStudentServiceAssembly.Split(',')[0]);
            //获取实例
            return (IStudentService)Activator.CreateInstance(type);
        }
        public static AbstractPhone CreatePhoneService()
        {
            Assembly assembly = Assembly.Load(PhoneServiceAssembly.Split(',')[1]);
            Type type = assembly.GetType(PhoneServiceAssembly.Split(',')[0]);
            return (AbstractPhone)Activator.CreateInstance(type);
        }
    }
}

app.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
  <appSettings>
    <add key="IStudentServiceAssembly" value="DIP.BLL.StudentService,DIP.BLL"/>
    <add key="AbstractPhoneAssembly" value="DIP.DAL.Honer,DIP.DAL"/>
  </appSettings>
</configuration>


结果:

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值