标签归档:读书总结

PHP设计模式笔记:使用PHP实现访问者模式

PHP中的设计模式笔记:访问者模式

【Visitor模式】
访问者模式表示一个作用于某对象结构中各元素的操作。它可以在不修改各元素类的前提下定义作用于这些元素的新操作,即动态的增加具体访问者角色。
访问者模式利用了双重分派。先将访问者传入元素对象的Accept方法中,然后元素对象再将自己传入访问者,之后访问者执行元素的相应方法。
访问者模式多用在聚集类型多样的情况下。在普通的形式下必须判断每个元素是属于什么类型然后进行相应的操作,从而诞生出冗长的条件转移语句。而访问者模式则可以比较好的解决这个问题。对每个元素统一调用$element->accept($vistor)即可。
访问者模式多用于被访问的类结构比较稳定的情况下,即不会随便添加子类。访问者模式允许被访问结构添加新的方法。
Visitor模式实际上是分离了对象结构中的元素和对这些元素进行操作的行为,从而使我们在根据对象结构中的元素进行方法调用的时候,不需要使用IF语句判断
也就是封装了操作
但是,如果增加新的元素节点,则会导致包括访问者接口及其子类的改变,这就会违反了面向对象中的开闭原则
当这种情况出现时,一般表示访问者模式已经可能不再适用了,或者说设计时就有问题了!

【Visitor模式结构图】

访问者模式简略图

访问者模式简略图



【Visitor模式中主要角色】
1)抽象访问者角色(Visitor):为该对象结构(ObjectStructure)中的每一个具体元素提供一个访问操作接口。该操作接口的名字和参数标识了 要访问的具体元素角色。这样访问者就可以通过该元素角色的特定接口直接访问它。
2)具体访问者角色(ConcreteVisitor):实现抽象访问者角色接口中针对各个具体元素角色声明的操作。
3)抽象节点(Node)角色:该接口定义一个accept操作接受具体的访问者。
4)具体节点(Node)角色:实现抽象节点角色中的accept操作。
5) 对象结构角色(ObjectStructure):这是使用访问者模式必备的角色。它要具备以下特征:能枚举它的元素;可以提供一个高层的接口以允许该访问者访问它的元素;可以是一个复合(组合模式)或是一个集合,如一个列表或一个无序集合(在PHP中我们使用数组代替,因为PHP中的数组本来就是一个可以放置任何类型数据的集合)

【Visitor模式的优缺点】
访问者模式有如下的优点:
1)访问者模式使得增加新的操作变得很容易。使用访问者模式可以在不用修改具体元素类的情况下增加新的操作。它主要是通过元素类的accept方法来接受一个新的visitor对象来实现的。如果一些操作依赖于一个复杂的结构对象的话,那么一般而言,增加新的操作会很复杂。而使用访问者模式,增加新的操作就意味着增加一个新的访问者类,因此,变得很容易。
2)访问者模式将有关的行为集中到一个访问者对象中,而不是分散到一个个的节点类中。
3)访问者模式可以跨过几个类的等级结构访问属于不同的等级结构的成员类。迭代子只能访问属于同一个类型等级结构的成员对象,而不能访问属于不同等级结构的对象。访问者模式可以做到这一点。
4)积累状态。每一个单独的访问者对象都集中了相关的行为,从而也就可以在访问的过程中将执行操作的状态积累在自己内部,而不是分散到很多的节点对象中。这是有益于系统维护的优点。

访问者模式有如下的缺点:
1)增加新的节点类变得很困难。每增加一个新的节点都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每一个具体访问者类中增加相应的具体操作。
2)破坏封装。访问者模式要求访问者对象访问并调用每一个节点对象的操作,这隐含了一个对所有节点对象的要求:它们必须暴露一些自己的操作和内部状态。不然,访问者的访问就变得没有意义。由于访问者对象自己会积累访问操作所需的状态,从而使这些状态不再存储在节点对象中,这也是破坏封装的。

使用Visitor模式的前提: 对象群结构中(Collection) 中的对象类型很少改变。
在接口Visitor和Element中,确保Element很少变化,也就是说,确保不能频繁的添加新的Element元素类型加进来,可以变化的是访问者行为或操作,也就是Visitor的不同子类可以有多种,这样使用访问者模式最方便.
如果对象集合中的对象集合经常有变化, 那么不但Visitor实现要变化,ConcreteVisitor也要增加相应行为,GOF建议是,不如在这些对象类中直接逐个定义操作,无需使用访问者设计模式。

【Visitor模式与其它模式】
1、如果所浏览的结构对象是线性的,使用迭代模式而不是访问者模式也是可以的
2、访问者模式浏览合成模式的一些结构对象
以上两点来自《Java与模式》一书

【Visitor模式PHP示例】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
 
 
<?php
/**
 * 访问者模式 2010-05-13 sz
 * @author phppan.p#gmail.com
 * @package design pattern
 */
 
interface Visitor {
    public function visitConcreteElementA(ConcreteElementA $elementA);
    public function visitConcreteElementB(concreteElementB $elementB);
}
 
interface Element {
    public function accept(Visitor $visitor);
}
 
/**
 * 具体的访问者1
 */
class ConcreteVisitor1 implements Visitor {
    public function visitConcreteElementA(ConcreteElementA $elementA) {
        echo $elementA->getName() . " visitd by ConcerteVisitor1 <br />";
    }
 
    public function visitConcreteElementB(ConcreteElementB $elementB) {
        echo $elementB->getName() . " visited by ConcerteVisitor1 <br />";
    }
 
}
 
/**
 * 具体的访问者2
 */
class ConcreteVisitor2 implements Visitor {
    public function visitConcreteElementA(ConcreteElementA $elementA) {
        echo $elementA->getName() . " visitd by ConcerteVisitor2 <br />";
    }
 
    public function visitConcreteElementB(ConcreteElementB $elementB) {
        echo $elementB->getName() . " visited by ConcerteVisitor2 <br />";
    }
 
}
 
/**
 * 具体元素A
 */
class ConcreteElementA implements Element {
    private $_name;
 
    public function __construct($name) {
        $this->_name = $name;
    }
 
    public function getName() {
        return $this->_name;
    }
 
    /**
     * 接受访问者调用它针对该元素的新方法
     * @param Visitor $visitor
     */
    public function accept(Visitor $visitor) {
        $visitor->visitConcreteElementA($this);
    }
 
}
 
/**
 *  具体元素B
 */
class ConcreteElementB implements Element {
    private $_name;
 
    public function __construct($name) {
        $this->_name = $name;
    }
 
    public function getName() {
        return $this->_name;
    }
 
    /**
     * 接受访问者调用它针对该元素的新方法
     * @param Visitor $visitor
     */
    public function accept(Visitor $visitor) {
        $visitor->visitConcreteElementB($this);
    }
 
}
 
/**
 * 对象结构 即元素的集合
 */
class ObjectStructure {
    private $_collection;
 
    public function __construct() {
        $this->_collection = array();
    }
 
 
    public function attach(Element $element) {
        return array_push($this->_collection, $element);
    }
 
    public function detach(Element $element) {
        $index = array_search($element, $this->_collection);
        if ($index !== FALSE) {
            unset($this->_collection[$index]);
        }
 
        return $index;
    }
 
    public function accept(Visitor $visitor) {
        foreach ($this->_collection as $element) {
            $element->accept($visitor);
        }
    }
}
 
class Client {
 
     /**
     * Main program.
     */
    public static function main() {
        $elementA = new ConcreteElementA("ElementA");
        $elementB = new ConcreteElementB("ElementB");
        $elementA2 = new ConcreteElementB("ElementA2");
        $visitor1 = new ConcreteVisitor1();
        $visitor2 = new ConcreteVisitor2();
 
        $os = new ObjectStructure();
        $os->attach($elementA);
        $os->attach($elementB);
        $os->attach($elementA2);
        $os->detach($elementA);
        $os->accept($visitor1);
        $os->accept($visitor2);
    }
 
}
 
Client::main();
?>

【–EOF–】

Oreilly.Developing.Large.Web.Applications.Mar.2010读后记录

Oreilly.Developing.Large.Web.Applications.Mar.2010读后记录

【概要】
作者偏向于使用动态语言将JS,CSS,HTML等代码全部封装在类中,从而实现整个应用的模块化
包括页面的模块化,数据的模块化,CSS的模块化,JS的模块化
读完全书…… 感觉有些纠结,不知道作者想干嘛,模块化?封装?应该是我水平不够!

【关键字】
模块化,封装,面向对象
内容,结构,表现,行为分离

【章节介绍与体会】
chapter1 The Tenets
总体介绍了这本书,差不多就是将整本书的每个章节进行了简单的说明
其中就模块化组件进行了介绍
原则一:由模块化组件构成的大型WEB应用是高可用的,可维护和可靠的
原则二:在大型WEB应用中,使用面向对象的JavaScript和服务器端脚本将推动应用的模块化,从而提高应用的可重用性,可维护性和可靠性
原则三:HTML是语义化,它本身是缺乏表现元素的, 但是它能以一种容易识别内容的形式插入到多种环境
HTML是一种对文本内容进行结构和意义(或者说“语义”)进行补充的方法
关于HTML的语义化的好处请猛击:http://www.vogim.com/teach/tutorial_show.aspx?id=395
原则四:CSS是信息架构的表现层,可以以模块化的形式在各种环境下复用
原则五:JavaScript是信息架构的行为层,可以以模块化和面向对象的形式在各种环境下复用
原则六:在用户接口与后端之间的数据交换可以通过一个清晰的数据接口定义来管理。页面定义一个单一的的点来加载和保存数据
原则七:以高可用性的模块组成的页面封装一切需要的东西(如HTML,CSS,JavaScript及其它),这可以使每个模块以独立的功能模块和聚合的单位用于各种环境的各个页面
原则八:Ajax是轻量和模块化的,并且在数据交换和更新之间保持一个清晰的隔离。在浏览器和服务器之间的数据交换可以通过一个定义清楚的接口来进行管理
原则九:大型HTML,JavaScript,CSS和PHP为建造一个大型的WEB应用提供了一个好的基础。他们还提升了网站测量和测试的环境
原则十:大型WEb应用的文件组织结构反映了这个应用的架构,其中包括明确划分每个文件的使用范围

chapter2 Object Orientation
这一章首先概述了面向对象以及为什么使用面向对象是一种比较好的方法,然后简单介绍了uml以及如何以面向对象的方式展现一个web页面,最后作者讲了PHP和Javascript中面向对象的一些基础知识
其中特别指出PHP是基于类的语言,而javascript是基于原型(或对象)的语言

chapter3 Large-Scale HTML
阐述了模块化对于一个好的信息架构的重要性,以及如何模块化HTML,其中推荐语义化的HTML
然后作者对于我们常用的HTML标签进行了区分,分出哪些是好的标签(例如:strong,div,body,ul,li等等),哪些是坏的(例如:font,i,hr,d等)
然后就id,class,name作了说明;
一个id在一个页面中只能出现一次
class是语义化的元素的一个集合,可以在一个页面出现多次
name属性用于表单提交数据到服务器
关于id和name的相同点和不同点请移步: http://www.phppan.com/2009/09/id-and-name-attribute-in-html/
然后就RDFa,XHTML及HTML5作了简单说明

chapter4 Large-Scale CSS
同样,在本章作者提出了模块化CSS的概念
一个好的WEB系统的表现层是通过CSS来实现的
首先说明了包含CSS的三个方法:链接,内联,嵌入,在嵌入CSS后,我们需要应用这些CSS,那么此时我们就会用到id(以#开头), class(以.号开头)以及使用后代(以空格隔开),元素,组(以逗号隔开)
然后介绍了CSS的应用范围,如模块级,页面级,其中就页面级范围,作者给了一个在body中添加id属性,使用CSS的后代应用方式控制显示的方法()
在本章的第二节,作者介绍了CSS中的定位技术,其中就盒子模型,文档流,相对定位,绝对定位和浮动,这对CSS的定位技术有一个不失简单的说明
第三节就层与容器分别作了一个简单的 示例,然后第四节就CSS重置及字体设置进行了简单说明,其中作者推荐使用YUI进行操作

chapter5 Large-Scale JavaScript
同CSS一样,作者提出了模块化Javascript的概念
首先在第一节作者对于包含Javascript进行了说明:它与CSS一样包含三种方法:链接,内联,嵌入,然后介绍了JS的命名空间和依据ID访问module
第二节介绍了DOM,以及常用的类库中的DOM
第三节介绍了事件驱动应用
第四节介绍了一些JS实现动画效果(动作,尺寸,颜色)

chapter6 Data Management
数据分为静态数据和动态数据,不同的数据的管理策略也不同
定义数据接口,所有的数据都从数据接口中获取,每个页面仅有一个点来获取数据
数据管理者是一个抽象和封装了特殊数据集的对象,并非每个模块都会有相应的数据管理者,也存在共用的数据管理者
在作者示例中可以看到数据管理者都会有相同的方法保存数据和获取数据,并且还提到了使用继承和委托的方式扩展数据
作者提到可用的数据源包括:SQL(数据库),XML
可以使用来自网络的数据,它通常包括XML格式或JSON格式
在本章的最后,作者介绍了cookie的数据管理,及表单的数据管理($_GET, $POST, $_REQUEST)

chapter7 Large-Scale PHP
整个章节都是围绕Page类来进行,从创建到使用
page类将包含一个页面的所有元素,将JS,CSS等文件也聚合在一起
包括数据的加载和保存,并依据模块创建内容
在这个类中包括JS管理,CSS管理,动态数据管理,页面内容管理,页面公用元素管理

层和容器是模块化的特殊形式

chapter8 Large-Scale Ajax
Ajax是旧技术的集合,是新瓶装旧酒的过程
通过 XMLHttpRequest对象向服务器发送异步请求,获取数据并在前台页面做局部的更新
Ajax在页面中通过Javascript与服务器建立连接,并更新页面。
Ajax支持基本的GET和POST方法
在服务器对于Ajax发送的请求处理需要注意三个方面:1、选择一种数据格式;2、使用服务器代理;3、模块化
MVC是基于发布/订阅模式(观察都模式)?

chapter9 Performance
作者推荐了High Performance Web Site这本书
缓存很重要,我们可以缓存CSS文件,JS文件,图片,甚至模块化的实体内容和页面
对于不是经常变化的数据和文件,缓存是一种不错的优化方案
给CSS文件和JS文件添加版本
合并CSS文件,合并JS文件,减少连接数
缓存模块化内容
缓存Ajax内容
使用Expires
压缩JS
减少重复
…………
(整章内容貌似都是拿yahoo军规说事)

chapter10 Application Architecture
整个应用程序的文件目录的组织

–EOF–

High Performance Web Site(高性能网站)读后感

High Performance Web Site读后感

看到五月的程序员杂志上江永源童鞋有对yahoo优化原则的总结:
合并小数据文件到一个请求
拆分大数据文件到多个请求
优化文件内容、压缩、减少不必要的数据传输
缓存可以缓存的数据、文件

以前看过这本书的中文版,也看过别人写的简单版本以及yahoo军规34条,对其中的内容比较熟悉,
这次再看其英文版本,有感如下:

用户访问一个页面,就是将用户所需要的东西从服务器端传输到客户端的过程,那么如何减少这个传输时间呢?
第一:【减少传输的内容】
在不影响效果的情况下减少传输的内容
规则四:Gzip Components Gzip压缩
通过压缩,缩小文件体积,从而达到减少传输内容的目的
规则八:Make JavaScript and CSS External 将JS和CSS外链
将js和css外链,或者说是放在其它域名下,可以提高并发数,利用规则
规则十:Minify JavaScript and CSS 减小JS和CSS的体积
写JS和CSS都是有技巧的,用最少的代码实现同样的功能,减少空白,增强逻辑性,用缩写方式等等
规则十二:Remove Duplicate Scripts 删除重复脚本
规则十三:Configure ETags 设定ETags
规则十四: Make Ajax Cacheable 让Ajax可以缓存

第二:【提高传输速度,减少传输距离,减少其它计算或查找时间】
规则二:Use a Content Delivery Network 利用CDN技术
规则九:Reduce DNS Lookups 减少DNS查找
规则十一:Avoid Redirects 避免重定向

第三:【减少传输的次数】
一般来说,一个页面肯定有多个内容需要从服务器传输到客户端,此时我们需要减少传输的次数
规则一:减少HTTP请求,
就严重强调了其重要性,几种常见的方法:1,合并文件,2、CSS Sprites,3、图象地图,4、内联图像
规则三:Add an Expires 设置头文件过期,
缓存只是在用户非首次访问页面时有用,这也同样减少了传输的内容

第四:【用户体验】(渲染应该会更加贴切一些)
规则五:Put Stylesheets at the Top 把CSS放顶部
让浏览者能尽早的看到网站的完整样式,并且可以利用浏览器的加载效果
规则六:把JS放底部
网站呈现完毕后再进行功能设置,当然这些JS要在你的加载过程中不影响内容表现
规则七:Avoid CSS Expressions 避免CSS Expressions

以上只是以我自己的理解将十四条规则做了一个简单的分类,仅个人看法
另外,觉得书中所说的前端优化是在已有条件的基础上做的一些细节部分的调整,从而提高整体的前端性能
不过对于优化来说,后端的优化还是灰常重要的

over