【发布时间】:2009-06-12 15:52:27
【问题描述】:
是的,我知道,还有一个关于可变对象的问题。请参阅this 了解一般背景,this 了解与我的问题最接近的类似物。 (尽管它有一些不适用于此处的 C++ 特定泛音)
让我们假设下面的伪代码代表了最好的界面设计。也就是说,它是业务语义(就目前而言)到 OO 类型的最清晰表达。自然地,UglyData 和我们负责处理的事情会发生增量变化。
public class FriendlyWrapper
{
public FriendlyWrapper(UglyDatum u)
{
Foo = u.asdf[0].f[0].o.o;
Bar = u.barbarbar.ToDooDad();
Baz = u.uglyNameForBaz;
// etc
}
public Widget Foo { get; private set; }
public DooDad Bar { get; private set; }
public DooDad Baz { get; private set; }
// etc
public WhizBang Expensive1 { get; private set; }
public WhizBang Expensive2 { get; private set; }
public void Calculate()
{
Expensive1 = Calc(Foo, Bar);
Expensive2 = Calc(Foo, Baz);
}
private WhizBang Calc(Widget a, DooDad b) { /* stuff */ }
public override void ToString()
{
return string.Format("{0}{1}{2}{3}{4}", Foo, Bar, Baz, Expensive1 ?? "", Expensive2 ?? "");
}
}
// Consumer 1 is happy to work with just the basic wrapped properties
public string Summarize()
{
var myStuff = from u in data
where IsWhatIWant(u)
select new FriendlyWrapper(u);
var sb = new StringBuilder();
foreach (var s in myStuff)
{
sb.AppendLine(s.ToString());
}
return sb.ToString();
}
// Consumer 2's job is to take the performance hit up front. His callers might do things
// with expensive properties (eg bind one to a UI element) that should not take noticeable time.
public IEnumerable<FriendlyWrapper> FetchAllData(Predicate<UglyDatum> pred)
{
var myStuff = from u in data
where pred(u)
select new FriendlyWrapper(u);
foreach (var s in myStuff)
{
s.Calculate(); // as written, this doesn't do what you intend...
}
return myStuff;
}
这里最好的路线是什么?我可以看到的选项:
- 具有显式 Calculate() 方法的可变对象,如上所述
- 在 getter 中完成昂贵计算的可变对象(并且可能已缓存)
- 拆分成两个对象,其中一个继承(或者可能是组合?)另一个对象
- 某种静态 + 锁定机制,如上面链接的 C++ 问题中
我自己倾向于#2。但每条路线都有潜在的陷阱。
如果您选择 #1 或 #2,那么您将如何以清晰、正确的方式实现 Consumer2 的可变循环?
如果您选择#1 或#3,您将如何处理将来只想计算某些属性而不计算其他属性的情况?愿意创建 N 个辅助方法/派生类吗?
如果你选择#4,我认为你疯了,但请随意解释
【问题讨论】:
-
如果一个属性很贵,那么它的运行就违反了 MS 关于属性与方法 (msdn.microsoft.com/en-us/library/bzwdh01d(VS.71).aspx) 的指导方针,但即使作为一种方法,你当然仍然会遇到同样的问题