确保方法逻辑在没有布尔标志的情况下执行一次的更好方法
本文关键字:方法 执行 更好 一次 情况下 标志 布尔 确保 | 更新日期: 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.IsNullOrEmpty
、double.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));
}
}
}