确保方法逻辑在没有布尔标志的情况下执行一次的更好方法

时间:2015-11-27 08:48:23

标签: c# design-patterns

这是一种使用flag执行Dosomething逻辑的方法。 (C#代码和更新总是每帧调用一次。)
而且它并不是那么复杂,简单,非常简单且使用得很好。

class Monster {
    bool isCalled = false;
    float energy = 0.0f;

    void Update()
    {
        energy += Random.Range(0f, 1f);
        if((isCalled == false) && (energy>100.0f))
        {
            isCalled = true;
            DoSomething();
        }
    }

    void DoSomething(){}
}

但是,我认为布尔标志的管理是一项令人厌烦的任务。
所以我想找到更好的选择。

有没有更好或更优雅的方法来做这个(执行Dosomething一次)没有布尔标志?
例如,另一种设计模式的方式等。

5 个答案:

答案 0 :(得分:2)

我宁愿所有这些标志合并到一个enum中,就像那样:

class Monster {
  [Flags]
  private enum Status {
    Updated,
    Called,
    Killed,  
    ... 
  }

  private Status status;

  void Update() {
    if ((status & Status.Updated) == Status.Updated)
      return;

    try {
      ....
    }
    finally {
      status |= Status.Updated;
    } 
  }
}

答案 1 :(得分:1)

使用专用的名为布尔标志是明确且通用的模式。

通常您不需要专用标志,例如旧单例模式不使用bool,而是测试特殊值

if(instance == null)
{
    .. // do something
}

如您所见,逻辑非常清晰。人们经常使用其他特殊值来避免引入标志:string.IsNullOrEmptydouble.IsNaN,负值等。

重要的是要有明确的意图,不要用太多小细节掩盖逻辑。如果有太多事情需要注意 - 而是引入专用旗帜。

在您的情况下,您可能希望更明显地开始使用state-machine,因为我假设Monster可以在许多不同的状态中影响各种方法的作用:

class Monster
{
    enum States { NotInitialized, Dead, Normal, EnergyMax, ... }
    States _state;
    float _energy;

    void Update()
    {
        _energy += Random.Range(0f, 1f);
        switch(_state)
        {
            case States.Normal:
                if(_energy > EnergyMax)
                {
                    DoSomething(); // called once when energy become max
                    _state = States.EnergyMax;
                }
                break;
            ...
        }
    }
    ...
}

答案 2 :(得分:1)

嗯,一旦执行完毕,你总是可以用NOP动作替换DoSomething

class Monster {
    float energy = 0.0f;
    Action onUpdate;

    public Monster()
    {
        onUpdate = DoSomething;
    }

    void Update()
    {
        onUpdate();
    }

    void DoSomething()
    {
        energy += Random.Range(0f, 1f);
        if(energy > 100.0f)
        {
            // whatever you need to do
        }
        onUpdate = () => {};
    }
}

但是,我相信大多数开发人员都习惯使用布尔标志来跟踪这一点,如果你走这条路线,你可能会得到更少的眉毛。

答案 3 :(得分:0)

你可以这样做:

class Monster
{
    private Action _doSomething;

    public Monster()
    {
        _doSomething = DoSomething;
    }

    float energy = 0.0f;

    void Update()
    {
        energy += Random.Range(0f, 1f);
        if (energy > 100.0f)
            if (_doSomething != null)
                _doSomething();
    }

    void DoSomething() 
    {
        // logic...
        _doSomething = null;
    }
}

但我仍然认为旗帜是一种更好的做法。必须切换一些东西。国旗/参考..

答案 4 :(得分:0)

您可以使用这样的状态模式:

class Monster
    {
        float energy = 0.0f;
        DoSomethingState state;

        public Monster()
        {
            this.state = new DoSomethingStateNotCalled(this);
        }

        public void Update()
        {
            energy += Random.Range(0f, 1f);
            this.state.Update();
        }

        public void DoSomething() {
            System.Diagnostics.Debug.Write("done something");
        }

        public float GetEnergy() {
            return this.energy;
        }

        public void SetState(DoSomethingState state) {
            this.state = state;
        }
    }

abstract class DoSomethingState {

        protected Monster Monster;

        public DoSomethingState(Monster monster) {
            this.Monster = monster;
        }

        public abstract void Update();
    }

class DoSomethingStateCalled : DoSomethingState
    {
        public DoSomethingStateCalled(Monster monster)
            : base(monster)
        {
        }

        public override void Update()
        {
        }
    }

 class DoSomethingStateNotCalled : DoSomethingState
    {
        public DoSomethingStateNotCalled(Monster monster)
            : base(monster)
        {
        }

        public override void Update()
        {
            if (this.Monster.GetEnergy() > 100.0f)
            {
                this.Monster.DoSomething();
                this.Monster.SetState(new DoSomethingStateCalled(this.Monster));
            }
        }
    }