工厂模式
在大型系统中,许多代码依赖于少数几个关键类。需要更改这些类时,可能会出现困难。例如,假设您有一个从文件读取的 User
类。您希望将其更改为从数据库读取的其他类,但是,所有的代码都引用从文件读取的原始类。这时候,使用工厂模式会很方便。
工厂模式 是一种类,它具有为您创建对象的某些方法。您可以使用工厂类创建对象,而不直接使用 new
。这样,如果您想要更改所创建的对象类型,只需更改该工厂即可。使用该工厂的所有代码会自动更改。
清单 1 显示工厂类的一个示列。等式的服务器端包括两个部分:数据库和一组 PHP 页面,这些页面允许您添加反馈、请求反馈列表并获取与特定反馈相关的文章。
清单 1. Factory1.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
<?php
interface
IUser
{
function
getName();
}
class
User
implements
IUser
{
public
function
__construct(
$id
) { }
public
function
getName()
{
return
"Jack"``;
}
}
class
UserFactory
{
public
static
function
Create(
$id
)
{
return
new
User(
$id
);
}
}
$uo
= UserFactory::Create( 1 );
echo``(
$uo``->getName().``"\n"
);
?>
单元素模式(单列模式)
某些应用程序资源是_独占的_,因为有且只有一个此类型的资源。例如,通过数据库句柄到数据库的连接是独占的。您希望在应用程序中共享数据库句柄,因为在保持连接打开或关闭时,它是一种开销,在获取单个页面的过程中更是如此。
单元素模式可以满足此要求。如果应用程序每次包含且仅包含一个对象,那么这个对象就是一个_单元素_(Singleton)。清单 3 中的代码显示了 PHP V5 中的一个数据库连接单元素。
- php的应用主要在于数据库应用, 一个应用中会存在大量的数据库操作, 在使用面向对象的方式开发时, 如果使用单例模式, 则可以避免大量的new 操作消耗的资源,还可以减少数据库连接这样就不容易出现 too many connections情况。
- 如果系统中需要有一个类来全局控制某些配置信息, 那么使用单例模式可以很方便的实现. 这个可以参看zend Framework的FrontController部分。
- 在一次页面请求中, 便于进行调
清单 3. Singleton.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
<?php
require_once``(``"DB.php"``);
class
DatabaseConnection
{
public
static
function
get()
{
static
$db
= null;
if
(
$db
== null )
$db
=
new
DatabaseConnection();
return
$db``;
}
private
$_handle
= null;
private
function
__construct()
{
$dsn
=
'mysql://root:password@localhost/photos'``;
$this``->_handle =& DB::Connect(
$dsn``,
array``() );
}
public
function
handle()
{
return
$this``->_handle;
}
}
print``(
"Handle = "``.DatabaseConnection::get()->handle().``"\n"
);
print``(
"Handle = "``.DatabaseConnection::get()->handle().``"\n"
);
?>
您可以使用全局变量存储数据库句柄,但是,该方法仅适用于较小的应用程序。在较大的应用程序中,应避免使用全局变量,并使用对象和方法访问资源。
观察者模式
观察者模式为您提供了避免组件之间紧密耦合的另一种方法。该模式非常简单:一个对象通过添加一个方法(该方法允许另一个对象,即_观察者_ 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者使用该信息执行的操作与可观察的对象无关。结果是对象可以相互对话,而不必了解原因。
一个简单示例是系统中的用户列表。清单 4 中的代码显示一个用户列表,添加用户时,它将发送出一条消息。添加用户时,通过发送消息的日志观察者可以观察此列表。
清单 4. Observer.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
<?php
interface
IObserver
{
function
onChanged(
$sender``,
$args
);
}
interface
IObservable
{
function
addObserver(
$observer
);
}
class
UserList
implements
IObservable
{
private
$_observers
=
array``();
public
function
addCustomer(
$name
)
{
foreach``(
$this``->_observers
as
$obs
)
$obs``->onChanged(
$this``,
$name
);
}
public
function
addObserver(
$observer
)
{
$this``->_observers []=
$observer``;
}
}
class
UserListLogger
implements
IObserver
{
public
function
onChanged(
$sender``,
$args
)
{
echo``(
"'$args' added to user list\n"
);
}
}
$ul
=
new
UserList();
$ul``->addObserver(
new
UserListLogger() );
$ul``->add
此代码定义四个元素:两个接口和两个类。IObservable
接口定义可以被观察的对象,UserList
实现该接口,以便将本身注册为可观察。IObserver
列表定义要通过怎样的方法才能成为观察者,UserListLogger
实现 IObserver
接口。图 4 的 UML 中展示了这些元素。
图 4. 可观察的用户列表和用户列表事件日志程序
如果在命令行中运行它,您将看到以下输出:
% php observer.php 'Jack' added to user list %
测试代码创建 UserList
,并将 UserListLogger
观察者添加到其中。然后添加一个消费者,并将这一更改通知 UserListLogger
。
认识到 UserList
不知道日志程序将执行什么操作很关键。可能存在一个或多个执行其他操作的侦听程序。例如,您可能有一个向新用户发送消息的观察者,欢迎新用户使用该系统。这种方法的价值在于 UserList
忽略所有依赖它的对象,它主要关注在列表更改时维护用户列表并发送消息这一工作。
此模式不限于内存中的对象。它是在较大的应用程序中使用的数据库驱动的消息查询系统的基础。
策略模式
我们讲述的最后一个设计模式是_策略_ 模式。在此模式中,算法是从复杂类提取的,因而可以方便地替换。例如,如果要更改搜索引擎中排列页的方法,则策略模式是一个不错的选择。思考一下搜索引擎的几个部分 —— 一部分遍历页面,一部分对每页排列,另一部分基于排列的结果排序。在复杂的示例中,这些部分都在同一个类中。通过使用策略模式,您可将排列部分放入另一个类中,以便更改页排列的方式,而不影响搜索引擎的其余代码。
清单 5. Strategy.php