RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 939349
Accepted
Kir_Antipov
Kir_Antipov
Asked:2020-02-01 12:26:04 +0000 UTC2020-02-01 12:26:04 +0000 UTC 2020-02-01 12:26:04 +0000 UTC

检查对象状态的最佳方法

  • 772

我们先想象一个类似的类:

public class Vasya
{
    public void FreezeWater() => ...

    public void WalkOnWater() => ...
}

也就是说,我们的Vasya可以冻结水,也可以尝试在上面行走。在冰上行走并没有什么困难,所以一个类似的假设代码:

var vasya = new Vasya();
vasya.FreezeWater();
vasya.WalkOnWater(); 

将毫无问题地运行,但以下块:

var vasya = new Vasya();
vasya.WalkOnWater(); 

会扔给我们一些VasyaDrownedException,因为他Vasya没有把水带到适合走路的聚集状态。

既然我们不想这么突然和 Vasya 说再见,我们可以像这样修补这个类:

public class Vasya
{
    public bool IsWaterFrozen{ get; private set; } = false;

    public void FreezeWater() 
    {
        IsWaterFrozen = true;
        ...
    }

    public void WalkOnWater() 
    {
        if (!IsWaterFrozen)
            throw new InvalidActionException("Water is not frozen!");
        ...
    }
}

在这种情况下,试图淹死 Vasya 的臭名昭著的尝试会抛出我们已经预料到的异常,所以我们可以到此结束,但问题是:我们的 Vasya 是一个非常鲁莽的物体,所以他在水中跑了几千次。第二。因此,我们每秒有一千个额外的检查和一千个假设的异常(我们知道,抛出异常并不是一个便宜的操作)

这种经常被调用的方法(所以它的性能很关键)的情况对我来说似乎是不可接受的。

理论上,您可以像这样解决这种情况:

public class Vasya
{
    public bool IsWaterFrozen{ get; private set; } = false;
    private Action _walkOnWater ;

    public Vasya() => _walkOnWater = ThrowWaterIsNotFrozen;

    public void FreezeWater() 
    {
        _walkOnWater = SuccessfullyWalkOnWater;
        IsWaterFrozen = true;
        ...
    }

    public void WalkOnWater() => _walkOnWater();

    private void ThrowWaterIsNotFrozen() => throw new InvalidActionException("Water is not frozen!");

    private void SuccessfullyWalkOnWater() => ...
}

也就是说,我们通过只更改一次调用上下文来保存方法免于不断检查

但是在这里我还有一个问题:
额外的委托调用不会比检查布尔标志更昂贵吗?


总的来说,划一条线,问题是:如何组织一个方法调用更正确,它的逻辑取决于另一个方法的调用,而且它的性能对我们来说非常非常关键

c#
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. Cost
    2020-02-01T16:26:45Z2020-02-01T16:26:45Z

    我也不知道我是否正确理解了这个问题,我会按照我的理解回答。

    在我看来,有三种选择:

    1. 这两种方法不能单独调用,而且是刚性捆绑运行的(Vasya 总是先冻结水再踩水)
    2. 没有第一种就不能调用第二种方法(瓦夏可以冻结水,因为他无所事事,但如果他要在上面行走,他不会忘记它)
    3. 两种方法都可以相互分开调用(Vasya 随时冻结水,无论如何走路)

    在第一种情况下,我们将它们封装在第三种方法中,该方法始终以正确的顺序调用它们。在这种情况下,不需要检查,也不会引发异常。

    public class Vasya
    {
            private void FreezeWater() { }
    
    
            private void WalkOnWater() { }
    
    
            public void MakeMove()
            {
                FreezeWater();
                WalkOnWater();
            }
    }
    

    因此,如果我们想让 Vasya 走上去,那么

    public class Vasya
    {
            private void FreezeWater() { }
    
    
            private void WalkOnWater() { }
    
    
            public void MakeMove()
            {
                FreezeWater();
                WalkOnWater();
            }
    
            public void Walk()
            {
                FreezeWater();
                for(int step = 0; step < 1000; step++)
                { 
                    WalkOnWater();
                }
            }
    }
    

    在第二种情况下,我们将第一种方法保持打开状态,其他一切都与第一种方法相同。

     public class Vasya
     {
            public void FreezeWater() { }
    
    
            private void WalkOnWater() { }
    
    
            public void MakeMove()
            {
                FreezeWater();
                WalkOnWater();
            }
      }
    

    在第三种情况下,我们期望调用第二种方法,而不是先调用第一个方法。让瓦夏想走就走,水还没结冰就骂他,实在是太奇怪了。因此,在这种情况下产生的异常在我看来是不正确的。我们希望它能够在水不结冰的情况下行走,因此必须将这种情况视为正常,而不是例外。@Andrew 的回答显示了一种可能的解决方案。Vasya可以随时去散步,他决定是否去。

    您可以更进一步,通过实施水的状态模式或 Vasya 的策略来摆脱每次 Vasya 采取新步骤时检查水是否结冰的问题。例如,Vasya 的策略

    public class Vasya
    {
        publicvoid FreezeWater() 
        {
            ...
            movingStrategy = new FrozenWaterMovingStrategy();
        }
    
        public MovingStrategy movingStrategy = new LiquidWaterMovingStrategy();
    
        public void WalkOnWater()
        {
            movingStrategy.Move();
        }
    }
    
    public abstract class MovingStrategy
    {
        public abstract void Move();
    }
    
    public class FrozenWaterMovingStrategy : MovingStrategy
    {
    
        public override void Move()
        {
            // то что было в теле метода WalkOnWater()
        }
    }
    
    public class LiquidWaterMovingStrategy : MovingStrategy
    {
        public override void Move()
        {
            // обработка ожидаемого поведения Васи в жидкой воде
        }
    }
    

    在 Vasya 的所有赌博中,将调用所需的方法而无需任何检查

    • 2
  2. Best Answer
    Bulson
    2020-02-02T02:07:52Z2020-02-02T02:07:52Z

    事实上,你可以申请你的案子State pattern。

    创建 Vasya 状态类型的接口

    public interface IVasyaState
    {
        IVasyaState FreezeWater();
        IVasyaState WalkOnWater(Action addSteps);
    }
    

    现在我们在“水未冻结”和“水已冻结”两个类中实现这个接口。

    public class NotFreezedWater : IVasyaState
    {
        //меняем состояние на заморож.воду
        public IVasyaState FreezeWater() => new FreezedWater();
    
        //шаги не прибавляем, просто возвращаем текущее сост.
        public IVasyaState WalkOnWater(Action addSteps) => this;
    }
    
    public class FreezedWater : IVasyaState
    {
        //ничего не делаем
        public IVasyaState FreezeWater() => this;
    
        public IVasyaState WalkOnWater(Action addSteps)
        {
            addSteps();
            return this;
        }
    }
    

    好吧,现在实际上是瓦夏本人

    public class Vasya
    {
        //ctor
        public Vasya()
        {
            State = new NotFreezedWater();
        }
    
        //состояние Васи
        public IVasyaState State { get; set; }
    
        //количество проделанных шагов
        public int CountSteps { get; private set; }
    
        public void FreezeWater()
        {
            State = State.FreezeWater();
        }
    
        public void WalkOnWater(int steps)
        {
            State = State.WalkOnWater(() => { this.CountSteps += steps; });
        }
    }
    

    这种模式无疑的优点是不需要产生一堆if()来检查对象属性值的各种条件,也没有人取消对责任唯一性原则的遵守。是的,不需要抛出任何异常等等。

    测试用例本身在这里。

    • 2
  3. Andrew_STOP_RU_AGRESSION_IN_UA
    2020-02-01T14:23:34Z2020-02-01T14:23:34Z

    嗯,据我理解的问题...

    但我认为这是最快的方法。

    public class Vasya
    {
        private _isWaterFrozen = true;
    
        public void FreezeWater() 
        {
            _isWaterFrozen = true;
            ...
        }
    
        public bool WalkOnWater() 
        {
            if (!_isWaterFrozen)
                return false;
            ...
            ...
            ... 
            return true;
        }
    }
    

    在任何情况下,通过方法返回标志都比异常快,使用委托,或者,上帝禁止,从外部某处 tryCatch

    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5