如何处理时间耦合?
我因此而苦苦挣扎:
我的类有一些具有时间耦合的方法。 也就是说,必须首先调用MethodA ,以“初始化” MethodB需要正常工作的数据。
我通常通过将违规依赖项 作为参数传递给“MethodB”来显式化时间耦合,就像在这个片段中一样:
private class SomeClass { private string field; private int count; public SomeClass() { MethodA(); MethodB(field); } private void MethodA() { field = "Something"; } private void MethodB(string str) { count = str.Length; } }
虽然它使事情明确,但我觉得我做错了。 我最终得到的方法根本就不使用字段(静态方法!),所以这个类开始变得不那么紧密了。
这是最好的方法吗? (通过传递参数失去凝聚力)
编辑:关于一些建议使用字段作为构造函数中的参数或使用构建器模式来避免无效状态的答案: 我不能这样做,因为在我的情况下我正在构建一个Parser 。 MethodA读取输入并根据它设置状态(从文件中读取字符),然后调用MethodB。 必须以正确的顺序调用它们。 这是真正的问题:应该在另一个之前调用一个。
我想你需要进行一种复杂的初始化,其中必须在实际初始化对象之前指定一些参数,并且你希望更好地控制类用户正在做什么以避免无效状态。 解决这种情况的一个很好的知识模式是所谓的“构建器模式”,在OOP中经常使用。 我不想指出一篇特定的文章,你会发现自己有很多例子,只需使用关键字“builder pattern”。 为了完成,总体思路是制作一个流畅的方法序列,指定内部字段的值,并委托最终方法“Build”来创建工作对象实例,并validation传递的参数。
Fluent API通过不在“构建器”对象中公开依赖方法直到适当的方式解决公共接口上的这种问题:
SomeClass someInstance = SomeClassBuilder(x=> { x.MethodA().MethodB("somevalue"); });
这需要更多的plumbling,因为您需要构建器对象,以及构建器组件,例如从MethodA返回的公开MethodB的对象。 这样,调用MethodB的唯一方法是首先调用MethodA。
我不鼓励你采取这种方法。 对于许多场景来说,它可能有点过分,但是如果您遇到适合的场景,请务必注意此选项。
如果您遵循贫血领域模型,您可以打破您的class级并使其成为2个较小的class级。 你会意识到设计不好,因为你当前的类违反了SRP ,简而言之它有2个责任:1用于处理输入过程,1用于处理输入结果。
将其分解以便ClassA
处理输入并返回结果,然后ClassB
将ClassA
的结果作为参数,然后处理它。 例如:
public class ClassA { public string MethodA() { // read the input return "Something"; // or return the input } } public class ClassB { private int count; public void MethodB(string str) { count = str.Length; } }
如果您发现同时使用这两个类很麻烦,请使用另一个聚合服务 。 例如:
public class ClassC { public ClassA ClassA = new ClassA(); public ClassB ClassB = new ClassB(); public void Execute(){ string result = ClassA.MethodA(); ClassB.MethodB(result); } }
您只需从MethodB
删除参数并使用该field
,这样就不会失去内聚力
private class SomeClass { private string field; private int count; public SomeClass() { MethodA(); MethodB(); } private void MethodA() { field = "Something"; } private void MethodB() { count = field.Length; } }
笔记:
1)你描述问题的方式就像模板方法设计模式,你应该看看这里 。
2) 静态方法不属于该类
我不知道你的确切目标是什么,但为什么不把参数放在类的构造函数中:
private class SomeClass { private string _field; private int _count; public SomeClass(string field) { _field = field; _count = field.Length; } }
现在你将拥有这样的东西
SomeClass sc = new SomeClass("Something");//or whatever you want for field.