zoukankan      html  css  js  c++  java
  • 面向对象编程之开放闭合原理的

      开放封闭原则(OCP,Open Closed Principle)是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化、降低耦合,而开放封闭原则正是对这一目标的最直接体现。

      关于开放封闭原则,其核心的思想是:
      软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的
      因此,开放封闭原则主要体现在两个方面:
      对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
      对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
      “需求总是变化”、“世界上没有一个软件是不变的”,这些言论是对软件需求最经典的表白。从中透射出一个关键的意思就是,对于软件设计者来说,必须在不需要对原有的系统进行修改的情况下,实现灵活的系统扩展。而如何能做到这一点呢?
      只有依赖于抽象实现开放封闭的核心思想就是对抽象编程,而不对具体编程,因为抽象相对稳定。让类依赖于固定的抽象,所以对修改就是封闭的;而通过面向对象的继承和对多态机制,可以实现对抽象体的继承,通过覆写其方法来改变固有行为,实现新的扩展方法,所以对于扩展就是开放的。
      
      举个栗子:
      
     
      1.银行业务办理
       A.没有实现开放闭合原理的方式:
        
    public class BankProcess
        {
            public void Deposite(){}   //存款
            public void Withdraw(){}   //取款
            public void Transfer(){}   //转账
        }
    
        public class BankStaff
        {
            private BankProcess bankpro = new BankProcess();
            public void BankHandle(Client client)
            {
                switch (client .Type)
                {
                    case "deposite":      //存款
                        bankpro.Deposite();
                        break;
                    case "withdraw":      //取款
                        bankpro.Withdraw();
                        break;
                    case "transfer":      //转账
                        bankpro.Transfer();
                        break;
                }
            }
        }
    View Code

        目前设计中就只有存款,取款和转账三个功能,将来如果业务增加了,比如增加申购基金功能,理财功能等,就必须要修改BankProcess业务类。我们分析上述设计就能发现不能把业务封装在一个类里面,违反单一职责原则,而有新的需求发生,必须修改现有代码则违反了开放封闭原则。

        那么,如何使代码耦合度更低?而不是牵一发儿动全身,前辈们已经给我们趟出了一些路子:将业务功能抽象为接口,当业务员依赖于固定的抽象时,对修改就是封闭的,而通过继承和多态继承,从抽象体中扩展出新的实现,就是对扩展的开放。

       B.实现了开放闭合原理的方式:

        public interface IBankProcess //首先声明一个业务处理接口
        {
            void Process();
        }
        public class DeposiProcess:IBankProcess
        {
            public void Process()         //办理存款业务
            {
                Console.WriteLine("Process Deposit");
            }
        }
        public class WithDrawProcess:IBankProcess
        {
            public void Process()        //办理取款业务
            {
                Console.WriteLine("Process WithDraw");
            }
        }
        public class TransferProcess:IBankProcess
        {
            public void Process()        //办理转账业务
            {
                Console .WriteLine ("Process Transfer");
            }
        }
        public class BankStaff
        {
            private IBankProcess  bankpro = null ;
            public void BankHandle(Client client)
            {
                switch (client .Type)
                {
                    case "Deposite":      //存款
                        userProc =new WithDrawUser();
                        break;
                    case "WithDraw":      //取款
                        userProc =new WithDrawUser();
                        break;
                    case "Transfer":      //转账
                        userProc =new WithDrawUser();
                        break;
                }
                userProc.Process();
            }
        }
    View Code

      银行工作人员:

    class BankStaff
    {
    private IBankProcess bankProc = null;
    public void HandleProcess(Client client)
    {
    bankProc = client.CreateProcess();
    bankProc.Process();
    }
    }
    View Code

      客户:

    class Client
    {
    private string ClientType;
    public Client(string clientType)
    {
    ClientType = clientType;
    }
    public IBankProcess CreateProcess()
    {
    switch (ClientType)
    {
    case "存款用户":
    return new DepositProcess();
    break;
    case "转账用户":
    return new TransferProcess();
    break;
    case "取款用户":
    return new DrawMoneyProcess();
    break;
    }
    return null;
    }
    }
    View Code

      我们办理业务的时候:

    class BankProcess
    {
    public static void Main()
    {
    EasyBankStaff bankStaff = new BankStaff();
    bankStaff.HandleProcess(new Client("转账用户"));
    }
    }
    View Code

      当有新的业务增加时,银行经理不必为重新组织业务流程而担忧,你只需为新增的业务实现IBankProcess接口:

    class FundProcess : IBankProcess
    {
    //IBankProcess Members
    #region IBankProcess Members
    public void Process()
    {
    // 办理基金业务
    throw new Exception("The method or operation is not implemented.");
    }
    #endregion
    }
    View Code

      新的设计遵守了开放封闭原则,在需求增加时只需要向系统中加入新的功能实现类,而原有的一切保持封闭不变的状态,这就是基于抽象机制而实现的开放封闭式设计。

      2.系统配置文件读取

      配置文件有多重文件格式:php,ini,json,xml等

      我们的原则:封装变化,对扩展开放,对修改闭合

      首先,增加抽象接口:

    <?php  
    interface Configuration{  
        public function toArray($configFilePath);  
    }  
    ?>
    View Code

      然后,具体实现类继承接口:

      phpConfiguration.php

    <?php  
    require_once "configuration.php";  
    class phpConfiguration implements Configuration{  
        public function toArray($configFilePath){  
            $config = require_once $configFilePath;  
            return $config;  
        }  
    }  
    ?>
    View Code

      jsonConfiguration.php

    <?php  
    require_once "configuration.php";  
    class JsonConfiguration implements Configuration{  
        public function toArray($configFilePath){  
            return json_decode(file_get_contents($configFilePath), true);  
        }  
    }  
    ?>
    View Code

      给出config.php配置工具类:

    <?php
    require_once "phpConfiguration.php";
    class config{
        var $configFilePath;
        //定义一个构造方法初始化赋值
        function __construct($configFilePath) {
            $this->configFilePath=$configFilePath;
        }
        public function configToArray($configuration){
            $result =$configuration->toArray($this->configFilePath);
            $config = is_array($result) ? $result : array();
            return $config;
        }
    
    }
    ?>
    View Code

    完整例子下载:配置文件开放闭合原则实例

      3.媒体播放器实例

      以电脑中的多媒体播放软件为例,作为一款播放器,应该具有一些基本的、通用的功能,如打开多媒体文件、快进、音量调剂等功能。不论在什么平台下,遵循这个原则设计的播放器都应该有统一的操作规划和操作习惯,都应该保证操作者能够很快上手。

      首先,定义一个抽象业务接口:

    <?php
    interface process  
    {  
          public function process();  
    }  
    ?>
    View Code

      然后,对此接口进行拓展,实现解码和输出的功能:

    <?php
    class playerencode implements process   
    {  
          public function process()  
          {  
                echo "encode
    ";  
          }  
    }  
      
    class playeroutput implements process   
    {  
          public function process()  
          {  
                echo "output";  
          }  
    }  
    ?>
    View Code

      接下来定义播放器的线程调度处理器:

    class playProcess  
    {  
          private $message = null;  
          public function __construct()  
          {  
      
          }  
          public function callback(event $event) {  
                $this->message = $event->click();  
                if($this->message instanceof process) {  
                      $this->message->process();  
                }  
          }  
    }  
    View Code

      然后,在定义一个mp4类,这个类相对是封闭的,其中定义时间的处理逻辑。

    class Mp4  
    {  
          public function work() {  
                $playProcess = new playProcess();  
                $playProcess->callback(new event('encode'));  
                $playProcess->callback(new event('output'));  
          }  
    }  
    View Code

      最后,增加一个事件分拣的处理类,此类负责对事件进行分拣,判断用户或内部行为,供播放器的线程调度器调度。

    class event  
    {  
          private $m;  
          public function __construct($me)  
          {  
                $this->m = $me;  
          }  
            
          public function click() {  
                switch ($this->m) {  
                      case 'encode':  
                            return new playerencode();  
                      break;  
                      case 'output':  
                            return new playeroutput();  
                      break;  
                }  
          }  
    }  
    View Code

    完整例子下载:播放器开放闭合原则实例

    三个栗子,应该大概能理解开放闭合原理了。

    总结一下

    实现开发-封闭原则的思想就是对抽象编程,而不是具体编程,因为抽象相对稳定,让类依赖于固定的抽象,这样的修改时封闭的;而通过对象的继承和多态机制,可以实现对抽象类的继承,通过覆盖其方法来修改固有行为,实现新的拓展方法,所以对于拓展就是开放的。

    (1)在设计方面充分利用“抽象”和“封装”的思想

    一方面也就是在软件系统中找到各种可能的“可变因素”,并将之封装起来

    另一方面,一种可变因素不应当散落在不同代码模块中,而应当被封装到一个对象中。

    (2)在系统功能编程实现方面利用面向接口的编程

    当需求发生变化时,可以提供接口新的实现类,以求适应变化

    面向接口编程要求功能类实现接口,对象声明为借口类型。

    参考文献:

    https://yq.aliyun.com/articles/45638  设计模式六大原则——开放封闭原则(OCP)

    http://blog.csdn.net/u011250882/article/details/47358519  设计原则之开放闭合原则(OCP)

    http://blog.csdn.net/dnidong/article/details/57401935  php面向对象的设计原则之开发-封闭原则(OCP)

  • 相关阅读:
    Unique Binary Search Trees(dp)
    Binary Tree Inorder Traversal
    Reverse Linked List II
    O​r​a​c​l​e​1​1​g​自​带​的​S​Q​L​ ​d​e​v​e​l​o​p​e​r​无​法​打​开​解​决​
    英语飙升的好方法
    MyEclipse加入jquery.js文件missing semicolon的错误
    js,jq获取手机屏幕分辨率的宽高
    给标签元素设固定宽高,内部添加滚动条显示
    解决手机端点击input的时候,页面会放大
    支付宝异步回调验证签名
  • 原文地址:https://www.cnblogs.com/miketwais/p/OOP_OCP.html
Copyright © 2011-2022 走看看