長いソフトウェアアーキテクチャの質問
明確さの編集:、、 ...などのタイプで構成されるオブジェクトグラフを、、...などNodeA
のタイプで構成されるオブジェクトグラフに変換しようとしています
。その逆も同様です。タイプのプロパティは、タイプの同様のプロパティに対応していますが、多くの場合、それは単なる些細な割り当てではありません。NodeB
*My*NodeA
*My*NodeB
NodeX
MyNodeX
このような2つの類似したクラス構造がある場合:
// pure model, i.e. minimal information that is convenient for storage
abstract class Node
{
public int BaseProperty { get; set; }
public NodeCollection Children { get; private set; } // : Collection<Node>
}
class NodeA /* NodeB, NodeC ... */ : Node
{
public int DerivedAProperty { get; set; }
}
と
// objects that are convenient for being used by the application
abstract class MyNode
{
public int MyBaseProperty { get; set; }
public MyNodeCollection Children { get; private set; } // : Collection<MyNode>
}
class MyNodeA /* MyNodeB, MyNodeC ... */ : MyNode
{
public int MyDerivedAProperty { get; set; }
}
、そしてクラスをまったく変更せずに、タイプのオブジェクトグラフをNodeX
タイプの1つにMyNodeX
、またはその逆に変換する必要があります。私はこのパターンを定期的に使用していることに気付きました。NodeX
NodeX-> MyNodeX
// USAGE / external code
Node node = ...
MyNode myNode = MyNode.Load(node, ARGS); // static factory
abstract class MyNode
{
...
// factory
public static MyNode Load(Node node, ARGS)
{
var type = node.GetType();
MyNode myNode;
// no 'is' usage because NodeB could be derived from NodeC etc.
if (type == typeof(NodeA))
myNode = new MyNodeA(ARGS); // arbitrary ctor
else if (...)
...
myNode.Load(Node);
return myNode
}
public virtual void Load(Node node)
{
this.MyBaseProperty = node.BaseProperty;
foreach (var child in node.Children)
this.Children.Add(MyNode.Load(child, this.ARGS));
}
}
class MyNodeA : MyNode
{
...
public override void Load(Node node)
{
var m = (NodeA)node; // provoke InvalidCastException if coding error
base.Load(node);
this.MyDerivedAProperty = m.DerivedAProperty;
}
}
MyNodeX-> NodeX
// USAGE / external code
MyNode myNode = ...
Node node = myNode.Commit();
abstract class MyNode
{
...
// 'kind of' factory
public abstract Node Commit();
public virtual Commit(Node node)
{
node.BaseProperty = this.MyBaseProperty;
foreach (var child in this.Children)
node.Children.Add(child.Commit());
}
}
class MyNodeA : MyNode
{
...
public override Node Commit()
{
var m = new NodeA(); // "factory" method for each type
this.Commit(m);
return m;
}
public override void Commit(Node node)
{
var m = (NodeA)node; // provoke InvalidCastException if coding error
base.Commit(node);
m.DerivedAProperty = this.MyDerivedAProperty;
}
}
私はこのアプローチを何度も成功裏に使用してきましたが、クラスに追加する必要のあるメソッドは単純であり、外部コードも単純であるため、一般的に気に入っています。base.Load(node)
また、 /を呼び出すことでコードの重複を回避しますbase.Commit(node)
。Load
ただし、静的ファクトリメソッドのif/elseラダーは本当に好きではありません。
MyNode-> Node ()の場合と同様に、Node-> MyNode( )の場合の各タイプにファクトリメソッドを設定することをお勧めします。しかし、明らかに少し問題があります。私はまた、私が今しなければならない2つのキャストをしたくないです。Load
Commit
static
virtual
どういうわけかそのようなことを達成することは可能ですか?