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

示例:状态映射表
说明:
在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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值