面向对象编程之开放闭合原理的

简介:   开放封闭原则(OCP,Open Closed Principle)是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化、降低耦合,而开放封闭原则正是对这一目标的最直接体现。  关于开放封闭原则,其核心的思想是:  软件实体应该是可扩展,而不可修改的。

  开放封闭原则(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\r\n";  
      }  
}  
  
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)

目录
相关文章
|
2月前
|
设计模式 API 数据安全/隐私保护
探索设计模式的魅力:外观模式简化术-隐藏复杂性,提供简洁接口的设计秘密
外观模式是一种关键的设计模式,旨在通过提供一个简洁的接口来简化复杂子系统的访问。其核心价值在于将复杂的内部实现细节封装起来,仅通过一个统一的外观对象与客户端交互,从而降低了系统的使用难度和耦合度。在软件开发中,外观模式的重要性不言而喻。它不仅能够提高代码的可读性、可维护性和可扩展性,还能促进团队间的协作和沟通。此外,随着业务需求和技术的发展,外观模式能够适应变化,通过修改外观对象来灵活调整客户端与子系统之间的交互方式。总之,外观模式在软件设计中扮演着举足轻重的角色,是构建高效、稳定且易于维护的软件系统的关键
72 1
探索设计模式的魅力:外观模式简化术-隐藏复杂性,提供简洁接口的设计秘密
|
2月前
|
C++
关系表达式:编程中的比较利器
在编程中,关系表达式扮演着至关重要的角色。它们允许我们比较两个或多个值,并基于这些比较的结果来执行相应的操作。关系表达式通过返回布尔值(真或假)来告诉我们两个值之间的关系,从而帮助我们在程序中做出决策。
16 0
|
5月前
|
设计模式
二十三种设计模式全面解析-深入探讨状态模式的高级应用技术:释放对象行为的无限可能
二十三种设计模式全面解析-深入探讨状态模式的高级应用技术:释放对象行为的无限可能
|
11月前
|
存储 Java 程序员
【C#本质论 六】类-从设计的角度去认知(封装)(上)
【C#本质论 六】类-从设计的角度去认知(封装)(上)
88 0
|
11月前
|
编译器 C#
【C#本质论 六】类-从设计的角度去认知(封装)(下)
【C#本质论 六】类-从设计的角度去认知(封装)(下)
69 0
|
设计模式 缓存 JavaScript
你不知道的javascript设计模式(十七) ----编程设计原则和设计规则
你不知道的javascript设计模式(十七) ----编程设计原则和设计规则
73 0
编程基本功:典型的柳氏风格命名一例
编程基本功:典型的柳氏风格命名一例
52 0
编程基本功:典型的柳氏风格命名一例
|
Java C++
保守VS开放?看清封装对象属性 | 带你学《Java面向对象编程》之四
高楼万丈,起于平地。本节通过对比正反几个实例剖析了封装对象属性的必要性,介绍了进行封装的基本原则。
保守VS开放?看清封装对象属性   |  带你学《Java面向对象编程》之四
|
C#
艾伟:Silverlight 里如何实现隐式样式,ImplicitStyleManager 的实现思想
在 WPF 中,我们可以方便的在全局范围定义一个样式,就可以应用到所有这种类型的对象,这就是所谓的隐式样式(implicit Style),比如: WPF中定义样式 Button aButton b 这样之后,两个按钮就都变成了浅蓝色的背景。
786 0
|
UED
五个案例简述Web设计原则:通用一致
《Web设计指南》是专门为广大Web内容生态提供一套简单实用的设计指南,目的是提升设计与开发的效率及质量,为广大用户提供优质的用户体验。 Web内容数以千亿涵盖生活各个方面,除了稳定流畅的浏览,优质的内容及服务,也需要高质量的交互及视觉体验。
887 0