初识设计模式——状态模式

个人理解

定义:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变其类。

理解:这个模式主要解决的问题是消除庞大的条件分之语句,条件分支语句过大的使用,可能出现维护困难,操控的对象方法较为复杂等问题。例如订单的状态、游戏的等级等等都可以使用状态模式。

主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为(状态模式的行为上说的,如果从状态模式的表现上来看,还是用于消除庞大的条件分之语句)。

组成部分:一个状态控制抽象类(State)、若干个状态控制类(StateA、StateB...)、一个主题对象(Context)。

案例分析

设计场景

某卡牌游戏平台,每个紫色英雄可以进阶5次:青铜(初始)、白银、黄金、铂金、钻石、大师(实在找不到进阶的名称了,将就着看吧,以下统称“段位”),每个阶段分别存在最大等级上限(30、40、50、60、70、80)。每次升级后,等级重置。这种情况下,数据库存储可以分为两种方式,第一种:设置两个字段,一个字段为用户等级,另一个字段为用户的段位等级;另一种:设置一个字段,值为上一段位最大等级数值加当前阶段等级,例如:字段存储值(以下统称“存储值”)为88,则该英雄为黄金18级。下面的例子将以第二种为例。

面对过程想法

将每个段位的等级上限设置为一个数组,便利数组,判断英雄的存储值是否小于每个元素,如果大于则该英雄的段位就是当前段位,等级为英雄的存储值减去上一个段位的最大等级。

问题出现于,当游戏平台大多数玩家都达到满级了,玩家流失严重,需要升级游戏。现在增加橙色英雄,可以进阶6次:青铜(初始)、白银、黄金、铂金、钻石、大师、王者,每个阶段分别存在最大等级上限(30、40、50、60、70、80)。这可怎么改,在外面在增加一个判断,如果是紫色英雄...,如果是橙色英雄将上面那个复制下来,代码冗余不说,修改还贼费劲,吃力不讨好。

面对对象想法

增加一个英雄抽象类,生成两个实体英雄类:橙色英雄、紫色英雄,两个类的获取等级的方法不一样就可以了。目前存在的问题还是存在。根据单一职责定义:“就一个类而言,应该仅有一个引起它变化的原因。”在这个类中尽量少的增加其他功能,我们是不是可以将英雄的状态控制认为成一个功能。另外,由于存在庞大的条件分之语句,我们在修改的时候还是不方便。

使用状态模式

建立一个状态控制抽象类、六个具体的状态控制类、一个英雄抽象类、两个具体英雄类,具体的状态控制类继承状态控制抽象类,实现与英雄类相关的状态方法,两个具体的英雄类继承英雄抽象类,然后每个英雄都操作具体的功能。如果需要在增加一种英雄,只需要增加一个英雄类就可以了;如果需要在增加一种状态(例如“青铜”与“白银”之间增加“铝合金”段位),直接增加一个状态类,然后在修改上下两个段位的方法就好了,再也不用担心维护麻烦了。

场景代码

英雄抽象类:

<?php

//英雄抽象类
abstract class Hero{
	protected $hp;	//血量
	protected $mp;	//魔法值
	protected $atk;	//攻击力
	protected $type;	//当前英雄的类型
	//获取当前英雄的等级
	abstract public function getState($level);
}

橙色英雄:

<?php

//橙色英雄
class OrangeHero extends Hero
{
	protected $hp;
	protected $mp;
	protected $atk;
	protected $type = 2;
	public function getState($level)
	{
		$state = new BronzeState();
		return $state->getState($level, $this->type);
	}
}

紫色英雄:

<?php

//紫色英雄
class PurpleHero extends Hero
{
	protected $hp;
	protected $mp;
	protected $atk;
	protected $type = 1;
	public function getState($level)
	{
		//获取当前英雄的等级值
		$state = new BronzeState();
		return $state->getState($level, $this->type);
	}
}

状态抽象类:

<?php

//状态抽象类
abstract class State
{
	protected $maxLevel;		//当前状态等级上限
	protected $name;			//当前状态名称
	abstract public function getState($level, $type);
}

青铜状态类:

<?php

//青铜
class BronzeState extends State
{
	protected $maxLevel = 30;
	protected $name = '青铜';
	public function getState($level, $type)
	{
		$nextStateLevel = $level-$this->maxLevel;
		if ($level>$this->maxLevel) {
			$state = new SilverState();
			return $state->getState($nextStateLevel, $type);
		} else {
			return [
				'state'	=> $this->name,
				'level'	=> $level
			];
		}
	}
}

白银状态类:

<?php

//白银
class SilverState extends State
{
	protected $maxLevel = 40;
	protected $name = '白银';
	public function getState($level, $type)
	{
		$nextStateLevel = $level-$this->maxLevel;
		if ($level>$this->maxLevel) {
			$state = new GoldState();
			return $state->getState($nextStateLevel, $type);
		} else {
			return [
				'state'	=> $this->name,
				'level'	=> $level
			];
		}
	}
}

黄金状态类:

<?php

//黄金
class GoldState extends State
{
	protected $maxLevel = 50;
	protected $name = '黄金';
	public function getState($level, $type)
	{
		$nextStateLevel = $level-$this->maxLevel;
		if ($level>$this->maxLevel) {
			$state = new PlatinumState();
			return $state->getState($nextStateLevel, $type);
		} else {
			return [
				'state'	=> $this->name,
				'level'	=> $level
			];
		}
	}
}

铂金状态类:

<?php

//铂金
class PlatinumState extends State
{
	protected $maxLevel = 60;
	protected $name = '铂金';
	public function getState($level, $type)
	{
		$nextStateLevel = $level-$this->maxLevel;
		if ($level>$this->maxLevel) {
			$state = new GoldState();
			return $state->getState($nextStateLevel, $type);
		} else {
			return [
				'state'	=> $this->name,
				'level'	=> $level
			];
		}
	}
}

钻石状态类:

<?php

//钻石
class DiamondState extends State
{
	protected $maxLevel = 70;
	protected $name = '钻石';
	public function getState($level, $type)
	{
		$nextStateLevel = $level-$this->maxLevel;
		if ($level>$this->maxLevel) {
			return [
				'state'	=> $this->name,
				'level'	=> '满级'
			];
		} else {
			return [
				'state'	=> $this->name,
				'level'	=> $level
			];
		}
	}
}

客户端:

<?php

include './State.php';
include './BronzeState.php';
include './DiamondState.php';
include './GoldState.php';
include './PlatinumState.php';
include './SilverState.php';

include './Hero.php';
include './OrangeHero.php';
include './PurpleHero.php';

class Client 
{
	public function main()
	{
		//我的橙色英雄
		$level = 234;
		$orangeHero = new OrangeHero();
		echo '我的橙色英雄<br/>';
		print_r($orangeHero->getState($level));
		echo '<hr/>';
		//我的紫色英雄
		$level = 200;
		$purpleHero = new PurpleHero();
		echo '我的紫色英雄<br/>';
		print_r($purpleHero->getState($level));
		
	}
}
$client = new Client();
$client->main();

UML图

如果需要进行增加一个在青铜和白银之间加入一个段位,则扩展一个状态类,然后修改BronzeState(青铜状态类)即可。如果需要增加其他英雄,则直接扩展一个英雄类即可。

下一篇

初识设计模式——原型模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值