• 面向对象设计原则之依赖倒转原则


    转载来自:https://blog.csdn.net/lovelion/article/details/7562783

    如果说开闭原则是面向对象设计的目标的话,那么依赖倒转原则就是面向对象设计的主要实现机制之一,它是系统抽象化的具体实现。依赖倒转原则是Robert C. Martin在1996年为“C++Reporter”所写的专栏Engineering Notebook的第三篇,后来加入到他在2002年出版的经典著作“Agile Software Development, Principles, Patterns, and Practices”一书中。依赖倒转原则定义如下:

    依赖倒转原则(Dependency Inversion Principle, DIP):抽象不应该依赖于细节,细节应当依赖于抽象。换言之,要针对接口编程,而不是针对实现编程。

    依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法

    在引入抽象层后,系统将具有很好的灵活性,在程序中尽量使用抽象层进行编程,而将具体类写在配置文件中,这样一来,如果系统行为发生变化,只需要对抽象层进行扩展,并修改配置文件,而无须修改原有系统的源代码,在不修改的情况下来扩展系统的功能,满足开闭原则的要求。

    在实现依赖倒转原则时,我们需要针对抽象层编程,而将具体类的对象通过依赖注入(DependencyInjection, DI)的方式注入到其他对象中,依赖注入是指当一个对象要与其他对象发生依赖关系时,通过抽象来注入所依赖的对象。常用的注入方式有三种,分别是:构造注入,设值注入(Setter注入)和接口注入。构造注入是指通过构造函数来传入具体类的对象,设值注入是指通过Setter方法来传入具体类的对象,而接口注入是指通过在接口中声明的业务方法来传入具体类的对象。这些方法在定义时使用的是抽象类型,在运行时再传入具体类型的对象,由子类对象来覆盖父类对象。

    扩展
    
    软件工程大师Martin Fowler在其文章Inversion of Control Containers and the Dependency Injection pattern中对依赖注入进行了深入的分析,参考链接:
    
    http://martinfowler.com/articles/injection.html

    下面通过一个简单实例来加深对依赖倒转原则的理解:

    Sunny软件公司开发人员在开发某CRM系统时发现:该系统经常需要将存储在TXT或Excel文件中的客户信息转存到数据库中,因此需要进行数据格式转换。在客户数据操作类中将调用数据格式转换类的方法实现格式转换和数据库插入操作,初始设计方案结构如图1所示:

     

    图1 初始设计方案结构图

    在编码实现图1所示结构时,Sunny软件公司开发人员发现该设计方案存在一个非常严重的问题,由于每次转换数据时数据来源不一定相同,因此需要更换数据转换类,如有时候需要将TXTDataConvertor改为ExcelDataConvertor,此时,需要修改CustomerDAO的源代码,而且在引入并使用新的数据转换类时也不得不修改CustomerDAO的源代码,系统扩展性较差,违反了开闭原则,现需要对该方案进行重构。

    在本实例中,由于CustomerDAO针对具体数据转换类编程,因此在增加新的数据转换类或者更换数据转换类时都不得不修改CustomerDAO的源代码。我们可以通过引入抽象数据转换类解决该问题,在引入抽象数据转换类DataConvertor之后,CustomerDAO针对抽象类DataConvertor编程,而将具体数据转换类名存储在配置文件中,符合依赖倒转原则。根据里氏代换原则,程序运行时,具体数据转换类对象将替换DataConvertor类型的对象程序不会出现任何问题。更换具体数据转换类时无须修改源代码,只需要修改配置文件;如果需要增加新的具体数据转换类,只要将新增数据转换类作为DataConvertor的子类并修改配置文件即可,原有代码无须做任何修改,满足开闭原则。重构后的结构如图2所示:

    图2重构后的结构图

    在上述重构过程中,我们使用了开闭原则、里氏代换原则和依赖倒转原则,在大多数情况下,这三个设计原则会同时出现,开闭原则是目标,里氏代换原则是基础,依赖倒转原则是手段,它们相辅相成,相互补充,目标一致,只是分析问题时所站角度不同而已。

    扩展

    Robert C. Martin(Bob大叔):Object Mentor公司总裁,面向对象设计、模式、UML、敏捷方法学和极限编程领域内的资深顾问。

     


    再上两张Bob大叔的“玉照”,:

     

     

    【作者:刘伟 http://blog.csdn.net/lovelion】

    精彩评论:

    虽然我还看不懂

    • 开闭原则是目标,里氏代换原则是基础,依赖倒转原则是手段
      第一要明确,所有的原则都是为了实现面向对象设计的可扩展性,可复用性,可维护性(对原有代码不要进行修改)而定义的
      一个已有的代码模块,需要实现可扩展性,需要对外保持开放
      为了实现可复用性,需要保持独立(单一职责,高内聚,低耦合);
      为了实现可维护性,需要对内封闭(对已有代码模块不要进行修改)。
      开闭原则(Open-Closed Principle, OCP):一个软件实体应当对扩展开放(可扩展性),对修改关闭(可维护性)。即软件实体应尽量在不修改原有代码的情况下进行扩展。所以说开闭原则是目的。
      第二,为了实现开闭原则(可扩展性,可维护性和复用性)在最初就需要对代码模块进行抽象化设计(抽象化是实现开闭原则的关键);面向对象思想中的抽象化是指把现实中一类具有相同属性,行为的事物归类的方法。 抽象 ---对同一类对象的共同属性和行为进行概括,形成类。 有:数据抽象(属性或状态)、代码抽象(某类对象的共有的行为特征或功能)。抽象的实现是:类 大牛们就想在Java、C#等编程语言中,可以为系统定义一个相对稳定的抽象层,而将不同的实现行为移至具体的实现层中完成。在很多面向对象编程语言中都提供了接口、抽象类等机制,可以通过它们定义系统的抽象层,再通过具体类来进行扩展。如果需要修改系统的行为,无须对抽象层进行任何改动,只需要增加新的具体类来实现新的业务功能即可,实现在不修改已有代码的基础上扩展系统的功能,达到开闭原则的要求。具体操作作:通过针对抽象基类编程(业务逻辑关系的建立),具体运行时代换具体子类对象执行,可以达到开闭原则的目的,
      该实现过程就是里氏代换原则定义本身,所以说里氏代换原则是理论基础! 通过里氏代换原则的操操作过程,大牛们总结出抽象不依赖于细节,细节应该依赖于抽象的依赖倒转原则。具体就是变量、参数、方法返回、数据类型转换等都要用抽象定义声明,再通过依赖注入(构造注入、设值注入和接口注入)或依赖获取的方式将具体对象注入到有依赖关系的对象中。所以说依赖倒转原则是实现目的手段! 在实现针对抽象编程的实践中总结出接口隔离原则(Interface Segregation Principle, ISP):使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。
    • 每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干。也为实现可复用性打下基础; 在具体实现层(抽象的实现)实践中总结出单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。(实现可复用性,可维护性)
      在使用依赖倒转原则的实践中引入依赖注入。 用稍微正式一点的语言,定义依赖注入产生的背景缘由和依赖注入的含义。 随着面向对象分析与设计的发展,一个良好的设计,核心原则之一就是将变化隔离(【不变部分】 (可复用性,可维护性)【变化部分】(可扩展性)),使得变化部分发生变化时,不变部分不受影响(这也是OCP的目的)。 为了做到这一点,要利用面向对象中的多态性(同一名称,不同的功能实现方式。目的:达到行为标识统一,减少程序中标识符的个数。),使用多态性后,客户类不再直接依赖服务类,而是依赖于一个抽象的接口,这样,客户类就不能在内部直接实例化具体的服务类。但是,客户类在运作中又客观需要具体的服务类提供服务,因为接口是不能实例化去提供服务的。就产生了“客户类不准实例化具体服务类”和“客户类需要具体服务类”这样一对矛盾。为了解决这个矛盾,开发人员提出了一种模式:客户类(如上例中的Role)定义一个注入点(Public成员Weapon),用于服务类(实现IAttackStrategy的具体类,如WoodSword、IronSword和MagicSword,也包括以后加进来的所有实现IAttackStrategy的新类)的注入,而客户类的客户类(Program,即测试代码)负责根据情况,实例化服务类,注入到客户类中,从而解决了这个矛盾。
  • 相关阅读:
    jquery mobile 按钮部件(包含图标的使用)
    jquery mobile页面切换效果(Flip toggle switch)(注:jQuery移动使用的数据属性的列表。 )
    jquery mobile基本结构搭建
    xshell连接虚拟机
    virtualbox安装ubantu系统
    python对象关系映射ORM
    javascript的reverse,sort方法,concat方法
    Array对象的方法push,pop unshift,shift
    javascript的Array对象
    javascript的String字符串对象
  • 原文地址:https://www.cnblogs.com/Galesaur-wcy/p/15511001.html
Copyright © 2020-2023  润新知