开发者

Can I set a state within a function?

I have this code:

procedure EstablishCommunication;
var
    State         : TStates;
    Attempts      : Byte;      
    procedure IncAttempts;
    begin
        Inc(Attempts);
    end;
begin
    State    := stReadDeviceID;
    Attempts := 0;

    while True do
    begin
        if Attempts >= MAX_ATTEMPTS then
        begin
            State := stError;
        end;
        case State of
            stReadDeviceID:
            begin
                // some code
                IncAttempts;
            end;
            stError:
            begin
                // Error code
            end;
        ...
        ...
        ...

I'd like to put the code that set state to stError within of the procedure IncAttempts, resulting:

procedure EstablishCommunication;
var
    State         : TStates;
   开发者_开发百科 Attempts      : Byte;      
    procedure IncAttempts;
    begin
        Inc(Attempts);

        if Attempts >= MAX_ATTEMPTS then
        begin
            State := stError;
        end;
    end;
begin
    State    := stReadDeviceID;
    Attempts := 0;

    while True do
    begin            
        case State of
            stReadDeviceID:
            begin
                // some code
                IncAttempts;
            end;
            stError:
            begin
                // Error code
            end;
        ...
        ...
        ...

So, can I move the code to IncAttempts?

Is this a code smell?

If yes, Can you advice me a better way?


I would see this as perfect valid code. I ask myself the following questions when declaring a method inside another. Most of the time I don't do it, but sometimes it's results in better code.

  • Will the internal function ever need to change as in a descendant class?
  • Can I override External method without calling the internal method and be OK?
  • Does the internal function have practical application outside of external method?
  • Is the internal function complex enough that it should be unit tested outside the scope of there external method?

If any of the above apply don't use an Internal Method.

However if if you don't have any of the above, and it can remove repeated code and/or simplify the design then you can consider using a internal function.


No real problem with that, should work just fine. You are already modifying another local variable Attempts so there is no reason why modifying State should smell more. I do think you should be careful of using inline functions to much. The code often ends up hard to read/understand.


I would say that the new code have some whiff...

It all depends on how many states you manage in current code, and if the number of states could change in the future. Beware of how and when you set the state, and beware of how and when you check the state.

In the two code snippets you show, there is a minor difference:

In the first, original code, the current state is preserved through the iteration, and the new error-state is set in the beginning of the iteration, and it is always checked.

In the second, refactored code, the state is changed in the middle of the iteration, and it is only altered if the state is stReadDeviceID.

Now, if the last line in this while True do-iteration is if State = stError then Break;, then your first code will run the iteration one more time, changing the state to stError in the beginning if the iteration. Your second code will exit at the end of the current iteration, and the code in the stError-section of the case-statement will never be executed...

If you want to go all the way, and study the GoF's State Design Pattern, then take a look at these pages:

  • http://en.wikipedia.org/wiki/State_pattern (no Delphi code...)
  • http://sourcemaking.com/design_patterns/state (with Delphi code!)
  • http://www.dofactory.com/Patterns/PatternState.aspx (no Delphi code...)
  • http://conferences.embarcadero.com/article/32129#_Toc12157322 (with Delphi code!)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜