从魔兽看PHP设计模式_PHP
前段时间看到有人用魔兽来解释设计模式,感觉很有意思,于是我把它改了改,又添加了些设计模式内容,今天发出来。有些地方借鉴了前人的内容,没有注明,请前人不要见怪啊。
这里用大家感兴趣的魔兽3来讨论PHP的几种常见的设计模式:单件模式、策略模式、工厂模式、观察者模式。今天就讲这四个吧,以后继续。
这些设计模式,都是针对面向对象来说的,所以都用PHP5,另外在这里我想说的是PHP4从2008年8月8日(我记得是和北京奥运会同一天,没查证,呵呵)的时候官方就发了最后一个PHP4的补丁,这意味这PHP4的时代已经终结,所以,我建议大家现在就别理PHP4吧,就以PHP5来说吧。
一、单件模式:
问题的提出:
某些应用程序资源是独占的,因为有且只有一个此类型的资源。例如,通过数据库句柄到数据库的连接是独占的。您希望在应用程序中共享数据库句柄,因为在保持连接打开或关闭时,它是一种开销,在获取单个页面的过程中更是如此。
问题的解决:
那么下面我们就开始玩魔兽吧。首先双击war3.exe,这时候就开始运行魔兽了。我们用代码来实现吧。
class War3
{
public function __construct()
{
echo "War3 is Running.","
";
}
}
$war = new War3();
运行!很好,输出
War3 is Running.
我们已经可以开始游戏了,但是,如果我在代码末尾再加入
$war2 = new War3();
$war3 = new War3();
会怎么样呢?我们试试,输出结果:
War3 is Running.
War3 is Running.
War3 is Running.
完了,如果不小心双击了两次就开了3个魔兽,那如果再双击几次,那电脑肯定爆掉。。。我们还是来想想解决方法吧。
既然我们不能这么随意的就把这个类实例化了,那么我们就把构造函数改成私有方法。
class War3
{
private function __construct()
{
echo "War3 is Running.","
";
}
}
可是私有变量外部是无法访问的,这样以来,我们就连一个都打不开了啊。别急,我们再给他加一个不用通过实例化,外部也能访问的函数,那就是静态函数,
class War3
{
private function __construct()
{
echo "War3 is Running.","
";
}
public static function runWar()
{
}
}
通过这个静态的方法runWar()我们来控制类War3的实例化,那么还缺上一个标识,我们再创建一个标识,通过这个标识来表示我们的类是否已经实例化,如果实例化,直接返回句柄就行了。
把类修改成
class War3
{
protected static $_instance = null;
private function __construct()
{
echo "War3 is Running.","
";
}
public static function runWar()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
}
当然,我们运行魔兽时的实例化也要换种方法,就通过
$war = War3::runWar();
就能开始玩魔兽了,好了,下面把完整的代码附上来:
class War3
{
protected static $_instance = null;
private function __construct()
{
echo "War3 is Running.","
";
}
public static function runWar()
{
if (null === self::$_instance) {
self::$_instance = new self();
}
return self::$_instance;
}
}
$war = War3::runWar();
$war2 = War3::runWar();
$war3 = War3::runWar();
运行一下,结果是:
War3 is Running.
太好了,我双击了这么多次,也就只运行了一个魔兽,现在随便你怎么打开,机子都不会爆掉了。
这就是传说中的单价模式,主要用于一些很占资源的而且实例仅有一个实例就够用的东西,比如,zend framework中的Zend_Controller_Front前端控制器,就是采用单价模式来设计的,大家有兴趣的话可以看看那个。
二、策略模式:
问题的提出:
在此模式中,算法是从复杂类提取的,因而可以方便地替换。例如,如果要更改搜索引擎中排列页的方法,则策略模式是一个不错的选择。思考一下搜索引擎的几个部分 —— 一部分遍历页面,一部分对每页排列,另一部分基于排列的结果排序。在复杂的示例中,这些部分都在同一个类中。通过使用策略模式,您可将排列部分放入另一个类中,以便更改页排列的方式,而不影响搜索引擎的其余代码。
问题的解决:
呵呵,不讲那么复杂,刚才魔兽好不容易打开了,我们还是玩魔兽好了。
下面我们选battle,哇好多种族啊,有人族(Human),兽族(ORC),暗夜精灵族(Nighy Elf),不死族(Undead)。我选精灵族(Nighy Elf),再选一个精灵族和两个兽族(ORC),一个兽族和我是一家的,另一个精灵族和兽族是另一家的。
每一个玩家在进入游戏后都会得到一些资源,如一个大厅,五个小精灵(苦工)和一个矿山。这些可以称为是初始化的一些东西,这里我们就可以用到策略模式来封装这些初始化。
进入正题,首先我们来构建一个玩家类:
class player
{
//玩家名字
protected $_name;
//种族
protected $_race;
//队伍
protected $army;
//建筑
protected $building;
//人口
protected $population;
//黄金
protected $gold;
//木材
protected $wood;
//构造函数,设定所属种族
public function __construct($race)
{
$this->race = $race;
}
//__get()方法用来获取保护属性
private function __get($property_name)
{
if(isset($this->$property_name)) {
return($this->$property_name);
}
else {
return(NULL);
}
}
//__set()方法用来设置保护属性
private function__set($property_name,$value)
{
$this->$property_name=$value;
}
}
接着,我们再建一个玩家初始化的接口,
interface initialPlayer
{
//制造初始化的部队
public function giveArmy($player);
//制造初始化的建筑
public function giveBuilding($player);
//初始化资源
public function giveSource($player);
}
好了,到这里我们就该对这个接口来实现了,为了方便,我只选了两个种族,就只写这两个种族的初始化了:
首先是精灵族:
class NighyElfInitial implements initialPlayer
{
//制造初始化的部队
public function giveArmy($player)
{
//五个小精灵
for($i=0; $i
{
$creator = new CreatArms();//这个是创建部队类,在后面得工厂模式中会用到,这里我就不多说了
$player->army[] = $creator->Creat('Wisp','./Arms/');
}
}
//制造初始化的建筑
public function giveBuilding($player)
{
$creator = new CreatBuildings();
//一个基地
$player->building[] = $creator->Creat('TownHall','./Buildings/');
//一个矿场
$player->building[] = $creator->Creat('Mine','./Buildings/');
}
//初始化人口上限
public function giveSource($player)
{
$player->population= 10;
$player->gold= 1000;
$player->wood= 100;
}
}
接下来是兽族:
class ORCInitial implements initialPlayer
{
//制造初始化的部队
public function giveArmy($player)
{
//五个苦工
for($i=0; $i
{
$creator = new CreatArms();//这个是创建部队类,在后面得工厂模式中会用到,这里我就不多说了
$player->army[] = $creator->Creat('Peon','./Arms/');
}
}
//制造初始化的建筑
public function giveBuilding($player)
{
$creator = new CreatBuildings();
//一个基地
$player->building[] = $creator->Creat('TownHall','./Buildings/');
//一个矿场
$player->building[] = $creator->Creat('Mine','./Buildings/');
}
//初始化人口上限
public function giveSource($player)
{
$player->population= 10;
$player->gold= 1000;
$player->wood= 100;
}
}

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

JWT是一种基于JSON的开放标准,用于在各方之间安全地传输信息,主要用于身份验证和信息交换。1.JWT由Header、Payload和Signature三部分组成。2.JWT的工作原理包括生成JWT、验证JWT和解析Payload三个步骤。3.在PHP中使用JWT进行身份验证时,可以生成和验证JWT,并在高级用法中包含用户角色和权限信息。4.常见错误包括签名验证失败、令牌过期和Payload过大,调试技巧包括使用调试工具和日志记录。5.性能优化和最佳实践包括使用合适的签名算法、合理设置有效期、

文章讨论了PHP 5.3中引入的PHP中的晚期静态结合(LSB),从而允许静态方法的运行时分辨率调用以获得更灵活的继承。 LSB的实用应用和潜在的触摸

会话劫持可以通过以下步骤实现:1.获取会话ID,2.使用会话ID,3.保持会话活跃。在PHP中防范会话劫持的方法包括:1.使用session_regenerate_id()函数重新生成会话ID,2.通过数据库存储会话数据,3.确保所有会话数据通过HTTPS传输。

SOLID原则在PHP开发中的应用包括:1.单一职责原则(SRP):每个类只负责一个功能。2.开闭原则(OCP):通过扩展而非修改实现变化。3.里氏替换原则(LSP):子类可替换基类而不影响程序正确性。4.接口隔离原则(ISP):使用细粒度接口避免依赖不使用的方法。5.依赖倒置原则(DIP):高低层次模块都依赖于抽象,通过依赖注入实现。

如何在系统重启后自动设置unixsocket的权限每次系统重启后,我们都需要执行以下命令来修改unixsocket的权限:sudo...

在PHPStorm中如何进行CLI模式的调试?在使用PHPStorm进行开发时,有时我们需要在命令行界面(CLI)模式下调试PHP�...

静态绑定(static::)在PHP中实现晚期静态绑定(LSB),允许在静态上下文中引用调用类而非定义类。1)解析过程在运行时进行,2)在继承关系中向上查找调用类,3)可能带来性能开销。
