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

本文关键字:方法 执行 更好 一次 情况下 标志 布尔 确保 | 更新日期: 2023-09-27 18:24:54

这是一种使用flag执行剂量计量逻辑的方法。(C#代码和Update总是每帧调用一次。)
它并不是那么复杂,简单,非常简单和使用良好的方式。

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(){}
}

但是,我认为布尔标志的管理是一项令人厌倦的任务
所以我正在努力寻找更好的替代方案

有没有更好或优雅的方法可以在没有布尔标志的情况下做到这一点(执行一次剂量测量)
例如,另一种设计模式的方式等。

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

我宁愿将所有这样的标志组合成一个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;
    } 
  }
}

使用命名良好的专用布尔标志是一种清晰而常见的模式。

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

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

正如你所看到的,逻辑已经足够清晰了。人们经常使用其他特殊值来避免引入标志的必要性:string.IsNullOrEmptydouble.IsNaN、负值等。

重要的是要有明确的意图,不要用太多小细节模糊逻辑。如果有太多的事情需要注意,那就引入一面专用的旗帜吧。

在您的情况下,您可能希望更明显地开始使用状态机,因为我假设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;
            ...
        }
    }
    ...
}

好吧,一旦DoSomething被执行,您总是可以用NOP操作替换它:

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 = () => {};
    }
}

然而,我相信大多数开发人员都习惯于使用布尔标志来跟踪这一点,如果你走这条路,你可能不会那么惊讶。

您可以这样做:

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;
    }
}

但我仍然认为挂国旗是更好的做法有些东西必须切换。标志/参考。。

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

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));
            }
        }
    }