状态模式
状态模式是一种较为复杂的设计模式,它用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。当系统中某个对象存在多个状态,这个状态之间可以进行转换,而对象在不同状态下行为补相同时可以使用状态模式。
定义
英文定义:“Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.”。
中文定义:允许对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
状态模式重要等级★★★☆☆ 状态模式难度等级★★★★☆
模式结构图
实例
实例说明
某酒店订房系统,可以将酒店房间设计为一个类,酒店房间对象将会存在已预定、已空闲、已入住状态。对于客户而已,这些状态的转换细节无需知道,不同状态的对象有不同的行为。如已经预定或者入住的房间不能再接受其他顾客的预定。
实例类图
代码实现
房间类Room
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Room
{
private int no;
private RoomState state;
public int No
{
get
{
return no;
}
}
public RoomState State
{
get
{
return state;
}
set
{
state = value;
}
}
public Room(int no)
{
this.no = no;
state = new Free(this);
}
public virtual void Reserve()
{
state.Reserve();
}
public virtual void CheckIn()
{
state.CheckIn();
}
public virtual void CheckOut()
{
state.CheckOut();
}
}
抽象状态类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class RoomState
{
protected Room room;
public RoomState(Room room)
{
this.room = room;
}
public virtual void Reserve()
{
Console.WriteLine(room.No + "号房预定。");
room.State = new Reserved(room);
}
public virtual void CheckIn()
{
Console.WriteLine(room.No + "号房入住。");
room.State = new CheckedIn(room);
}
public virtual void CheckOut()
{
Console.WriteLine(room.No + "号房退房。");
room.State = new Free(room);
}
}
入住状态
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class CheckedIn : RoomState
{
public CheckedIn(Room room) : base(room) { }
public override void Reserve()
{
Console.WriteLine("预定失败,"+room.No+"房未空闲");
}
public override void CheckIn()
{
Console.WriteLine(room.No + "房已入住。");
}
}
空闲状态
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Free:RoomState
{
public Free(Room room) : base(room) { }
public override void CheckOut()
{
Console.WriteLine(room.No + "房未被预定或者使用");
}
}
预定状态
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class Reserved : RoomState
{
public Reserved(Room room) : base(room) { }
public override void Reserve()
{
Console.WriteLine(room.No + "房已经被预定");
}
}
测试代码
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
class Program
{
static void Main(string[] args)
{
Room room = new Room(101);
room.Reserve();
room.CheckIn();
room.CheckOut();
room.CheckOut();
Console.ReadKey();
}
}
运行截图
模式扩展
状态共享
在某些情况下,多个环境对象需要共享同一个状态,或者为了节约系统资源,将某些状态给多个环境对象复用。那么就需要将这些状态对象定义为静态的。例如实例中的房间状态对象,其实是可以复用的。
总结
模式优点
1)封装了转换规则。在状态模式中无需使用条件语句来进行判断。
2)枚举可能的状态,在枚举状态之前需要确定状态种类。
3)将所有与某个有关状态的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象地状态即可改变对象的行为。
4)允许状态转换逻辑和状态对象合成一体,而不是一个巨大的条件语句块。
5)可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
模式缺点
1)状态模式的使用会增加系统类和对象的数量。
2)代码实现和模式结构较为复杂。
3)对于新增加的状态类,需要修改那些负责状态转换的源码,违背了“开闭原则”。