何时检查对象的状态,一般面向对象编程,C#示例。

5

我不太确定如何用一句话来表达这个问题,所以我在搜索之前遇到了一些困难。这对我来说经常发生,我想得到关于如何解决这个问题的共识。

假设你有两个类,ExampleClassExampleClassManagerExampleClass有一个Update(Data data)方法,该方法从ExampleClassManager中调用。然而,在Enabled状态下,ExampleClass可以处于两种状态之一,并且它希望处理传递给Updatedata。而在disabled状态下,它根本不使用data

我应该在ExampleClassManager中检查状态,如果是disabled就不传递data,还是无论如何都传递data并在ExampleClass中忽略它?

如果我没有表达清楚,这里有一个代码示例。

public class ExampleClass {
    public bool Enabled {
        get;
        set;
    }

    public void Update(Data data) {
        if(Enabled) {
            //do stuff with data
        }
    }
}

public class ExampleClassManager {
    private List<ExampleClass> exampleClassList=new List<ExampleClass>();

    public void UpdateList() {
        foreach(ExampleClass exampleClass in exampleClassList) {
            exampleClass.Update(data);
        }
    }
}

或者

public class ExampleClass {
    public bool Enabled {
        get;
        set;
    }

    public void Update(Data data) {
        //do stuff with data
    }
}

public class ExampleClassManager {
    private List<ExampleClass> exampleClassList=new List<ExampleClass>();

    public void UpdateList() {
        foreach(ExampleClass exampleClass in exampleClassList) {
            if(exampleClass.Enabled) {
                exampleClass.Update(data);
            }
        }
    }
}

3
我需要翻译以下内容:问题是:A)如果您对已禁用的ExampleClass进行“更新”,然后启用该实例,会发生什么情况?它应该显示在被禁用之前与其绑定的数据,还是应该显示在其被禁用时提供给它的更新数据?B)ExampleClassManager在分发其数据时是否关心ExampleClass是否启用?C)您是否预计有其他ExampleClass的实现/子类,其中它会希望获取数据或具有其他应该在被“更新”时更改的“可更新”概念,即使已禁用?A) 如果您对已禁用的 ExampleClass 进行“更新”,然后启用该实例,那么它应该显示被禁用之前所绑定的数据,而不是更新之后提供的数据。B) ExampleClassManager 分发数据时并不关心 ExampleClass 是否启用。C) 您是否预计会有其他 ExampleClass 的实现/子类,它们希望在被“更新”时更改数据,即使已经被禁用? - Chris Sinclair
另外D)您是否希望调用代码强制更新已禁用的“ExampleClass”实例?在您的第二个示例中,调用代码可以忽略实例被禁用的事实并对其进行更改。从任何调用“Update”的类的所有代码都必须履行此“如果我被禁用,请不要更新我”的合同,但没有义务这样做。 - Chris Sinclair
1
这真的取决于输入数据的处理有多重要。在这种情况下,“ExampleClass”没有选择如何处理禁用状态,而是让它的客户自己作出选择。你可能认为这是不好的设计。它没有告诉你输入将不会发生任何事情。如果“ExampleClass”对您的数据处理很重要,则可能需要检查此禁用状态。但是,您如何响应被禁用的状态呢?抛出异常?忽略?尝试其他路线?记录一些信息? - oɔɯǝɹ
非常感谢您迄今为止的回复。毫无例外,如果ExampleClass被禁用,我不希望调用Update函数,因此我认为遵循第一种模式是有意义的。 - tmakino
1
如果是ExampleClass决定是否达到不同的状态,那么一定选择选项1。我会将Enable的setter设置为私有。 - Julián Urbano
4个回答

3

考虑到它取决于 ExampleClass 的一个属性,我会选择选项 1 并在 ExampleClass.Update 内部进行检查。否则,任何可以访问 ExampleClass 对象的对象都可以调用 Update,而不论其状态如何。通过在 Update 方法内部进行检查,您可以确保只有在对象启用时才会继续执行。这里的问题是谁可以更改对象的状态?

参见迪米特法则

每个单元只应具有有关其他单元的有限知识:仅与当前单元“密切”相关的单元。


谢谢,这引出了一个相关的问题。如果我有许多ExampleClasses和一个ExampleClassManager来管理它们,是将“Enabled”设为私有并让每个ExampleClass负责自己的状态更好呢?还是应该将“Enabled”设置为公共属性,并让管理器设置ExampleClass的状态?在我的简化示例中,“Enabled”是true/false取决于ExampleClass内部对传递给它的“Data”对象的反应。我可能刚刚在最后一句话中回答了自己的问题,但请确认一下。 - tmakino
如果每个ExampleClass都完全负责自己的状态,那么我的管理类只是一个赞美的Dictionary<int, ExampleClass>,其中int是唯一的ID。您会建议使用复杂的“Manager”类和简单的ExampleClasses,还是使用复杂的ExampleClass和简单的Manager?这是否有一个普遍接受的答案,还是取决于每个具体情况? - tmakino
依我看,是的,你已经回答了自己的问题 :-) 如果唯一负责状态更改的是 ExampleClass,那么将 setter 设为 private,getter 设为 public。如果其他类 在您的程序集内 也可以更改它,则还应将 setter 视为 internal - Julián Urbano
关于Manager...除了调用Update之外,它还有什么作用?如果它只是一个ExampleClass的集合,那么我会忘记它。如果它在添加/删除ExampleClass对象时具有一些额外的功能,那么请保留它。这取决于它的功能。 - Julián Urbano
那么你需要有人将ExampleClass对象从一个列表移动到另一个列表...但是你真的需要两个列表吗?我会只保留一个List<ExampleClass>,并删除管理器。再次强调,这取决于谁对这两个列表进行了什么操作。你是否只想在启用/禁用对象上执行除“更新”以外的其他操作?你也可以轻松使用LINQ。 - Julián Urbano
显示剩余2条评论

0
“我的管理类应该做多少管理?”你的第二个选项是“微观管理”方法——即经理应该向ExampleClass指示每一个小细节,包括它应该做什么和如何做。
通常,这更多地是基于结构的编程而不是面向对象的编程。我希望您的经理告诉您的对象“去做这件事”,而不必担心细节。ExampleClass应该在内部封装所有行为,不要强迫经理担心它。
我的投票是选择选项1,但需要注意这些是一般原则,您总是能够找到某些情况需要选项2。
有一个问题需要问——除了让经理检查之外,是否有其他原因使ExampleClass.Enabled.get成为公共的?如果这是唯一的原因,那么它就是内部实现,gettor应该是私有的。如果有很多东西正在查看此字段,则可能意味着您的选项2工作流对于此类更自然。

0

我会选择选项2,classManager应该管理对象,他应该知道是否触发更新。 单个对象的更新方法应该做它所说的事情(更新对象而不是什么都不做)。

@caerolus:我还不能评论...无论如何,给出的示例都没有违反迪米特法则

无论如何,我认为这是一个有点个人选择的问题,也许更适合在Stack Exchange上讨论?


0
假设你有两个对象,公司和员工。你让公司检查员工是否饥饿,还是让员工自己检查?听起来你想让员工自己检查,对吧?但如果公司想为所有员工订餐,那么公司需要检查员工是否饥饿。
所以我的观点是,这取决于设计和上下文,何时检查、谁在检查以及为什么要检查。在你的例子中,我会说这并不重要,因为上下文没有确定。

不错的例子!但我认为应该是这样的:操作是吃饭(在这里是更新)。谁决定是否要吃饭?员工。公司可以检查员工是否饥饿(在这里是启用)吗?可以,但最终,吃还是不吃由员工自己决定。所以你可以让大家知道你是否饥饿,但只有你自己能决定是否要吃饭……因此不再饥饿。 - Julián Urbano

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接