Ja, ich weiß, noch eine Frage über veränderbare Objekte. Siehe this für allgemeinen Hintergrund und this für das nächste Analog zu meiner Frage. (obwohl es einige C++ spezifische Obertöne hat, die hier nicht gelten)C# Design für ein Objekt, wo einige Eigenschaften teuer sind: Entschuldigung, um es veränderbar zu machen?
Nehmen wir an, dass der folgende Pseudocode die beste Schnittstelle Design darstellt. Das ist der klarste Ausdruck der Geschäftssemantik (wie sie heute steht) in den OO-Typ. Natürlich unterliegen die UglyData und die Dinge, die wir damit tun, inkrementellen Veränderungen.
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;
}
Was ist die beste Route hier? Optionen kann ich sehen:
- veränderbares Objekt mit einem expliziten berechnen() -Methode, wie oben
- Mutable Objekt, in die teueren Berechnungen in dem Getter fertig sind (und wahrscheinlich im Cache)
- Split in zwei Objekte, bei denen eine inherits (oder vielleicht komponiert?) von der anderen
- irgendeine Art von statischen Verriegelungsmechanismus +, wie in der C++ Frage oben
I # bin Neigung in Richtung 2 selbst verbunden. Aber jede Route hat potenzielle Fallstricke.
Wenn Sie # 1 oder # 2 wählen, wie würden Sie Consumer2's Loop über Mutables in einer klaren, korrekten Weise implementieren?
Wenn Sie # 1 oder # 3 wählen, wie würden Sie zukünftige Situationen behandeln, in denen Sie nur einige Eigenschaften berechnen möchten, aber keine anderen? Möchten Sie N Hilfsmethoden/abgeleitete Klassen erstellen?
Wenn Sie # wählen 4, ich glaube, du bist verrückt, aber ich fühle mich frei
Wenn eine Eigenschaft teuer ist, dann läuft sie im Gegensatz zu den MS-Richtlinien, die Eigenschaften und Methoden vergleichen (http://msdn.microsoft.com/en-us/library/bzwdh01d (VS.71)).aspx) aber selbst als Methode hast du natürlich immer noch die gleichen Probleme – annakata