zoukankan      html  css  js  c++  java
  • 设计模式

    设计模式简介

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理地运用设计模式可以完美地解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式都描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是设计模式能被广泛应用的原因。

    什么是 GOF(四人帮,全拼 Gang of Four)?

    在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。

    四位作者合称 GOF(四人帮,全拼 Gang of Four)。他们所提出的设计模式主要是基于以下的面向对象设计原则。

    • 对接口编程而不是对实现编程。
    • 优先使用对象组合而不是继承。

    设计模式的使用

    设计模式在软件开发中的两个主要用途。

    开发人员的共同平台

    设计模式提供了一个标准的术语系统,且具体到特定的情景。例如,单例设计模式意味着使用单个对象,这样所有熟悉单例设计模式的开发人员都能使用单个对象,并且可以通过这种方式告诉对方,程序使用的是单例模式。

    最佳的实践

    设计模式已经经历了很长一段时间的发展,它们提供了软件开发过程中面临的一般问题的最佳解决方案。学习这些模式有助于经验不足的开发人员通过一种简单快捷的方式来学习软件设计。

    设计模式的类型

    根据设计模式的参考书 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 中所提到的,总共有 23 种设计模式。这些模式可以分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)、行为型模式(Behavioral Patterns)。当然,我们还会讨论另一类设计模式:J2EE 设计模式。

    创建型模式

    工厂模式抽象工厂模式单例模式建造者模式原型模式

    结构型模式

    适配器模式桥接模式过滤器模式组合模式装饰器模式外观模式享元模式代理模式

    行为型模式

    责任链模式命令模式解释器模式迭代器模式中介者模式备忘录模式观察者模式状态模式空对象模式策略模式模板模式访问者模式

    J2EE 模式

    MVC 模式业务代表模式组合实体模式数据访问对象模式前端控制器模式拦截过滤器模式服务定位器模式传输对象模式

    下面用一个图片来整体描述一下设计模式之间的关系:

    设计模式之间的关系

    设计模式的六大原则

    1、开闭原则(Open Close Principle)

    开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

    2、里氏代换原则(Liskov Substitution Principle)

    里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

    3、依赖倒转原则(Dependence Inversion Principle)

    这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。

    4、接口隔离原则(Interface Segregation Principle)

    这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。

    5、迪米特法则,又称最少知道原则(Demeter Principle)

    最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

    6、合成复用原则(Composite Reuse Principle)

    合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。

    在这简单介绍几种:

    单例模式

    1. $_instance必须声明为静态的私有变量
    2. 构造函数和析构函数必须声明为私有,防止外部程序new 类从而失去单例模式的意义
    3. getInstance()方法必须设置为公有的,必须调用此方法 以返回实例的一个引用
    4. ::操作符只能访问静态变量和静态函数
    5. new对象都会消耗内存
    6. 使用场景:最常用的地方是数据库连接。
    7. 使用单例模式生成一个对象后, 该对象可以被其它众多对象所使用。
    8. 私有的__clone()方法防止克隆对象

    单例模式,使某个类的对象仅允许创建一个。构造函数private修饰, 
    申明一个static getInstance方法,在该方法里创建该对象的实例。如果该实例已经存在,则不创建。比如只需要创建一个数据库连接。

     1 <?php
     2 
     3 /**
     4  * Singleton class[单例模式]
     5  * @author ITYangs<ityangs@163.com>
     6  */
     7 final class Mysql
     8 {
     9 
    10     /**
    11      *
    12      * @var self[该属性用来保存实例]
    13      */
    14     private static $instance;
    15 
    16     /**
    17      *
    18      * @var mixed
    19      */
    20     public $mix;
    21 
    22     /**
    23      * Return self instance[创建一个用来实例化对象的方法]
    24      *
    25      * @return self
    26      */
    27     public static function getInstance()
    28     {
    29         if (! (self::$instance instanceof self)) {
    30             self::$instance = new self();
    31         }
    32         return self::$instance;
    33     }
    34 
    35     /**
    36      * 构造函数为private,防止创建对象
    37      */
    38     private function __construct()
    39     {}
    40 
    41     /**
    42      * 防止对象被复制
    43      */
    44     private function __clone()
    45     {
    46         trigger_error('Clone is not allowed !');
    47     }
    48 }
    49 
    50 // @test
    51 $firstMysql = Mysql::getInstance();
    52 $secondMysql = Mysql::getInstance();
    53 
    54 $firstMysql->mix = 'ityangs_one';
    55 $secondMysql->mix = 'ityangs_two';
    56 
    57 print_r($firstMysql->mix);
    58 // 输出: ityangs_two
    59 print_r($secondMysql->mix);
    60 // 输出: ityangs_two

    Test1.php

    1 <?php
    2 class Test1{
    3     static function test(){
    4         echo __FILE__;
    5     }

    Factory.php

    <?php
    class Factory{
        /*
         * 如果某个类在很多的文件中都new ClassName(),那么万一这个类的名字
         * 发生变更或者参数发生变化,如果不使用工厂模式,就需要修改每一个PHP
         * 代码,使用了工厂模式之后,只需要修改工厂类或者方法就可以了。
         */
        static function createDatabase(){
            $test = new Test1();
            return $test;
        }
    }

    Test.php

     1 <?php
     2 spl_autoload_register('autoload1');
     3 
     4 $test = Factory::createDatabase();
     5 $test->test();
     6 function autoload1($class){
     7     $dir  = __DIR__;
     8     $requireFile = $dir."\".$class.".php";
     9     require $requireFile;
    10 }

    观察者模式

    1:观察者模式(Observer),当一个对象状态发生变化时,依赖它的对象全部会收到通知,并自动更新。 
    2:场景:一个事件发生后,要执行一连串更新操作。传统的编程方式,就是在事件的代码之后直接加入处理的逻辑。当更新的逻辑增多之后,代码会变得难以维护。这种方式是耦合的,侵入式的,增加新的逻辑需要修改事件的主体代码。 
    3:观察者模式实现了低耦合,非侵入式的通知与更新机制。 

    定义一个事件触发抽象类。

    EventGenerator.php

    <?php
    require_once 'Loader.php';
    abstract class EventGenerator{
        private $observers = array();
        function addObserver(Observer $observer){
            $this->observers[]=$observer;
        }
        function notify(){
            foreach ($this->observers as $observer){
                $observer->update();
            }
        }
    }

    定义一个观察者接口

    Observer.php

    1 <?php
    2 require_once 'Loader.php';
    3 interface Observer{
    4     function update();//这里就是在事件发生后要执行的逻辑
    5 }
     1 <?php
     2 //一个实现了EventGenerator抽象类的类,用于具体定义某个发生的事件
     3 require 'Loader.php';
     4 class Event extends EventGenerator{
     5     function triger(){
     6         echo "Event<br>";
     7     }
     8 }
     9 class Observer1 implements Observer{
    10     function update(){
    11         echo "逻辑1<br>";
    12     }
    13 }
    14 class Observer2 implements Observer{
    15     function update(){
    16         echo "逻辑2<br>";
    17     }
    18 }
    19 $event = new Event();
    20 $event->addObserver(new Observer1());
    21 $event->addObserver(new Observer2());
    22 $event->triger();
    23 $event->notify();

     AbstractFactory(抽象工厂模式)

    有些情况下我们需要根据不同的选择逻辑提供不同的构造工厂,而对于多个工厂而言需要一个统一的抽象工厂:

     1 <?php 
     2 class System{} 
     3 class Soft{} 
     4 
     5 class MacSystem extends System{} 
     6 class MacSoft extends Soft{} 
     7 
     8 class WinSystem extends System{} 
     9 class WinSoft extends Soft{} 
    10 
    11 /** * AbstractFactory class[抽象工厂模式] * @author ITYangs<ityangs@163.com> */ interface AbstractFactory {
    12 public function CreateSystem(); 
    13 public function CreateSoft(); 
    14 } 
    15 
    16 class MacFactory implements AbstractFactory{ 
    17 public function CreateSystem(){ 
    18 return new MacSystem(); 
    19 } 
    20 public function CreateSoft(){ 
    21 return new MacSoft(); 
    22 } 
    23 } 
    24 class WinFactory implements AbstractFactory{ 
    25 public function CreateSystem(){ 
    26 return new WinSystem(); 
    27 } 
    28 public function CreateSoft(){ 
    29 return new WinSoft(); 
    30 } 
    31 } 
    32 
    33 
    34 
    35 
    36 //@test:创建工厂->用该工厂生产对应的对象 //创建MacFactory工厂 
    37 $MacFactory_obj = new MacFactory(); 
    38 //用MacFactory工厂分别创建不同对象 
    39 var_dump($MacFactory_obj->CreateSystem());//输出:object(MacSystem)#2 (0) { } var_dump($MacFactory_obj->CreateSoft());// 输出:object(MacSoft)#2 (0) { }
    40 
    41  //创建WinFactory $WinFactory_obj = new WinFactory(); //用WinFactory工厂分别创建不同对象 
    42 var_dump($WinFactory_obj->CreateSystem());//输出:object(WinSystem)#3 (0) { } var_dump($WinFactory_obj->CreateSoft());//输出:object(WinSoft)#3 (0) { }

    注册模式

    注册模式,解决全局共享和交换对象。已经创建好的对象,挂在到某个全局可以使用的数组上,在需要使用的时候,直接从该数组上获取即可。将对象注册到全局的树上。任何地方直接去访问。

     1 <?php
     2 
     3 class Register
     4 {
     5     protected static  $objects;
     6     function set($alias,$object)//将对象注册到全局的树上
     7     {
     8         self::$objects[$alias]=$object;//将对象放到树上
     9     }
    10     static function get($name){
    11         return self::$objects[$name];//获取某个注册到树上的对象
    12     }
    13     function _unset($alias)
    14     {
    15         unset(self::$objects[$alias]);//移除某个注册到树上的对象。
    16     }
    17 }
  • 相关阅读:
    在C#中实现Python的分片技术
    如何将松散的dll打包进需要发布的exe
    Python基础学习(第8天)
    javascript中 的 + RegExp['x241'] 怎么理解
    CSS和JavaScript标签style属性对照表
    浏览器 怪异模式(Quirks Mode) 与 标准模式(Standards Mode)
    Javascript如何判断一个变量是数字类型?
    我的第一个jquery插件:下拉多选框
    javascript中===与==
    ztree高级实例(原创)
  • 原文地址:https://www.cnblogs.com/BrokenHeart/p/10662716.html
Copyright © 2011-2022 走看看