《GOF设计模式》—状态(STATE)—Delphi源码示例:状态映射表

来源:互联网 发布:娜拉走后怎样 知乎 编辑:程序博客网 时间:2024/05/17 20:36

示例:状态映射表
说明:
在C++ Programming Style中,Cargil描述了另一种将结构加载在状态驱动的代码上的方法:他使用表(如哈希表)将输入映射到状态转换。对每一个状态,一张表将每一个可能的输入映射到一个后继状态.

代码:

clip_image002 
unit uState7;

interface

uses
    SysUtils, Classes, Dialogs, Contnrs;

type
    TContext = class;
    TState = class;
    TStates = class;

    THandleEvent = procedure(AContext: TContext) of object;

    TStateKind = (skOpen, skClose);
    TEventKind = (ekOpen, ekClose);

    RMapInfo = record
        Kind: TEventKind;
        State: TState;
    end;
    PMapInfo = ^RMapInfo;

    TMapList = class(TList)
    private
        function GetItems(Index: Integer): PMapInfo;
    public
        function Add(AData: RMapInfo): Integer;
        function Find(AKind: TEventKind): PMapInfo;
        //---
        property Items[Index: Integer]: PMapInfo read GetItems;
    end;

    TState = class
    private
        FList: TMapList;
        procedure ChangeState(AKind: TEventKind; AContext: TContext);
    protected
        function GetKind: TStateKind; virtual; abstract;
    public
        constructor Create;
        destructor Destroy; override;
        //---
        procedure Init; virtual; abstract;
        procedure Open(AContext: TContext); virtual;
        procedure Close(AContext: TContext); virtual;
        //---
        property Kind: TStateKind read GetKind;
    end;
    TState_Open = class(TState)
    protected
        function GetKind: TStateKind; override;
    public
        procedure Init; override;
        procedure Close(AContext: TContext); override;
    end;
    TState_Close = class(TState)
    protected
        function GetKind: TStateKind; override;
    public
        procedure Init; override;
        procedure Open(AContext: TContext); override;
    end;
    TStates = class
    private
        FList: TObjectList;
        function Find(AKind: TStateKind): TState;
    public
        constructor Create;
        destructor Destroy; override;
        //---
        class function Instance: TStates;
        //---
        function GetState_Open: TState;
        function GetState_Close: TState;
    end;

    TContext = class
    private
        FState: TState;
        procedure ChangeState(AState: TState);
    public
        constructor Create;
        //---
        procedure Open;
        procedure Close;
    end;

procedure Test;

implementation

var
    FStates: TStates;

procedure Test;
var
    AContext: TContext;
begin
    AContext := TContext.Create;
    try
        with AContext do
        begin
            Open;
            Close;
            //---
            Close;
        end;
    finally
        AContext.Free;
    end;
end;

procedure TState.Close(AContext: TContext);
begin
end;

procedure TState.ChangeState(AKind: TEventKind; AContext: TContext);
var
    pData: PMapInfo;
begin
    pData := FList.Find(AKind);
    if pData <> nil then
    begin
        if Assigned(pData.State) then
            AContext.ChangeState(pData.State);
    end;
end;

procedure TState.Open(AContext: TContext);
begin
end;

constructor TStates.Create;
begin
    if FStates = nil then
    begin
        FStates := Self;
        FList := TObjectList.Create;
    end
    else
        raise Exception.Create('Error');
end;

destructor TStates.Destroy;
begin
    FStates := nil;
    FList.Free;
    //---
    inherited;
end;

function TStates.Find(AKind: TStateKind): TState;
var
    i: Integer;
begin
    for i := 0 to FList.Count - 1 do
    begin
        if TState(FList[i]).Kind = AKind then
        begin
            Result := TState(FList[i]);
            Exit;
        end;
    end;
    //---
    Result := nil;
end;

constructor TContext.Create;
begin
    ChangeState(TStates.Instance.GetState_Close);
end;

procedure TContext.Open;
begin
    FState.Open(self);
end;

procedure TContext.Close;
begin
    FState.Close(self);
end;

procedure TContext.ChangeState(AState: TState);
begin
    FState := AState;
end;

procedure TState_Open.Close(AContext: TContext);
begin
    ShowMessage('Close');
    Self.ChangeState(ekClose, AContext);
end;

function TState_Open.GetKind: TStateKind;
begin
    Result := skOpen;
end;

procedure TState_Open.Init;
var
    AData: RMapInfo;
begin
    with AData do
    begin
        Kind := ekOpen;
        State := self;
    end;
    FList.Add(AData);
    //---
    with AData do
    begin
        Kind := ekClose;
        State := TStates.Instance.GetState_Close;
    end;
    FList.Add(AData);
end;

function TState_Close.GetKind: TStateKind;
begin
    Result := skClose;
end;

procedure TState_Close.Init;
var
    AData: RMapInfo;
begin
    with AData do
    begin
        Kind := ekOpen;
        State := TStates.Instance.GetState_Open;
    end;
    FList.Add(AData);
    //---
    with AData do
    begin
        Kind := ekClose;
        State := Self;
    end;
    FList.Add(AData);
end;

procedure TState_Close.Open(AContext: TContext);
begin
    ShowMessage('Open');
    Self.ChangeState(ekOpen, AContext);
end;

function TStates.GetState_Close: TState;
begin
    Result := self.Find(skClose);
    if not Assigned(Result) then
    begin
        Result := TState_Close.Create;
        FList.Add(Result);
        //---
        Result.Init;
    end;
end;

function TStates.GetState_Open: TState;
begin
    Result := self.Find(skOpen);
    if not Assigned(Result) then
    begin
        Result := TState_Open.Create;
        FList.Add(Result);
        //---
        Result.Init;
    end;
end;

class function TStates.Instance: TStates;
begin
    if FStates = nil then
        FStates := TStates.Create;
    //---
    Result := FStates;
end;

function TMapList.Add(AData: RMapInfo): Integer;
var
    pData: PMapInfo;
begin
    New(pData);
    pData^ := AData;
    Result := inherited Add(pData);
end;

function TMapList.Find(AKind: TEventKind): PMapInfo;
var
    i: Integer;
begin
    for i := 0 to self.Count - 1 do
    begin
        if Self.Items[i].Kind = AKind then
        begin
            Result := Self.Items[i];
            Exit;
        end;
    end;
    //---
    Result := nil;
end;

function TMapList.GetItems(Index: Integer): PMapInfo;
begin
    Result := inherited Items[Index];
end;

constructor TState.Create;
begin
    FList := TMapList.Create;
end;

destructor TState.Destroy;
begin
    FList.Free;
    //---
    inherited;
end;

initialization
    FStates := nil;

finalization
    if FStates <> nil then
        FStates.Free;

end.

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 手指被挤压紫了怎么办 眼睛撞了有淤血怎么办 下眼底有小白点怎么办 狗的白眼球充血怎么办 眼球有出血点是怎么办 吃阿胶上火了该怎么办 胎儿胼胝体发育不良怎么办 鸡眼看到硬芯了怎么办 小脚趾起茧子疼怎么办 脚起老茧很痛怎么办 化疗后骨髓抑制严重怎么办 胃炎引起的胃胀怎么办 胃病胀肚子很鼓怎么办 小孩淋巴结发炎肚子疼痛怎么办 顺产后子宫脱垂怎么办 顺产完子宫脱垂怎么办 额头长了个鱼鳞怎么办 脸上长了很多痣怎么办 做过狐臭的疤痕怎么办 痤疮留下的红印怎么办 脸上疤掉了黑印怎么办 脸上有黑色的疤怎么办 一只眼睛外斜视怎么办 残币银行不给换怎么办 手上有多套房的怎么办 长了两层脚指甲怎么办 指甲长了两层怎么办 脚趾甲长了两层怎么办 产妇气血虚没奶怎么办 哺乳期气血不足奶水少怎么办 刚怀孕喝了啤酒怎么办 受风怎么办最快最有效 孕妇后背受风了怎么办 肩膀和后背受风怎么办 手指关节杵肿了怎么办 骨关节退行性变怎么办 疼风脚趾肿了怎么办 痛风脚右侧肿了怎么办 痛风引起的脚肿怎么办 老人腰闪了该怎么办 腰闪了站不起来怎么办