转:让设计不再成为负担-设计模式详解(8)

第九章 管理良好的集合 迭代器和组合模式


今天,我们来讲迭代器模式。事实上,迭代器模式在php中以SPL内置的各种迭代器已经完全满足我们使用的需求。有特殊需求的只要重写SPL提供的类和实现特定的接口就能完成了。
  但是,我还是希望我们能够了解一个迭代器具体是如何工作的。
  首先我们可能经常遭遇一个问题。
  就是数组,散列表或者对象列表这些等等元素的集合处理问题。比如说在无限分类中可能要涉及到处理数组。也可能自定义一群对象后,通过数组存储。我们经常操作的系统目录也属于集合的范畴。数据库的查询。。等等等。集合的涉及范围是非常广的。那我们就希望有一个统一的接口来完成一个迭代工作。而不用担心具体的迭代过程是怎么样的。简单的说:迭代器让我们能够游走于聚合内的每一个元素,而又不暴露其内部的表示(比如循环。各种不同的集合的循条件是不同的。)。
  如果不明白?我可以举个例子。比如我们需要对一个字符串的每个字节进行处理。
那就可能for($i=0;i<strlen($string);$i++)这样操作来处理字符串的每个字节。
另一个例子是数组。可能会for($i=0;i<count($array);$i++)这样来操作处理的字符串。
当我们同一个项目里不停的使用循环的时候。就得不停的转换两种循环模式和循环条件。面向对象是Everything is Object!
当我们把数组或者其他形式的集合通过对象的形式调用和处理的时候。可能会遭遇一些问题。比如说下面这个现实生活中的例子。
有两家书店。他们卖了很多书(废话。去死.囧)。他们加入了一个书市联盟。联盟希望他们提供自己店的书目清单。看起来不错的主意,但是出现了一个问题。
两家书店的书目存储的方式完全不同。A书店用的是数组存储。B书店因为种种原因用的字符串处理。可联盟又希望获取到他们的数目清单。这该如何操作呢?毕竟两家书店的数据都是庞大的。不可能因为一个联盟的要求而改变自己的数组存放方式。A和B也并不愿意这样。
好的。先看看他们两家的代码如何。可能会在这里找到问题的结症。

阅读剩余部分...

转:让设计不再成为负担-设计模式详解(7)

第六章 封装调用 命令模式


呵呵。休息了两天。今天开始开始我们的新的一个模式的认识:命令模式!
  首先看看我们今天的例子:程序box!
  我们现在给操作系统做一个程序。我想很多人用过懒人安装法吧。就是用一个应用程序列出所有的可能安装的程序。只需要点击就能安装。
  现在我们需要实现的功能类似。只用一个程序盒子就来控制其他程序的开和关!但不仅仅是预定义进去的几个程序。而是在将来会有更多的程序添加进去。但整个盒子的运作必须能够正常使用。也就是说,不管添加多少应用程序,都能够实现用盒子来操作应用程序的开关等操作。
  那现在我们面临的问题是什么?记住。设计模式是用来解决问题的。
  各种不同程序将会有不同的方法。并且这个盒子必须能够对这些程序发出正确的指令,让其实现正确的功能。可能会有一种好的解决方案,就是将盒子的程序做得简单点,让他从其他的程序里面解耦出来。尽量保证他的简单。但这样一来似乎又不可能,因为在用户点击盒子里面的按钮的时候必须执行正确的程序。你总不希望你的程序里充满if...elseif...elseif...这样的结构。因为他是硬编码进去的。将来需要添加新的应用程序,你又要修改。并且很有可能你还要修改你的程序来复合这个盒子。

阅读剩余部分...

转:让设计不再成为负担-设计模式详解(6)

第五章 独一无二的对象 单例模式


单例模式可能是所有设计模式中最简单,但却是非常重要的一种设计模式。
很多情况下都需要类只有一个实例,比如说数据库的实例对象(可以看深空的那个数据库类。就是采用了单例模式)。因为他只有一个类图。所以说他简单。
通过几个提问,可能你能更容易的理解单例模式!
你如何创建类的实例?
   使用new关键字
那如何避免一个类的实例创建?
可以这样操作么?
class MyObject{
  private function __construct() {
  }
}
那这样将如何获取这个类的实例?
  因为构造函数已经被私有化。只有类的内部才能调用这个类的实例。外部想调用是没办法的。
那如果这样操作是不是就解决了?
class MyObject{
  private function __construct() {
  }
public function getInstance(){
  return new MyObject;
}
}
直接外部调用getInstance()方法就能够返回这个类的实例。这样做的好处是保证整个应用程序中只有一个类的实例。当然。需要进一步的限制。为了保证这个类的实例是独一无二的。所以得在类的内部进行存储,判断。下面是标准的单例模式的例子

/**
* 单例模式实例
*/
class MyObject{
//提供一个私有的静态成员。他用来存储这个类在整个应用程序中的实例
   static $obj;//并且没有声明是什么保护类型。子类也可以直接使用。
//下面这个变量是测试用的
private $test;

private function __construct(){
  //可以在这里写入你构造这个类实例的时候初始化操作
  $this->test="我将进行单例模式的操作";
}
//通常情况下的单利模式都是采用getInstance作为单例引用的方法名
public static function getInstance(){
  //通过instanceof类型判断是否这个类的实例变量已经进行了初始化。此过程是保证整个类的实例是独一无二的
  if(!(self::$obj instanceof self)){
   self::$obj = new self();
  }
  return self::$obj;
}

阅读剩余部分...

转:让设计不再成为负担-设计模式详解(5)

上几章都大致了解了在OOP设计中,应该针对抽象编程而不是具体实现编程。
  但是上面几章的代码中或多或少都又"new"来创建对象的实例。那么在这些地方,就不是针对抽象编程,而成了具体实现的编程。
  但使用"new" 有错吗?从本质上讲是没错的,因为这是OOP的基础。但是,从另一个角度去说,他是错误的。但错不在他。而在程序上面。
  简单的说,就是我们使用了new关键词将代码的执行硬编码进了程序之中。他不能在程序运行时来决定运行哪一个。也就是说,当我们希望一个项目需要改变的时候,需要添加新的对象的时候,需要打开文件进去修改
  第三节的装饰模式重点讲过一个原则:对修改关闭,对扩展打开。但是,频繁使用new这个创建实例的办法就是在破坏这个原则。因为你总是会要在不久的将来改变他的。只要你要添加新的对象。你必定要修改源文件。
  那错误具体是由什么导致的?第一章我说过,OO编程的基本原理不是那些原则,而是Change!改变。一切都是因为改变捣的鬼。
  看看下面这个例子:
  我们需要开一个面包店。已经建立好了面包订购的类(Bread):
  下面用另一个类的方法调用他。

function orderBread(){
$bread = new Bread();//如果说大家看了上面的设计模式,或者已经对设计模式有了一定的认识,这里肯定那个希望是建立一个抽象类或者接口。可是那样就没办法实例化了
//对面包进行各样的操作
$bread->prepare();
$bread->bake();
$bread->cut();
$bread->box();
}

这里本身没有任何错误。但是,如果我要更多的面包呢?只能由我们来决定面包的种类,然后叫这个方法来制造面包了

function orderBread($_bread){
     if($_bread == "BlackBread"){
      $this->break = new BlackBread();
     }else if ($_break == "WhiteBread"){
      $this->break = new WhiteBread();
     }else if($_break == "SweetBread"){
       $this->break = new SweetBread();
    }else ($_break == "NutsBread"){
       $this->break = new NutsBread();
    }

//对面包进行各样的操作
$bread->prepare();
$bread->bake();
$bread->cut();
$bread->box();
}

  手写一堆代码。。真麻烦
  恩,这样就完成了。如果以后要改呢?要增加面包,或者减少面包种类呢?是不是必须得打开这个文件来修改他。删删改改的。
  这样就找到问题结症了。问题不在new,而在这一堆的改变上面。他们随时会改变的。你就得随时的去改变这些文件。
  那就把它拿出来。

if($_bread == "BlackBread"){

$this->break = new BlackBread();

}else if ($_break == "WhiteBread"){

$this->break = new WhiteBread();

}else if($_break == "SweetBread"){

$this->break = new SweetBread();

}else ($_break == "NutsBread"){

$this->break = new NutsBread();

}

这一块改变拿出来,放到另一个类里面。这样方法orderBread就不用关心是要定什么面包了。他只要知道调用它的时候需要制作一块面包。
这就是工厂!用工厂来建立对象!
先从工厂入手:

<?php
require("Bread.php");
class BreadFactory{
private $bread;
//通过这个creatBread方法创建我们的面包
public function creatBread($_bread){
  if(is_string($_bread)){
   //类型判断是必须的。php是弱类型语言。
       if($_bread == "BlackBread"){
        $this->bread = new BlackBread();
       }elseif ($_bread == "WhiteBread"){
        $this->bread = new WhiteBread();
       }elseif($_bread == "SweetBread"){
         $this->bread = new SweetBread();
      }elseif($_bread == "NutsBread"){
         $this->bread = new NutsBread();
      }else{
       echo "本工厂不提供这款面包";  
      }
      //以上没有任何变化。将他从原来的面包点的代码中拿出来
  }
  return $this->bread;
}
}
?>

阅读剩余部分...

转:让设计不再成为负担-设计模式详解(4)

第三章 装饰对象:装饰模式


Oh,居然没有人看我的思考并做出相应回答。那既然这样,我何必要费心写出我的答案呢?
  设计原则中又一点我已经重复强调了。这里也给个精确的定义:
   开-闭原则,对扩展开放,对修改封闭。
  回顾一下上面的两章。策略模式中的策略接口下实现策略类,是不是就是一种扩展呢?你需要做的只是添加更好的策略方式。但是修改你很难做到
  观察者模式是具有松耦合的。观察主题本身可能会需要修改。可能吗?一般不是特殊情况下的更改,不需要打开观察主题类。只需要对观察者进行扩展就可以了。这样是不是也满足了对扩展开放,对修改封闭呢?
  我们的目标是允许类在不更改现有代码的情况下进行良好扩展。这样就可以搭载新的行为。兄弟,你花几天的时间写了个几百行的类。突然需要改变,又要翻进类里面查找bug解决问题。ok。这该死的都完成了。好把,这个类的门就给死死的关上吧。不允许自己或者其他人随意打开类来进行修改。这样的好处显而易见的。这样可以使类具有更大的灵活性,可以接受新的功能来应对新的改变需求。
  从深入浅出中转几个常见问题:
  这似乎看其来有点矛盾,但是确实又一技术和技巧可以允许在不直接修改代码的情况下对其进行扩展。
  但请注意:在选择需要扩展的代码部分时要小心。每一个地方都采用开放-关闭原则,是一种浪费,也没有必要,还会导致代码变得复杂并且难以理解。
  要知道那些地方需要改变。这个设计到OO系统的经验。多看一下其他的例子可以帮助班别设计中的变化区。因为设计模式是贯穿整个工程的生命周期的。你可以在任何时候使用设计模式和设计原则重构你的代码。这没设没什么好担心的
  概念性的总结完毕。。。下面进入装饰模式的环节。
  老板很欣赏你,你给他完成了发工资又解决了发新闻的问题。现在请你去吃饭。到了饭局。老板开口了。你看这每个菜都很复杂,又是放盐又是放油的。多点不行,少也也不行。因为成本都是通过这些来控制的。如果是机器完成的多好啊。你就来模拟一下机器完成炒肉这个成本的计算
  听其来不错。下面有个比较错误的思维方式,类图说明
class.gif

阅读剩余部分...

转:让设计不再成为负担-设计模式详解(3)

第二章 让你的对象知悉现状 观察者模式


观察者模式在框架里应用是很多的。尤其是java的JDK.可以说是遍布观察者。js的监听事件,java的监听类。都是观察者的变体。甚至大家熟悉的MVC.也是个复杂的观察者模式.
  我们先脱离程序,用现实中的例子来说明什么是观察者模式
  你订阅过报吗?过程如何?应该是这样的。
  你向报社发出申请,我要订阅报纸。
  报纸将你加入名单。每天只要他还没倒闭。他就继续给你提供报纸。
  时间长了。有点烦这些整天报道喜讯的报纸。好吧,我取消报纸的订阅。
  报社在名单你取消你的名额。管你是谁,只要他又新的新闻,继续提供给他名单里的成员。
  OK!观察者的模式出来了。如果你能理解这个。你就理解了观察者模式!!!很简单不是吗?
  订阅者+出版者=观察者模式
  回到程序世界来,什么叫观察者模式?精确的定义应该是这样:
  定义了对象一对多的依赖,一旦对象的状态发生改变,它的所依赖者都会接到通知自动更新
  类图如下
  Observer.gif
   上次给公司解决工资发放问题了。老大很高兴,后果很忙碌。。继续给你个程序来做。公司新闻现在需要从数据库中取出。然后将这些数据分别发送到手机,网页,或者BB机(如果能的话:lol: )。商务通也是个不错的选择。现在psp很强大,也可以选择发送到psp里面。
  具体怎么实现不在这里考虑拉。只考虑思维。思维很重要。
  你如何操作类?
  会不会这样?

阅读剩余部分...

转:让设计不再成为负担-设计模式详解(2)

第一章 策略模式


为什么要用面向对象?我想最大的理由是OO可以让代码更加的具有可读性。也能让代码具有灵活性。继承一定是很多OO初学者和我一样都最喜欢用的代码复用方法吧。
  你可能要说了,为什么不呢?父类里面代码已经写好了。我继承后就能照用了。啊哈,继承从技术水平上说本身是没错的。但是相当于把功能方法硬编码进了程序里面。一旦需要修改就要打开源代码修改源代码。。
  你觉得在写程序的时间最多的部分是什么了?是前期编写还是后期维护?对的,就是后期维护。但项目过大的时候,后期无尽的添加修改功能能把一人逼疯。我也经常那样。于是。。我拿起了OO。用上了 OO的众多优秀特点。可还是不可避免的导致后期维护一塌糊涂。
  这都是说在前面的话。可能你又要说了,这光我什么事。我有足够的能力和经历去维护代码库和框架。
  其实我更想说的,在OO中,尤其是设计模型理念你,最需要的不是你又多大的能力去编写代码。而是思维。用<深入浅出 设计模式>中的话来说就是,先洗脑,再想事情。
  而设计模式中最主要最主要最主要最主要的思维方式就是:不要针对实现编码,要针对抽象编码。有些人能明白,有些人又不能明白。我想,进入设计模式大门后,你一定能够深切理解这句话。
  我们以一个例子来进入第一章:策略模式
  我们在外打工,最基本的是什么?工资!没工资我可活不下去。ok,现在有一个客户需要你给他用面向对象的方式写一个工资发放的系统出来。
  你会怎么做?先分析需要哪几个类。
  首先,所有人在公司里面都属于老板下的职员。ok,抽象类诞生abstract Personnel class。为什么是抽象的类,而不是实际的类?先想想哈,仔细想想你一定能明白的。(提示,抽象类的定义)
  职员又分两种:雇员和经理。又出来两个类,很好.class Mannage和class Employee。
  所有的职员都几个行为:发工资,涨工资,改变基础工资.减工资
  如果是你,会如何编写这个类?只是说这个类的结构。
会不会是这样?(类图待补充。。)
abstract Personnel class{
protected 很多属性//用protected是为了安全。要养成习惯
public function getSalary()//发工资了
public function addSalary()//天啊。涨工资了
public function basicSalary()//基本工资也发生了改变
public function decreaseSalary()//fuck,既然减我工资。我不干了
}

阅读剩余部分...

转:让设计不再成为负担-设计模式详解(1)

 废话不多说了。这次分享的是设计模式。。其实在学java的时候碰过。但没时间。就放下了。现在继续拿起来学习发。看明白了还是很简单的,对程序的编写,风格规范化都是很有帮助的。
            一楼一个设计模型。按照《深入浅出 设计模式》目录结构写的。因为是java的设计模式。。。例子都是自己写的。。。自己还只学4个。。。。一边学一边写把。
            从第二章开始,我会留1-2道思考题。希望观看的人不要只扫一眼就不看了。一起思考把。
           有任何纰漏和理解错误,请Boss告诉我。。不求加精。。。。等我完成一半再加精。


为什么要用设计模式?
  面向对象有很多设计原则。。。恩。网友ZendFramework在回帖里要求跟大家说为什么要用。和详细讲解设计原则。好吧。我转一堆设计原则过来。。。

阅读剩余部分...

    Page :
  1. 1