首先,鄙人的DZ分析贴其实一直是心里一件大事。。前几天辞职。一怒之下,把电脑上所有东西低格。。。昨天才装好系统
。网络一直每装好。刚刚才弄好,现在在配置php环境和下总总软件手册之类的。反正坐着也是坐着。打算在家休息两个月,完成DZ论坛分析计划,设计模式学习计划。ZF学习计划。然后是出去找工作
。。。貌似php最新的版本要出来了。很期待迟绑定的支持。因为鄙人比较倾向OO的设计实现。因为鄙人一直没空间。只能来这里发发帖写写自己的心得。。。再啰嗦一句。。终于没有阻碍的琐事打搅我了~~~认真学习,天天向上
顺便打个广告:
QUOTE:
SamPeng's blog。将开源精神进行到底这几天消失就是搞他去了。。。喜欢鄙人这些还没完成的教程的朋友,欢迎常来坐坐。加入收藏和邮件订阅是最好的选择
废话不多说了。这次分享的是设计模式。。其实在学java的时候碰过。但没时间。就放下了。现在继续拿起来学习发。看明白了还是很简单的,对程序的编写,风格规范化都是很有帮助的。
一楼一个设计模型。按照《深入浅出 设计模式》目录结构写的。因为是java的设计模式。。。例子都是自己写的。。。自己还只学4个。。。。一边学一边写把。
从第二章开始,我会留1-2道思考题。希望观看的人不要只扫一眼就不看了。一起思考把。
有任何纰漏和理解错误,请Boss告诉我。。不求加精。。。。等我完成一半再加精。
QUOTE:
为什么要用设计模式?
面向对象有很多设计原则。。。恩。网友ZendFramework在回帖里要求跟大家说为什么要用。和详细讲解设计原则。好吧。我转一堆设计原则过来。。。
“开—闭”原则
面向对象设计的基石是“开—闭”原则。
“开一闭”原则讲的是:一个软件实体应当对扩展开放,对修改关闭。
这个规则说的是,在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。
从另外一个角度讲,就是所谓的“对可变性封装原则”。
“对可变性封装原则”意味着两点:
1 .一种可变性不应当散落在代码的很多角落里,而应当被封装到一个对象里面。同一种可变性的不同表象意味着同一个继承等级结构中的具体子类。
2.一种可变性不应当与另一种可变性混合在一起。即类图的继承结构一般不应超过两层。
做到“开—闭”原则不是一件容易的事,但是也有很多规律可循,这些规律同样也是设计原则,它们是实现开—闭原则的工具。
里氏代换原则
里氏代换原则:
即如果一个软件实体使用的是基类的话那么也一定适用于子类。但反过来的代换不成立。
如果有两个具体类A和B之间的关系违反了里氏代换原则,可以在以下两种重构方案中选择一种:
1 创建一个新的抽象类C,作为两个具体类的超类,将A和B共同的行为移动到C中,从而解决A和B行为不完全一致的问题。
2 从B到A的继承关系改写为委派关系。
咋一看觉得这个怎么还是面向对象设计的原则呢?这个明明就是Java的语法规则。对,Java是提供了对里氏代换原则在语法上的支持。但是仅仅是语法上,在和现实世界的相符合程度上根本没有提供。所有常常会有不符合里氏代换原则的情况出现。
依赖倒转原则
依赖倒转原则讲的是:要依赖于抽象,不要依赖于具体。即针对接口编程,不要针对实现编程。针对接口编程的意思是,应当使用接口和抽象类进行变量的类型声明、参量的类型声明,方法的返还类型声明,以及数据类型的转换等。不要针对实现编程的意思就是说,不应当使用具体类进行变量的类型声明、参量的类型声明,方法的返还类型声明,以及数据类型的转换等。
依赖倒转原则虽然强大,但却不易实现,因为依赖倒转的缘故,对象的创建很可能要使用对象工厂,以避免对具体类的直接引用,此原则的使用还会导致大量的类。维护这样的系统需要较好的面向对象的设计知识。
此外,依赖倒转原则假定所有的具体类都是变化的,这也不总是正确的。有一些具体类可能是相当稳定、不会发生变化的,消费这个具体类实例的客户端完全可以依赖于这个具体类。
接口隔离原则
接口隔离原则讲的是:使用多个专门的接口比使用单一的接口要好。从客户的角度来说:一个类对另外一个类的依赖性应当是建立在最小的接口上的。如果客户端只需要某一些方法的话,那么就应当向客户端提供这些需要的方法,而不要提供不需要的方法。提供接口意味着向客户端作出承诺,过多的承诺会给系统的维护造成不必要的负担。
合成、聚合复用原则
合成、聚合复用原则就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部份,新的对象通过向这些对象的委派达到复用已有功能的目的。这个原则有一个简短的描述:要尽量使用合成、聚合,尽量不要使用继承。
合成、聚合有如下好处:
新对象存取成分对象的唯一方法是通过成分对象的接口。
这种复用是黑箱复用,因为成分对象的内部细节是新对象所看不到的。
这种复用可以在运行时间内动态进行,新对象可以动态的引用与成分对象类型相同的对象。
合成、聚合可以应用到任何环境中去,而继承只能应用到一些有限环境中去。
导致错误的使用合成、聚合与继承的一个常见原因是错误的把“Has-a”关系当作“Is-a”关系。如果两个类是“Has-a”关系那么应使用合成、聚合,如果是“Is-a”关系那么可使用继承。
迪米特法则
迪米特法则说的是一个对象应该对其它对象有尽可能少的了解。即只与你直接的朋友通信,不要跟陌生人说话。如果需要和陌生人通话,而你的朋友与陌生人是朋友,那么可以将你对陌生人的调用由你的朋友转发,使得某人只知道朋友,不知道陌生人。换言之,某人会认为他所调用的是朋友的方法。
以下条件称为朋友的条件:
当前对象本身。以参量的形式传入到当前对象方法中的对象。当前对象的实例变量直接引用的对象。当前对象的实例变量如果是一个聚集,那么聚集中的元素也都是朋友。
当前对象所创建的对象。
任何一个对象,如果满足上面的条件之一,就是当前对象的朋友,否则就是陌生人。
迪米特法则的主要用意是控制信息的过载,在将其运用到系统设计中应注意以下几点:
在类的划分上,应当创建有弱耦合的类。类之间的耦合越弱,就越有利于复用。
在类的结构设计上,每一个类都应当尽量降低成员的访问权限。一个类不应当public自己的属性,而应当提供取值和赋值的方法让外界间接访问自己的属性。在类的设计上,只要有可能,一个类应当设计成不变类。在对其它对象的引用上,一个类对其它对象的引用应该降到最低。
谁能够完全看明白呢?今天思考了很久,觉得设计模式应该不是为使用设计原则而出现的。他是一系列的经验积累而来的原则综合体。
就像我在第一章的策略模式中的例子,在设计团队中,你是觉得说上一堆的设计原则更容易沟通还是就一句话:我们用策略模式来定义这些工资发放形式吧。两者比起来,后者是不是更容易理解呢?你的伙伴马上就能明白:恩,我知道了。将算法整体的封装起来。这样达到对修改开放对无变化的地方闭合的效果。过程就是面向抽象而不是实现了。
下面几点是我总结出来为什么要学设计模式:
1、你更容易理解设计原则。记住,设计模式不是万能的。总有你找不到匹配的设计模式。万一这样怎么办?进入大脑的设计模式就其作用了。无论你是否在利用设计模式做设计。你脑袋里始终想的不应该是复合设计模式,而是符合设计原则。
2、模式可以让你的代码更具有OO良好设计质量。
3、模式是经验,不是去发明,而是发现。模式就像楼房的图纸。而不需要考虑如何实现他。是不是经常钻进如何实现某个效果而苦恼,反而和其他的程序整合出了纰漏。不要针对实现编程,要针对抽象做设计。这样更容易让自己感觉是在设计程序,而不是高价的打字员。
4、代码更容易维护。大部分设计模式允许系统局部独立于系统其他部分。
5、习惯封装。把变化部分拿出来封装之!
6、和团队有了更多的共同语言。一句话顶千言
7、切记:模式不是代码,而是解决实际问题的方案
我也学深入浅出设计模式书中一样,每完成一部分就弄个工具箱:
QUOTE:
看看我们现在有什么你也能做到!大家一起加油吧
OO基础:
继承,多态,封装,抽象。
OO原则:
将变化封装
多用组合,少用继承
针对接口编程,不针对实现编程
设计是为实现交互对象之间松耦合而努力
开-闭原则:对扩展开放,对修改封闭
依赖导致原则:依赖抽象,不要依赖具体类
OO模式
策略模式:定义算法族,分别封装起来,让他们之间可以互相替换。此模式让算法的变化独立于使用算法的用户
观察者模式:定义了对象一对多的依赖。这样一来,对象的状态发生改变,所依赖的对象都会获取通知而更新
装饰模式:动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更具又弹性的替代方案
工厂方法模式:提供一个接口来创建产品。但是具体的对象实例化是在它的子类中完成。也就是工厂方法将实例化推辞到子类完成
抽象工厂模式:提供一个接口,用于创建相关或者依赖对象的家族,而不需要明确指定具体类
单例模式:确保一个类只有一个实例,并提供全局访问点。
命令模式:将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。
迭代模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示
QUOTE:
所有程序建立在php5的基础上,已经全部调试成功目录:
QUOTE:
[ 本帖最后由 某个人 于 2008-11-19 17:00 编辑 ]
第一章 封装你的算法:策略模式
第二章 让你的对象知悉现状 观察者模式
第三章 观察对象:观察者模式
第四章 加工你的OO精华 工厂模式
第五章 独一无二的对象 单例模式
第六章 封装调用 命令模式
第七章 随遇而安 适配器和外观模式
第八章 封装算法 模板方法模式
第九章 管理良好的集合 迭代器和组合模式
第十章 事物的状态 状态模式
第十一章 控制对象的访问 代理模式
第十二 模式中的模式 复合模式








最新回复
为什么要用面向对象?我想最大的理由是OO可以让代码更加的具有可读性。也能让代码具有灵活性。继承一定是很多OO初学者和我一样都最喜欢用的代码复用方法吧。
你可能要说了,为什么不呢?父类里面代码已经写好了。我继承后就能照用了。啊哈,继承从技术水平上说本身是没错的。但是相当于把功能方法硬编码进了程序里面。一旦需要修改就要打开源代码修改源代码。。
你觉得在写程序的时间最多的部分是什么了?是前期编写还是后期维护?对的,就是后期维护。但项目过大的时候,后期无尽的添加修改功能能把一人逼疯。我也经常那样。于是。。我拿起了OO。用上了 OO的众多优秀特点。可还是不可避免的导致后期维护一塌糊涂。
这都是说在前面的话。可能你又要说了,这光我什么事。我有足够的能力和经历去维护代码库和框架。
其实我更想说的,在OO中,尤其是设计模型理念你,最需要的不是你又多大的能力去编写代码。而是思维。用<深入浅出 设计模式>中的话来说就是,先洗脑,再想事情。
而设计模式中最主要最主要最主要最主要的思维方式就是:不要针对实现编码,要针对抽象编码。有些人能明白,有些人又不能明白。我想,进入设计模式大门后,你一定能够深切理解这句话。
我们以一个例子来进入第一章:策略模式
我们在外打工,最基本的是什么?工资!没工资我可活不下去。ok,现在有一个客户需要你给他用面向对象的方式写一个工资发放的系统出来。
你会怎么做?先分析需要哪几个类。
首先,所有人在公司里面都属于老板下的职员。ok,抽象类诞生abstract Personnel class。为什么是抽象的类,而不是实际的类?先想想哈,仔细想想你一定能明白的。(提示,抽象类的定义)
职员又分两种:雇员和经理。又出来两个类,很好.class Mannage和class Employee。
所有的职员都几个行为:发工资,涨工资,改变基础工资.减工资
如果是你,会如何编写这个类?只是说这个类的结构。
会不会是这样?(类图待补充。。)
QUOTE:
只写个抽象类。其他的子类的方法就是覆盖这些,然后重写,对吗?这样看其来没什么问题。但是,如果我一个公司又几万人,有N种分工的工种,当然,还是要从这里继承下去。可是,难道每修改一个工种的发工资的方法就得达开源程序去添加或者修改吗?如果有几个员工是一样的呢工资呢?copy?这些方法确实能够解决问题。但是,效率呢?
我们在程序中最常打交道的是什么?Change!改变。程序是为了运行时的改变而改变,是为了将来某些不定的时间内改变而改变!
请记住这些原则:将程序中改变的部分剥离出来于不改变的部分分别开。恕小弟愚钝,我理解,这就是封装了。我丫的将改变的地方全封闭起来。其他的地方调用,只需要调用他就可以了。完全不需要知道他是如何操作的。这样听起来似乎很又意思。。
继续这个例子。。这几个方法都可能会改变。那就是他们了。剥离出来。放入一个OO常用的东西里面:接口的实现类。
注意,这里所说的放入接口实现类,并不是将所有的方法放入一个接口的实现来处理。这样就没灵活性的展示了。
而是将一个方法处理的形式交给一个接口的实现类。如下处理:
这个接口和实现非常简单。不需要多解释了哈。有疑问发论坛小刀给我。
这样一个接口和实现类就只实现一个功能,涨工资。我管你谁长,我只知道我这里我定义两个涨工资的方法。你自己调用就是了。外部调用也是一样。我只需要长工资。但不需要烦恼到底涨工资的人是什么职位。为什么呢?因为他会运行时的绑定。php5的迟绑定没有支持。多态只能是抽象意义的多态。因为他是个弱语言多态。
在抽象类里面这样处理:
子类需要干点什么?这些都已经继承过来了。只需要初始化一些参数就可以了。比如基本工资这些。怎么涨工资。在具体的方法里面去修改。
记住。。上面的都是继承过来的。他们已经从父类那里继承了各种工资的方法。
关键在下面如何进行动态绑定:
我创建一个操作类。因为没办法,php的特性造成的。如果需要模仿多态只能这样。。。当然。。不模仿多态也行。因为php本身弱语言特性就决定了php本身就是多态的。只是这样更符合OO的多态特性。
最后测试调用:
$a = new Employee();
User::addSalary($a);
User::decreaseSalary($a);
User::decreaseSalary($a);
echo $a->getSalary();
翻译一下:
a是个雇员。
老板给a涨了工资
老板减少了a工资
老板又减少了a工资
好把。看看a最后还剩多少工资
如果有其他的工资改变呢?发点奖金?涨工资不是按一次涨多少。而是需要按比例呢?不需要再打开该死的原类:Personnel了。直接去改接口文件内的定义吧。这些改变就留给各位把。
是不是把以后要改变的都剥离出来了呢?记住这一节的要点:将程序中改变的部分剥离出来于不改变的部分分别开!
现在回头来看看是不是在针对接口编程而不是实现编程了呢?慢慢和我一起理解和消化吧
本节完。。。。。
有理解错误的地方忘各位大神指出。谢谢
补充:
非常感激ZendFramwork补充的遗漏问题:
QUOTE:
设计模式的本质都是为了面向对象的那几个基本原则
首先你得让大家知道为什么会有这些设计模式.不能盲目的去学习.
最好先介绍一下 开闭原则 里矢代换原则 依赖倒转原则
比如策略模式和这些原则的关系:
我们依赖于抽象策略而不是具体策略 --依赖倒转原则
每一种具体的策略都能取代抽象策略的位置 --里矢代换原则
每当出现新的策略,直接添加,而不需要任何修改 --开闭原则
这几个原则明天我会在下一章重点阐述。。。下一章预告时间:明天晚上6点前
[ 本帖最后由 某个人 于 2008-11-2 20:43 编辑 ]
我们先脱离程序,用现实中的例子来说明什么是观察者模式
你订阅过报吗?过程如何?应该是这样的。
你向报社发出申请,我要订阅报纸。
报纸将你加入名单。每天只要他还没倒闭。他就继续给你提供报纸。
时间长了。有点烦这些整天报道喜讯的报纸。好吧,我取消报纸的订阅。
报社在名单你取消你的名额。管你是谁,只要他又新的新闻,继续提供给他名单里的成员。
OK!观察者的模式出来了。如果你能理解这个。你就理解了观察者模式!!!很简单不是吗?
订阅者+出版者=观察者模式
回到程序世界来,什么叫观察者模式?精确的定义应该是这样:
定义了对象一对多的依赖,一旦对象的状态发生改变,它的所依赖者都会接到通知自动更新
类图如下
Observer.gif
上次给公司解决工资发放问题了。老大很高兴,后果很忙碌。。继续给你个程序来做。公司新闻现在需要从数据库中取出。然后将这些数据分别发送到手机,网页,或者BB机(如果能的话
具体怎么实现不在这里考虑拉。只考虑思维。思维很重要。
你如何操作类?
会不会这样?
回想一下我在第一章和首楼上说的那几点概念和原则。
$WebBrowser这里是实例化过的-----是针对具体实现的编程。如果我们要增加上十余种的平台呢?打开源文件10余次。。删删改改。。很崩溃吧。
后面的update($news)这里倒是比较向是面向抽象编程。
ok .问题出现了。我以后添加修改或者删除发布平台怎么办?就像现在的blog。我想开发个程序。让这个平台扩展到任意的CMS或者任意的朋友blog上去显示。怎么办?难道添加几千几万条这样的代码。。。
好了。不卖官子了。现在我们已经找到了将会改变的部分。
QUOTE:
剩下的是拿出来封装。该怎么做呢?上面不是已经说了观察者模式的概念么?用在这里怎么样?
新闻作为一个主题。当他有新的新闻发布的时候。由于各平台都是观察者。所以会自动的更新状态。
添加修改平台都不会和主题发生影响。这就叫做松耦合。
设计原则之一:为了交互对象松耦合而努力。
何谓松耦合?我的理解就是彼此有依赖,但是不存在主要依赖。
用观察者模式来说,
关于观察者的一切,主题只知道观察者实现了某个接口(也就是Observer接口)。主题不需要知道观察者的具体类是谁、做了些什么或其他任何细节。
任何时候我们都可以增加新的观察者。应为主题唯一依赖的东西是一个实现Observer接口的对象列表,所以我们可以随时增加观察者。实际上,在运行时我们都可以用新的观察者取代现有的观察者,主题不会受到任何影响。同样的,也可以在任何时候删除某些观察者。
在新类型的观察者出现时,主题的代码不需要任何的改变(what this?开闭原则。对改变开放,对不改变的地方封闭)假如我们有个新的具体类需要当观察者,我们不需要为了兼容新类型而修改主题的代码,所有要做的就是在新类里实现此观察者接口,然后注册为观察者即可。主题不在乎别的,它只会发送通知给所有实现了观察者接口的对象。
如果我们在其他地方需要使用主题或者观察者,可以非常轻易的独立地重复复用。
改变主题或观察者其中一方,并不影响另一方。因为这两者是松耦合的
下面是我的实现。各位可以任意扩展。只是起个抛砖引玉的作用。
观察者接口:
具体的观察者~~可以任意添加各种这样的观察者。。但是构造器那的注册你需要照搬了=。=可以又很多形式。。。我只是说明一下观察者。就简洁点了
不要鸡蛋里挑骨头=。=
然后是主题类。他负责制造数据出来。然后给各个观察者。你可以理解成报社。。
简单的测试一下
会显示什么呢?
QUOTE:
好。接下来在上面测试语句后面跟一句。我注销这个用户,然后再更新一次新闻。看看会得到什么。这才是重点啊。呵呵会得到什么样的效果呢?
QUOTE:
网页新闻就获取不到新闻了。第二章就讲到这里。。。。事实上还可以实现很多功能。推和拉的功能。
课后作业:1、大家自己试试,如何做到观察者已经知道主题已经更新,但观察者不想更新数据。也就是根据观察者的喜好来判断是否更新手头上的新闻资料。
2、此模式复合哪几点设计原则
明天中午来公布答案。希望我能在回帖里看到同学们的思考
[ 本帖最后由 某个人 于 2008-11-3 17:15 编辑 ]
设计原则中又一点我已经重复强调了。这里也给个精确的定义:
开-闭原则,对扩展开放,对修改封闭。
回顾一下上面的两章。策略模式中的策略接口下实现策略类,是不是就是一种扩展呢?你需要做的只是添加更好的策略方式。但是修改你很难做到
观察者模式是具有松耦合的。观察主题本身可能会需要修改。可能吗?一般不是特殊情况下的更改,不需要打开观察主题类。只需要对观察者进行扩展就可以了。这样是不是也满足了对扩展开放,对修改封闭呢?
我们的目标是允许类在不更改现有代码的情况下进行良好扩展。这样就可以搭载新的行为。兄弟,你花几天的时间写了个几百行的类。突然需要改变,又要翻进类里面查找bug解决问题。ok。这该死的都完成了。好把,这个类的门就给死死的关上吧。不允许自己或者其他人随意打开类来进行修改。这样的好处显而易见的。这样可以使类具有更大的灵活性,可以接受新的功能来应对新的改变需求。
从深入浅出中转几个常见问题:
这似乎看其来有点矛盾,但是确实又一技术和技巧可以允许在不直接修改代码的情况下对其进行扩展。
但请注意:在选择需要扩展的代码部分时要小心。每一个地方都采用开放-关闭原则,是一种浪费,也没有必要,还会导致代码变得复杂并且难以理解。
要知道那些地方需要改变。这个设计到OO系统的经验。多看一下其他的例子可以帮助班别设计中的变化区。因为设计模式是贯穿整个工程的生命周期的。你可以在任何时候使用设计模式和设计原则重构你的代码。这没设没什么好担心的
概念性的总结完毕。。。下面进入装饰模式的环节。
老板很欣赏你,你给他完成了发工资又解决了发新闻的问题。现在请你去吃饭。到了饭局。老板开口了。你看这每个菜都很复杂,又是放盐又是放油的。多点不行,少也也不行。因为成本都是通过这些来控制的。如果是机器完成的多好啊。你就来模拟一下机器完成炒肉这个成本的计算
听其来不错。下面有个比较错误的思维方式,类图说明
class.gif
看其来不错。好像没什么问题。但肉只有这几种做法吗?中国饮食闻名于世,是因为简单的一个菜系能做出无数种方式。可能光一个肉能做出成百上千菜来。作料的不同,几百个菜种这是很有可能的。并且还又一个维护的危险,就是口味不同的人材料的量就会不同。再一个一个计算出价格。一个类一个类的去改变。很崩溃的把。
回顾一下上面说的,对扩展开放,对修改关闭。这里继承下来的类太多,就造成了类爆炸。维护也不方便
好了。让我们来了解一下装饰者模式是如何运作的。他能解决这些问题
首先,我们得知道厨师拿到菜了该如何去做成想要的菜。
1、获取一个菜的对象。比如说肉(A原料费)
2、用盐去装饰肉(B材料费)
3、用油装饰他(C材料费用)
4、用辣椒装饰他(D材料费用)
5、用炒菜装饰他。(E人工费用)
完成,青椒炒肉。想改变盐的分量。就在盐里面改变。要改变油量。就在油的装饰行为里改变。因为单价是相同的。
总价格=A+B+C+D+E。
再来看看他是如何做到的。
先,我们先获取一个对象
(画图很费时间。用括号代表了)
肉(描述,A原料费)
然后用油来装饰他。把他包围起来
油(描述,B材料费用(肉(描述,A原料费)))
然后用辣椒装饰他
辣椒(描述,C材料费(油(描述,B材料费用(肉(描述,A原料费)))))
最后炒菜装饰他
炒菜(描述,E人工费用( 辣椒(描述,C材料费(油(描述,B材料费用(肉(描述,A原料费)))))))
先嗲用E的价格计算方法。E的计算方法会调用下一层C的计算方法,C的计算方法又会调用下一层B的计算方法。这样层层累加,最后得到整数。
如何做到这一点?委托和继承,继承不是继承方法,而是继承类型。指引这些类都是在同一个类型(菜)之下的。这样通过多态才能完成上面的自动调用下一层方法。
可能实现起来就明白了。这样说还是很迷糊。如果这样想就对了。你可能已经预料到是以一个类作为基准,然后其他的装饰着来装饰这些产品。
好了,这是目前所知道的一切:
QUOTE:
看看装饰模式的精确定义吧QUOTE:
类图如下:Decorator.gif
再把这个应用到我们的计算饭菜成本价格的程序里去
123.gif
终于调试完了。。。。没办法哈。php和java那种纯粹的OO语言还是有很大区别的。
继续。
在调试过程中发现有个错误。类图不能这样。继承而来的抽象Decorator类,里面只是上面继承过来的类。也就是他不仅仅是个抽象类。而且是个虚类(我自己发明的名词=。=。因为里面什么都没有)。为什么要这么设立个类。因为我要保证整个逻辑的层次性,并且如果你将来要扩展自己的调料方法呢?难道改父类?所以这个类是有必要的。
废话不说了。上代码
这是food类。写在inderface文件内。本来是和Decorator抽象类放一起的,但使用的时候老是报错。拿开就没事了。
最好是抽象的。因为更容易扩展。当然也可以是实类。自己实验吧。
然后是。。。第二阶梯的装饰公司。。。他们负责装修好那些什么都没有的纯粹材料
(不明白。为什么两个抽象类放在一起的时候发生重定义错误。拉开就没问题了)
这只是装饰公司的招牌而已。。。。他告诉外面的人这里面的都是装饰者。想找谁自己进去点名拉
请这些伟大的装饰者上场!
好了。装饰公司已经开张了。等客户上门。你看,客户坐下面的:
所有人都到其了~~
自己对照我上面的类图来看。不多解释=。=。。。很多说明都写在描述里了。再多解释就是啰嗦了。
QUOTE:
测试代码:结果:
QUOTE:
只是简单的例子说明一下。所以输出没做更好的处理。大家可以自己实验。并且这只是个基础部分。我只公布了一半实例代码。另一半~~~嘿嘿,大家自己试试:我只是让盐,油,这些作料加进去。怎么个做法呢?炒还是烧。这些都可以作为装饰者来修饰整个过程~具体怎么做。。。自己写代码吧。有问题再问我。如果你能理解这个装饰者模式。那你这个一定能够写出来的。很简单。
可能你已经注意到了。装饰者类会产生大量的小类。这是事实,不能逃避。但是不能遮蔽他的强大。
java.io这个包大家一定听过。而且听起来非常的大。。类图我就不贴了。。。刚随便找了个。超过了文件尺寸。。。
这个包完全都是用装饰者模式编写的。
最上层的inputstream是抽象的组件。
然后下面的单类分别是需要被装饰的具体组件和装饰者集合。以前我看这个包的时候也是头大,然后就没看了。现在算是明白了。其实也很简单=。=
这只是个例子。
其实在php中,装饰者模式的应用我个人觉得最多的应该是字符串的处理了。太多的处理方式。大写,小写,格式化,截断,加密。。用装饰者模式操作他是不是思路,扩展,维护都会更方便呢?这是小方面,大方面就得看具体项目的应用了。呵呵~
可能小类太多,造成操作不方便。下一章节工厂模式可以解决这个问题。明天中午起来再写下个章节吧。。。。。挺长的.
包括3个部分,简单工厂模式,正统的工厂模式,工厂方法
[ 本帖最后由 某个人 于 2008-11-10 20:48 编辑 ]
但是上面几章的代码中或多或少都又"new"来创建对象的实例。那么在这些地方,就不是针对抽象编程,而成了具体实现的编程。
但使用"new" 有错吗?从本质上讲是没错的,因为这是OOP的基础。但是,从另一个角度去说,他是错误的。但错不在他。而在程序上面。
简单的说,就是我们使用了new关键词将代码的执行硬编码进了程序之中。他不能在程序运行时来决定运行哪一个。也就是说,当我们希望一个项目需要改变的时候,需要添加新的对象的时候,需要打开文件进去修改
第三节的装饰模式重点讲过一个原则:对修改关闭,对扩展打开。但是,频繁使用new这个创建实例的办法就是在破坏这个原则。因为你总是会要在不久的将来改变他的。只要你要添加新的对象。你必定要修改源文件。
那错误具体是由什么导致的?第一章我说过,OO编程的基本原理不是那些原则,而是Change!改变。一切都是因为改变捣的鬼。
看看下面这个例子:
我们需要开一个面包店。已经建立好了面包订购的类(Bread):
下面用另一个类的方法调用他。
这里本身没有任何错误。但是,如果我要更多的面包呢?只能由我们来决定面包的种类,然后叫这个方法来制造面包了
手写一堆代码。。真麻烦
恩,这样就完成了。如果以后要改呢?要增加面包,或者减少面包种类呢?是不是必须得打开这个文件来修改他。删删改改的。
这样就找到问题结症了。问题不在new,而在这一堆的改变上面。他们随时会改变的。你就得随时的去改变这些文件。
那就把它拿出来。
QUOTE:
这一块改变拿出来,放到另一个类里面。这样方法orderBread就不用关心是要定什么面包了。他只要知道调用它的时候需要制作一块面包。这就是工厂!用工厂来建立对象!
先从工厂入手:
然后是面包种类
面包和工厂准备好了。最后开店
最后测试一下
结果是
QUOTE:
是不是很简单,思路也非常清晰~注意,我在Bread文件里面让所有的面包都继承了个抽象类,单是在工厂里却没使用这个抽象类。实际上,所有的变量前面你应该理解成Bread的类型。
这个其实是简单工厂。并不能叫做完全的模式。但是我个人在很多的教程里面都看到将这样的过程称为工厂模式。事实上,这只是个编程习惯,但经常使用。所以还是能将其归纳进工厂模式的。
下面来看看我的简单面包点类图是如何的
Simplefactory.gif
再次提醒!这里所说的实现接口并不是单指:写一个类,用implements关键字来实现一个接口。而是泛指实现某个超类型(可以是一个类也可以是具体接口)的某个方法
现在我们又有了新的改变。面包店生意太好了。有一些其他省市的面包店希望加盟我们。
好像问题不是很大,用上面的简单工厂方式。那就每个工厂一个工厂类。HNBreadFactory,GDBreadFactory。
这样并没多大问题。但是我们面包店生意好就是因为我们的一些质量有保证。如果我希望多点质量控制呢?都用同样的揉面,切面,装箱。流程都是一模一样的。如何操作?下面就用工厂方法来完成这个工作。看看他是如何工作的。
先将creatBread方法从工厂类里面移出来,并放入我们原先的面包店。但他只知道建立面包。具体建立什么面包他并不知道。需要完成具体面包的是在他的子类里,也就是说将他抽象话。不仅抽象整个Bread类,也要抽象这个creatBread方法。
下面是代码
这样做的好处是抽象的类BreadStore并不能决定建立什么样的面包。当然,我这里说的由子类建立面包,并不是他自身在运行时决定。而是在下面的子类来决定他应该如何提供面包。你从这个代码里面只能理解到。
$orderBread = $this->creatBread($_type);
订购面包。
订购什么样的面包,BreadStore并不知道这个面包是什么样的。可他是抽象的,不能实例化。所以是由他的子类来重写creatBread类来决定建立什么样的面包。
看看他的子类如何做的
子类里通过重写方法来决定如何建立面包。每一个加盟店都有自己的面包对象家族。他来决定采用哪样的面包。
下面是关键的地方。因为光又面包店,却没有面包,当然是不行的。
这里相对于上面的简单工厂模式有了点改变,因为为了更好的扩展面包的种类。所以面包抽象类进行了改变,直接由他来定义好了各种质量保证流程
这样整个工作就完成了。好吧,订购两个不同地区的面包来尝一下吧。
如果你将两个简单商店类的creaderBread设立成静态的那就更简单,大家可以自己测试一下。
下面是显示结果:
QUOTE:
是不是很简单。再回头来看看测试代码$b =new GDBreadStore();
$b->orderBread("BlackBread");
$b =new HNBreadStore();
$b->orderBread("BlackBread");
我建立两个店,然后订购。非常的复合我们自身在生活中的习惯。
ok。如果上面的都明白了。那你也明白了什么叫做工厂方法模式。
他和简单工厂很相似。所以很多人混为一谈!但他是通过子类来决定建立什么样的面包。而简单工厂是有其他的类来确定建立什么样的面包。
下面看看我们的面包加盟店的类图。可能这个关系更清楚一点:
Factoryfunction.gif
解释都写在图上。就不啰嗦了=。=
定义我们的工厂方法模式:
QUOTE:
具体的工厂方法的类图Factoryfunction2.gif
工厂方法让具体的对象解脱了出来。并不再依赖具体的类。而是抽象。
它正式是复合OOP设计中非常重要的一个原则:
依赖倒置原则(经常听到,却不明白到底什么意思)
定义:
QUOTE:
看起来这个原则和上面的针对接口编程,不针对实现编程
这个原则非常的相似。但是有本质区别的
他更注重的是依赖抽象。
就像上面的面包店。本身面包店BreadStore他不能决定生产什么样的面包,他只能依赖他的底层子类来决定。
面包本身(各种面包)也不能依赖自身去决定怎么样去切片怎么样去装箱。只能依赖他的抽象类Bread。
这个原则说明了:不要让高层组件依赖于底层组件。而是不管高还是底,都应该依赖抽象对象。
换句话说。如果这个例子里所有的面包对象都是依赖面包这个具体类而建立的,就是违反了这个原则,就导致了解耦的失败。
依赖倒置原则到底倒置了哪里呢?
先想想看,你要开一个面包店会怎么考虑?
A:为了能够烘烤,切片,装到盒子里给客户,我必须先准备好不同种类的面包。黑的白的,甜的或者果仁的。甚至更多。
这样是没错的,但是这样就依赖各种面包的具体类。也就是这是从高层开始依赖。而违反了这个原则。如果我倒过来呢?
A:先提供一个抽象接口,他告诉我可以提供这些面包,而我不用担心会如何制作。
很好。这样就不用理会那些具体的面包类了。剩下的就是如何去开面包店了。思维~~~倒过来了。从底层开始往上面思考。并且依赖抽象。而不是具体的类了。
下面几个原则来告诉你如何做到尽量不要违反这个原则:切记!是尽量不要违反。而不是任何地方都不违反。这和OO设计原则一个道理的!不可能完全遵循OO设计原则而增加自己的工作两。设计原则和设计模式只是为了解决问题而存在,而不是产生问题。如果你连建立一个字符对象都用到此原则说明你有问题了。你应该思考一下这个对象将来是否会发生什么改变,如果不会发生改变,不遵循任何原则也没什么影响。
QUOTE:
你不可能完全遵守这些方针。你应该尽量达到这个原则。而不是随时都遵守这个原则。自己慢慢体会吧=。=让我们进入真正的抽象工厂模式吧。
现在我们需要进行原料控制,因为面包加盟店有些可能会偷工减料。所以我们给其指定原料工厂提供原料。
先准备一下原料工厂
上面的原料工厂里也看到了。每个原料都来至不同的原料对象。下面是对原料进行简单的定义
原料准备完毕。那如何将这个原料提供给具体的客户呢?
重点在
$material = new HNMaterialFactory();
$bread = new BlackBread($material);
这里重写了新建不同面包的对象方法。
$material就是原料工厂。告诉$bread从这个原料工厂里提取原料。这样保证完成正确的面包种类。
面包的抽象类并没有发生任何改变:
决定生产什么样的面包还是由各加盟店的子类来决定的。
下面是各种面包的定义
这里和上面的工厂方法是有区别的。大家可以自己翻上去查看。
重点改变是在新建这些面包种类的实例对象的时候在构造函数中引进了原料工厂。
真正起到作用的就是这里。
public function __construct(MaterialFactory $_factory){
$this->factory = $_factory;
}
准备工作中只是在准备,并不知道他准备的是什么口味的。所以弱耦合还是存在,并没破坏的。
由什么源材料决定什么样的面包。这是很自然的道理。
现在一切都有,只欠东风了。
输出其实和上面的一样。只是工作模式不同
QUOTE:
上面的工厂方法和简单工厂理解了的这个正式的工厂模式其实就非常容易理解了。。只是方式不同而已。可能细心的朋友已经发现了。工厂方法是蕴藏在抽象工厂模式中。通过抽象工厂所提供的接口,可以创建产品的家族。利用这个接口书写代码,我们的代码将从实际工厂解耦,以便在不同上下文中实现各种各样的工厂,制造出各种不同的产品。例如,不同的区域,不同的操作系统,不同的外观以及操作。
因为代码从实际的产品中解耦了,所以我们可以替换不同的工厂来取得不同的行为(例如,取得番茄酱料,而不是取得大蒜酱料);
好了。让我们来定义抽象工厂模式吧:
抽象工厂允许客户使用抽象的接口来创建一组相关的产品。而不需要知道(或关心)实际产出的具体产品是什么。这样一来,客户就从具体的产品中被解耦。
类图。。。。。如下。。
Factory.gif
画得比较乱。。。呃。。其实我已经理解了。只是不知道怎么用我这个软件话出来。。不能画折线。囧
至于为什么抽象工厂的方法经常以工厂方法的方式实现。。截一段深入潜出设计模式中的说明吧。
抽象工厂的任务是定义一个负责创建一组产品的接口。这个接口内的每个方法都负责创建一个具体的产品,同时,我们利用实现抽象工厂的子类来提供这些具体的做法。所以,在抽象工厂中利用工厂方法实现生产方法是相当自然的做法。
一下来区别工厂方法和抽象工厂之间:
QUOTE:
相对而言进过个人经验来判断是使用哪一个工厂模式。工厂方法相当于轻量级的设计模式。简单处理就可以使用他,只需要把抽象方法继承成子类并实现这个工厂方法就可以了。抽象工厂的范围更广泛一点。
ok。。今天工厂模式终于告一段落了。。。3个模式。你明白了吗?从简单到容易。从轻量级的简单工厂到重量级的抽象工厂。可以满足我们解耦应用程序的各项需要。根据自己项目的需求来选择吧!相信他能工作得很好。
结束。。有任何疑问请访问我的blog。。
[ 本帖最后由 某个人 于 2008-11-13 21:48 编辑 ]
很多情况下都需要类只有一个实例,比如说数据库的实例对象(可以看深空的那个数据库类。就是采用了单例模式)。因为他只有一个类图。所以说他简单。
通过几个提问,可能你能更容易的理解单例模式!
你如何创建类的实例?
使用new关键字
那如何避免一个类的实例创建?
可以这样操作么?
class MyObject{
private function __construct() {
}
}
那这样将如何获取这个类的实例?
因为构造函数已经被私有化。只有类的内部才能调用这个类的实例。外部想调用是没办法的。
那如果这样操作是不是就解决了?
class MyObject{
private function __construct() {
}
public function getInstance(){
return new MyObject;
}
}
直接外部调用getInstance()方法就能够返回这个类的实例。这样做的好处是保证整个应用程序中只有一个类的实例。当然。需要进一步的限制。为了保证这个类的实例是独一无二的。所以得在类的内部进行存储,判断。下面是标准的单例模式的例子
self的用法,我已经在我的blog进行过探讨。self代表了整个类的引用,而不是任何具体的实例引用。有兴趣的可以去看看。
类图我就不画了。挺简单的东西。就一个类。
作为单例模式。必须具有一下几个特征:
QUOTE:
其他的注意项我已经在上面的例子中进行了著名。结果我就不贴了。自己运行尝试。定义单例模式:
QUOTE:
没什么需要交代的了。就这么多。赶紧去修改自己的数据库类吧![ 本帖最后由 某个人 于 2008-11-14 13:42 编辑 ]
首先看看我们今天的例子:程序box!
我们现在给操作系统做一个程序。我想很多人用过懒人安装法吧。就是用一个应用程序列出所有的可能安装的程序。只需要点击就能安装。
现在我们需要实现的功能类似。只用一个程序盒子就来控制其他程序的开和关!但不仅仅是预定义进去的几个程序。而是在将来会有更多的程序添加进去。但整个盒子的运作必须能够正常使用。也就是说,不管添加多少应用程序,都能够实现用盒子来操作应用程序的开关等操作。
那现在我们面临的问题是什么?记住。设计模式是用来解决问题的。
各种不同程序将会有不同的方法。并且这个盒子必须能够对这些程序发出正确的指令,让其实现正确的功能。可能会有一种好的解决方案,就是将盒子的程序做得简单点,让他从其他的程序里面解耦出来。尽量保证他的简单。但这样一来似乎又不可能,因为在用户点击盒子里面的按钮的时候必须执行正确的程序。你总不希望你的程序里充满if...elseif...elseif...这样的结构。因为他是硬编码进去的。将来需要添加新的应用程序,你又要修改。并且很有可能你还要修改你的程序来复合这个盒子。
那有什么好的办法来使程序和盒子达到解耦呢?那就是今天要讲的命令模式!它能够做到。他将这个过程简单化为命令的发出者对象和命令的接受者对象。执行的是对象与对象之间的操作。这样依赖盒子就只需要知道在按了按钮后马上执行一个命令,但命令的具体内容他完全不需要知道。因为这个命令执行的具体知识是封装在命令接受者里面的。
可能这样说还是不能理解。我用一个具体的例子来说明:
到餐厅里面点菜,我们都要有这样一个过程:点菜--->服务员将订单送到厨房-->然后厨师开始做菜。
将这个过程对象化。
点菜:客户将一个包含了菜单的order写好了。传递给服务员
服务员调用这个order。然后对着厨房叫一声:准备饭菜。将整个菜单给厨师。
这样的过程就完成了一个命令模式。重点在服务员。和厨师之间的关系。服务员只需要调用准备饭菜这样的方法,厨师就开始做菜了。他们两个之间不需要任何沟通。因为服务员知道订单上面一定有这个方法,他只需要调用就可以了。厨师听到调用了准备饭菜。马上开始准备饭菜。他们两个之间就是完全解耦的
好了。看看这个例子我们怎么来写。可能你还比较迷茫。所以先从简单的开始:
再然后来写命令类
这样他就成了命令的发布者。所有需要发布命令的控制器,只需要调用上面这个类的execute方法。当然。需要将他绑定到你设计的控制器上去。我这里简单点。就两个按钮,一个按钮是开,一个是关。只控制这个文本编辑器
测试时候到了
哦。还忘记了我们的文本编辑器类
测试的结果
QUOTE:
逻辑搞清楚后,这个过程非常容易理解。EditOnCommand 和 EditOffCommand类封装具体的命令和命令接受者的绑定
EditControl类是接受者,他绑定上命令发送者。在模拟按钮(onButtonPress)的时候就能执行具体的命令。但这个按钮按下去他自己是不知道他在执行哪一个东西的命令。只知道自己执行了这个命令发送者定义好的方法。也就是服务员调用了餐厅老板定义好的:“准备饭菜”这样的方法。具体执行是在命令类的内部。所以完成了命令发布者和接受者之间的解耦。
命令模式还有一个特性是能够撤销命令的
看看我们怎么来实现他。
在命令接口里面添加这样一个方法。
QUOTE:
然后在具体命令类里面实现这个方法:接着是在控制器里面完成调用。你需要记录上一步的状态。所以需要一个变量来记录。
完成~
测试
在初始化上面都是一样的。
然后是模拟按钮有点不同
QUOTE:
结果是QUOTE:
当然你可以在代码里面控制得更好。比如说已经关闭了了再按关闭是没效果的。例子我只举一部分。。。需要看全部代码的我没打算把这个例子的全部代码写出来,可能会应用到我的类库中。所以关注我的blog吧。当完成这个模式的应用时我会发表新的日志的。当然。作为初学,希望你能来完成这个程序盒子的全部模拟过程。中间出现什么问题可以和我沟通。比如说,如果撤销的状态前一部是有属性的呢(编辑器的初始化配置)等等。
现在你大概的了解了整个过程中命令模式类和是如何互动了。
现在让我们来定义命令模式
QUOTE:
我们知道一个命令对象通过在特定接受者上绑定一组动作来封装一个请求(就像上面的EditOnCommand类需要绑定Edit的对象,然后将动作绑定到他的execute方法中),要达到这一点,命令对象将动作和接受者包进对象中。这个对象只会暴露出一个execute方法。此方法被调用的时候,接收者就会进行这些动作。从外面来看。其他对象并不知道究竟哪个接收者进行了哪些动作。只知道如果调用execute方法,请求的目的就能达到。这样做到完全的解耦。我们也看到了利用命令来参数化对象的一些例子。我们先用打开文本编辑器命令。然后可能以后又用到打开图片编辑器(具体例子自己实现。我就不写了)的命令。就和餐厅里的服务员一样。控制器并不在乎所拥有的是什么命令对象,只要这个命令对象实现了Command接口就可以了。
下面让我们来看看类图是怎么回事。可能更为清晰
Command.gif
具体的就这些了。说明都在类图上面的。不多解释了。
命令模式还能在三个方面进行应用:
宏命令(多个或一组对象同时进行命令请求。比如说一次打开多个程序。);
队列请求(php本身不支持多线成,所以这个应用不进行解释)
日志请求(比如说大量数据存储都进行日志存储,当出错后调用execute返回到日志的上一步错误点。可以说这个命令模式的应用也能应用到编辑器的保存数据上的设计上。概念是差不多的)
但具体怎么应用,暂时没有好的例子。所以。。关注鄙人的博客吧。在这个帖子只是介绍这些设计模式。不打算对每个应用都进行详细的论述。
本来鄙人是要把这个模式的例子全部完成的。但是担心是在做授人以鱼而不是渔了。所以只完成一部分。剩下的自己完成,出现问题可以到这个帖子下面跟帖,也可以到我博客给我留言。
[ 本帖最后由 某个人 于 2008-11-17 14:39 编辑 ]
但是,我还是希望我们能够了解一个迭代器具体是如何工作的。
首先我们可能经常遭遇一个问题。
就是数组,散列表或者对象列表这些等等元素的集合处理问题。比如说在无限分类中可能要涉及到处理数组。也可能自定义一群对象后,通过数组存储。我们经常操作的系统目录也属于集合的范畴。数据库的查询。。等等等。集合的涉及范围是非常广的。那我们就希望有一个统一的接口来完成一个迭代工作。而不用担心具体的迭代过程是怎么样的。简单的说:迭代器让我们能够游走于聚合内的每一个元素,而又不暴露其内部的表示(比如循环。各种不同的集合的循条件是不同的。)。
如果不明白?我可以举个例子。比如我们需要对一个字符串的每个字节进行处理。
那就可能for($i=0;i<strlen($string);$i++)这样操作来处理字符串的每个字节。
另一个例子是数组。可能会for($i=0;i<count($array);$i++)这样来操作处理的字符串。
当我们同一个项目里不停的使用循环的时候。就得不停的转换两种循环模式和循环条件。面向对象是Everything is Object!
当我们把数组或者其他形式的集合通过对象的形式调用和处理的时候。可能会遭遇一些问题。比如说下面这个现实生活中的例子。
有两家书店。他们卖了很多书(废话。去死.囧)。他们加入了一个书市联盟。联盟希望他们提供自己店的书目清单。看起来不错的主意,但是出现了一个问题。
两家书店的书目存储的方式完全不同。A书店用的是数组存储。B书店因为种种原因用的字符串处理。可联盟又希望获取到他们的数目清单。这该如何操作呢?毕竟两家书店的数据都是庞大的。不可能因为一个联盟的要求而改变自己的数组存放方式。A和B也并不愿意这样。
好的。先看看他们两家的代码如何。可能会在这里找到问题的结症。
书店A:
书店B
现在有一个共同的书目手册让他们输出自己的书目列表。
看起来并没有什么问题。但是,如果有更多的书店来加入这个联盟呢?而有的是用XML。有的是用数据库。甚至有的是用单一对象呢?
难道有多少就要做多少个循环处理吗?
no!绝对不行。记得一直强调的设计原则吗?一定一定要记住!改变是面向对象的敌人。一切问题都是因为改变而带来的。
改变的地方很明显了。就是输出时要进行多次的循环处理。
那用迭代器吧,将所有的循环封装起来。不再暴露出循环处理过程。
迭代器是个接口动作。所以我们需要创建一个接口,然后为这个接口实现提供一个迭代类。
当然,在此之前。我们必须了解迭代器是如何工作的。
QUOTE:
只是BookA和BookB两者都通过getItterator方法返回迭代器对象。这个对象封装好了hasNext方法判断是否有下一项。而next方法封装跳到下一项。这样一来。对于外部来讲。只知道BookA正在遍历内部的对象。而不需要知道任何这个便利过程。好了。让这就是我们的迭代器模式的威力。。看看我们如何实现他吧。跟着我动手吧。可能你还不知道该如何下手。记住。从上往下写,总有帮助的。所以先来完成接口
实现具体的迭代器
对书店的书目调用得改,需要返回一个迭代器对象
同样的书店B
最后,对我们的书目做修改
实现一下
$booka=new BookA();
$bookb=new BookB();
$a = new BookList($booka,$bookb);
$a->Menu();
显示和上面的例子是一样的。但是我们看看我们对这个例子做了这么多修改干了些什么。
让他不再针对的是具体的数组还是字符串了。管他的。我只知道书目正在遍历一个对象。他会给我看东西的。过程我并不需要知道。
让他更具扩展性。当第3个书店加入进来的时候,只需要修改menu方法。其他的都不用管。最重要的是。你不需要知道这个新的书店是什么东西存储的(当然,在我的例子里,我的迭代器只处理了数组和字符串的形式。SPL提供了更多的真正的迭代器,下面我会讲的)。
不再需要两个或者更多的循环。因为有人会完成这个工作的。一个循环遍历这个对象就够了。看仔细哦。这个循环的表象是在对这个对象进行循环。而不是任何特定的种类。解耦性良好。
当然。这还有缺陷,就是不是针对的公共的接口,而是两个不同的接口( 主要是说这里。public function __construct(BookA $_booka,BookB $_bookb))。当我们学习了SPL提供的封装的迭代器。这个问题会有很好的解决方案。
需要我画类图么?应该不需要。这个迭代器模式的类图是非常简单的。当然。。我也偶尔偷一下懒。不可能什么都要我来给你完成。还是自己动手吧。不懂的再来问我怎么做。
下面定义一下迭代器到底是怎么回事。其实上面已经说了他的定义。再来回顾一下把:
QUOTE:
当然,我的例子里只是对数组这样操作了。看其来并没多大意义。但是,迭代器最大的意义是让你可以将任何形式的循环遍历都能够像对数组一样简单的操作。迭代器这样做是很有意义的:这个模式提供了一种方法,可以顺序访问一个聚集对象中的元素,而又不用知道内部是如何表示的。另一个对你的设计造成重要影响的,是迭代器模式把在元素之间游走的责任交给了迭代器,而不是聚合对象。这不仅让聚合的接口和实现变得简介,也可以让聚合更专注于在它所应该专注的事情上面,而不必去理会遍历的事情。
迭代器原理讲解完毕。下面要讲的是SPL提供的种种迭代类库。可能有人会问为什么一开始不讲SPL的迭代器。道理很简单。因为你不知道本质是如何运行的。你就不知道如何去使用。这是软件工程的基本原理。虽然封装很重要。但那是针对客户,而不是你自己。你必须大致的了解如何创建一个迭代器。才能更好的使用SPL提供的迭代器。因为总有不顺手的武器,既然已经提供了种种接口,就用那些零件拼装出适合自己的武器吧。然而如果你不知道武器的原理。你根本不可能完成这一点
[ 本帖最后由 某个人 于 2008-11-19 16:57 编辑 ]
QUOTE:
我刚下玩CHM手册和搭建好环境。。。还在下zend。。万恶的网速。。。。首先你得让大家知道为什么会有这些设计模式.不能盲目的去学习.
最好先介绍一下 开闭原则 里矢代换原则 依赖倒转原则
比如策略模式和这些原则的关系:
我们依赖于抽象策略而不是具体策略 --依赖倒转原则
每一种具体的策略都能取代抽象策略的位置 --里矢代换原则
每当出现新的策略,直接添加,而不需要任何修改 --开闭原则
同意ZF的,
基本原则, 是OO设计的核心.
模式, 是设计的经验
《深入浅出 设计模式》是本好书, 很适合初学者
不过表现得不是很好哈。呵呵~~很好的意见。。以为自己懂了。。别人也明白了。。就一笔带过了。。过错过错。
现在开始完成第二章
QUOTE:
考虑了很久。。才决定先完成这个。。。因为思路是最重要的。如何实现是次要的。。。反正我天天在家呆着。。。完成是迟早的。而且是集中分析完成。这样思维上才足够连贯。