PHP编程SOLID设计原则理解

面向对象编程和面向对象设计的五个基本原则:

  • 单一职责原则(Single Responsibility Principle)---使用依赖注入,各类执行各自功能,不因任何一个类变化产生变动
  • 开放封闭原则(Open Closed Principle) ---对扩展是开放的,对修改是封闭的
  • 里氏替换原则(Liskov Substitution Principle) ---灵活切换/替换类,而不修改更多的代码
  • 接口隔离原则(Interface Segregation Principle)---与接口产生依赖,而不与具体实现接口产生依赖
  • 依赖反转原则(Dependency Inversion Principle) ---高层次不依赖低层次代码,低层次代码依赖高层次代码

       在多人开发项目的时候,我是建议大家用同一种编程开发工具;程序员本身要遵从这五个原则,对之后的维护是非常方便的,虽然开发的时候麻烦了点,现在我详细用实例来分别解释五个原则。


单一职责原则

单一职责规定一个类有且仅有一个理由使其改变。换句话说各类执行各自功能,不因任何一个类变化产生变动

例如我们现在有个订单要退款,并且验证订单是否已退款

class orderProcessor
{

    public function doRefund(Order $order)
    {
        $result = $this->checkOrderHasRefund($order->id);
        if ($result)
            return false;
        
        //更新订单状态
        $this->db->update('order', ['id' => $id, 'status' => 0], ['status' => 1]);

        //调用退款请求
        
    }
    
    public function checkOrderHasRefund($id)
    {
        return $this->db->select('*')->from('order')->where(['status' => 1, 'id' => $id])->get()->row_array();
    }
}


这个类中使用到了数据库操作,这就是不符合单一职责原则,如果数据发生改变,如关系数据库换成非关系数据库呢,所以我们要把数据库操作抽离出来,如下:

class OrderModel
{
    public function checkOrderHasRefund($id)
    {
        return $this->db->select('*')->from('order')->where(['status' => 1, 'id' => $id])->get()->row_array();
    }

    public function updateOrderStatus($id, $status) {
        return $this->db->update('order', ['id' => $id, 'status' => 0], ['status' => $status]);
    }
}
class OrderProcessor
{
    public $orderModel;

    public function __construct(OrderModel $orderModel)
    {
        $this->orderModel = $orderModel;
    }

    public function doRefund(Order $order)
    {
        $result = $this->orderModel->checkOrderHasRefund($order->id);
        if ($result)
            return false;

        //更新订单状态
        $result = $this->orderModel->updateOrderStatus($order->id, 9);
        if (!$result) {
            return false;
        }

        //调用退款请求
    }

}

class OrderProcessor
{
    public $orderModel;

    public function __construct(OrderModel $orderModel)
    {
        $this->orderModel = $orderModel;
    }

    public function doRefund(Order $order)
    {
        $result = $this->orderModel->checkOrderHasRefund($order->id);
        if ($result)
            return false;

        //更新订单状态
        $result = $this->orderModel->updateOrderStatus($order->id, 9);
        if (!$result) {
            return false;
        }

        //调用退款请求
    }

}

这样使用依赖注入,各类执行各自功能,不因任何一个类变化产生变动。

 

开放封闭原则

       一个项目已经成型,后期的新增修改是十分令人头疼的事,在你修改代码的时候都有可能引入新bug,或者破坏原有的功能。这时开放封闭原则的设计,理想的情况下我们就可以避免这种情况的发生,快速修改现有的代码。用上面的代码举例子

$result = $this->orderModel->checkOrderHasRefund($id);
if ($result)
    return false;

这段代码是判断订单是否付款,如果后续出现新增的验证功能呢,比如三天前订单不可退款、哪种支付订单可退款等等,我们怎么可以做到再步修改原有的代码上进行扩展呢。我们可以新建一个接口

interface OrderValidatorInterface
{
    public function validate(Order $order);
}


我们可以把所有的验证订单都继承这个接口,RefundOrderValidate验证订单是否付款,OrderPayValidate验证订单支付方式

class RefundOrderValidate implements OrderValidatorInterface
{

    public function __construct(OrderModel $orderModel)
    {
        $this->orderModel = $orderModel;
    }

    public function validate(Order $order)
    {
        return  $this->orderModel->checkOrderHasRefund($order->id);
    }

}
class OrderPayValidate implements OrderValidatorInterface
{

    public function __construct(OrderModel $orderModel)
    {
        $this->orderModel = $orderModel;
    }

    public function validate(Order $order)
    {
        $data = $this->orderModel->payMethod($order->id);
        if ($data['pat_type'] == $order->pay_type)
            return true;
        else
            return false;
    }

}
class OrderPayValidate implements OrderValidatorInterface
{

    public function __construct(OrderModel $orderModel)
    {
        $this->orderModel = $orderModel;
    }

    public function validate(Order $order)
    {
        $data = $this->orderModel->payMethod($order->id);
        if ($data['pat_type'] == $order->pay_type)
            return true;
        else
            return false;
    }

}
class OrderModel
{
    public function checkOrderHasRefund($id)
    {
        return $this->db->select('*')->from('order')->where(['status' => 1, 'id' => $id])->get()->row_array();
    }

    public function updateOrderStatus($id, $status)
    {
        return $this->db->update('order', ['id' => $id, 'status' => 0], ['status' => $status]);
    }

    public function payMethod($id){
        return $this->db->select('pay_type')->from('order')->where(['status' => 1, 'id' => $id])->get()->row_array();
    }
}


现在有两个类来实现OrderValidatorInterface接口,那我们就可以在OrderProcessor中使用他们了

class OrderProcessor
{

    public function __construct(OrderModel $orderModel, array $validators = [])
    {
        $this->orderModel = $orderModel;
        $this->validators = $validators;
    }

    public function doRefund(Order $order)
    {
        
        foreach ($this->validators as $validator){
            $res = $validator->validate();
            if (!$res)
                return false;
        }
        
        //更新订单状态
        $result = $this->orderModel->updateOrderStatus($order->id, 9);
        if (!$result) {
            return false;
        }

        //调用退款请求
    }

}

之后如果再有其他的规则验证,我们只有新增继承OrderValidatorInterface的类,就可以了而步修改原有的代码。

对开发封闭原则可以理解为:对扩展是开放的,对修改是封闭的。

 

里氏替换原则

里氏替换原则规定对象可以被其子类的实例所替换,并且不会影响导现有程序的正确性。

这里我就讲下这个里氏替换原则的意思,如果一个类使用到了某个接口来实现,那么一定可以通过该接口的其它实现来替换它,而不做出任何修改。这句话有点绕不好理解,看一下代码来帮助你理解

class OrderProcessor
{

    public function __construct(OrderModel $orderModel, LogInterface $repository, array $validators = [])
    {
        $this->orderModel = $orderModel;
        $this->validators = $validators;
        $this->repository = $repository;
    }

    public function doRefund(Order $order)
    {
        //记录日志
        $this->repository->log('order_log', '订单退款操作记录');

        foreach ($this->validators as $validator) {
            $res = $validator->validate();
            if (!$res)
                return false;
        }

        //更新订单状态
        $result = $this->orderModel->updateOrderStatus($order->id, 9);
        if (!$result) {
            return false;
        }

        //调用退款请求
    }

}

 

interface LogInterface
{
    public function doLog($file, $text);
}
class  FileLog implements LogInterface
{
    public function doLog($file, $text)
    {
        file_put_contents($file, $text);
    }
}
class LogModel implements LogInterface
{
    protected  $connect;

    public function connect(DatabaseConnector $connector)
    {
        $this->connect = $connector;
    }

    public function doLog($file, $text)
    {
        $this->connect->insert('log', ['file' => $file, 'text' => $text]);
    }
}

我们在orderProcessor中新增日志,和注入接口$repository,这个接口我们可以是LogModel或者FileLog,可以随意可替换的而不修改orderProcessor中的代码。

 

接口隔离原则

接口隔离原则规定不强制接口的实现不依赖它不是用的方法。意思是说在一个inerface中定义了几个function,依赖这个inteface的子类不应该强制必须实现interface中的function,而是应该用更细小的划分创建inerface。例如PHP自带的SessionHandlerInterface.php

interface SessionHandlerInterface {
    public function close();
    public function destroy($sessionId);
    public function gc($maxLifetime);
    public function open($savePath, $name);
    public function read($sesssionId);
    public function write($sessionId, $sessionData);
}

这个类是定义了要实现会话处理器必须要实现的几个方法,默认情况下都是使用文件缓存来实现的,如果替换成Redis呢,在Redis中有自带的过期缓存回收,不会使用到gc。从这个方面上我们可以把SessionHandlerInterface 颗粒化

interface GarbageCollectorInterface 
{
    public function gc($maxLifetime);
}

有了这个我们就不用去依赖整个会话处理器。

 

依赖反转原则

依赖反转其实是很好理解的,是对代码的分层,高层次和低层次;程序设计的时候高层次代码不依赖低层次代码。

比如我们现在要做一个根据id查询用户信息的接口

interface UserInterface
{
    public function findUserById($id);
}

class RedisUserProvider implements UserInterface
{
    protected $redis;
    
    public function __construct(RedisConnection $redis)
    {
        $this->redis = $redis;
    }
    
    public function findUserById($id) {
        return $this->redis->get('user_' . $id);
    }
}

class User
{
    public function __construct(UserInterface $users)
    {
        $this->users = $users;
    }
    
    public function userInfo ($id) {
        return $this->users->findUserById($id);
    }
}

这段代码你有没有发现 User 这个类中注入的依赖不是 RedisUserProvider 而是 UserInterface这个就是低层依赖高层,这样我们从 Redis  中获取换成MYSQL中获取用户信息,就不会出现问题。

 

看完上面内容,是不是有中感觉五个规则互相存在联系,那就是了,程序设计如果有一个不符合规则,必定会引起其他规则的不符合,例如最后一个依赖反转规则不是低层次代码依赖高层次,就会违背里氏替换原来,就无法用MYSQL替换Redis。

最后以上代码只是帮组理解。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值