设计模式-原理-依赖倒置原则

1.原文:High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions。

2.直译:高水平(层次)的模块不应该依赖底水平(层次)的模块,两者都应该依赖抽象。抽象不应该依赖具体实现,具体实现应该依赖抽象。

3.理解:

(1)有依赖关系的两个类如果有层次关系,比如业务类->基础类,这时不能直接调用.应该面对一个抽象编程,业务类调用这个抽象类.

(2)有实现关系的两个类,抽象类(接口也算)->实现类,抽象类不能依赖一个具体类. 如果是一个独立的实现类没有抽象意义的,也应该依赖抽象

来段儿代码吧.我想了半天确实是有意义的.

<?php
//实现一个发布功能
/*
抽象类:发布
*/
Abstract class APublish{
    abstract function doSomething(Wx $content);
}
/*
实现类:发布
*/
class Publish{
    function doSomething(Wx $channelContent){
        //... 发布相关的功能
        echo '统一加上公司水印';
        //调用api
        $channelContent -> do1();
    }
}
/*
底层类:微信的发布api
*/
class Wx{
    function do1(){
        echo '微信处理';
    }
}

这个例子非常好.高层是发布,底层是api.业务功能依赖底层封装的sdk之类的基础模块.

第一:高层依赖底层的具体实现,并不是依赖一个抽象.因为对于Publish::doSomething(Wx $channelContent)明确要求要传递一个实现类的对象过来

第二:

(1)抽象依赖具体实现,

对于APublish::doSomething(Wx $channelContent)的实现依赖一个具体的实现(细节)

(2)具体实现没有依赖抽象,也依赖了具体实现

Wx类的实例,具体实现Publish::doSomething(Wx $channelContent)也就依赖了另一个具体实现,没有依赖抽象

(其实这是必然的,抽象类A依赖的是具体实现(细节)B,具体实现A1不也得依赖具体实现(细节)B).

改一下

<?php
/*
抽象一个业务渠道出来
*/
interface IChannelContent{
    function deal();
}
/*
还是那个发布类,原来是依赖具体实现现在依赖一个抽象的业务渠道概念
*/
Abstract class APublish{
    abstract function doSomething(IChannelContent $content);
}
/*
实现类也得改
*/
class Publish{
    function doSomething(IChannelContent $channelContent){
        //... 发布相关的功能
        echo '统一加上公司水印';
        //调用api
        $channelContent -> deal();
    }
}

/*
底层类:微信的发布api,这个是不需要变化的,可能你也变不了是一个公共模块
*/
class Wx{
    function do1(){
        echo '微信处理';
    }
}

/*
 * 一个业务系统根据业务接口封装出来的使用类,区分开底层sdk.
 * 注意:这时候理解Wx是一个很难变化的实现类,基本不会变化.类似固定的数据类型了(int,string,array这种)
 * */
class WxChannel implements IChannelContent{
    protected $api;
    function __construct(Wx $wx)
    {
        $this->api = $wx;
    }

    function deal(){
        $this->api->do1();
    }    
}

 

但是有什么用呢?

任何抽象都能应对那个抽象目标的变化.

其实第一种写法可以应对doSomethinig处理方式的改变,比如统一处理添加了一个新能力 " 加上发布时间"这种,也不是不能用.

但是你从设计角度来说.在核心业务中调用基础功能,应该维护一个基础功能的抽象,称之为防腐层.才能有效的面对不可控的变化(别人写的你不能改).这是一行还好.如果散到代码里面到处都是,要是改就很闹心了.(给你个需求,记录一下调用的log!)

改完以后其实添加了另一个好处,突然发现渠道可以增加了

class Weibo{
    function deal1(){
        echo '微博处理';
    }
}
class Weibo implements IChannelContent{
    protected $api;
    function __construct(Weibo $weibo)
    {
        $this->api = $weibo;
    }

    function deal(){
        $this->api->deal1();
    }
}

对于认为Wx是基础类型的问题,如果有个interface IWx,感觉最开始的写法也是可以接受的,并不违反依赖倒置原则,但是IWx是个宽接口,而且不是防腐层抽象.也不推荐这么写

<?php
interface IWx{
    function do1();
    function do2();
    function do3();
    //...好多好多api
}
class Wx implements IWx{
    function do1(){
        echo '微信处理1';
    }
    function do2(){
        echo '微信处理2';
    }
    function do3(){
        echo '微信处理3';
    }
    //... 还得有实现
}
abstract class APublish{
    abstract function doSomething(IWx $wx);
}
class Publish{
    function doSomething(IWx $wx){
        //... 发布相关的功能
        echo '统一加上公司水印';
        //调用api
        $wx ->do1();
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值