我有一个非常复杂的图形数据结构。为了清楚起见,我们将其简化为:
class Node;
class AbstractEdge { void foo() {} };
class Edge1: public AbstractEdge { void bar1() {} };
class Edge2: public AbstractEdge { void bar2() {} };
正如您所看到的,我们的图形与任何其他图形不同:存在两种边缘,两者都继承自AbstractEdge。这种设计无法改变。现在,假设我必须设计两个类:
class OrientedEdge1
{
Edge1 * edge;
bool orientation;
void foo() { edge->foo(); }
void bar1() { edge->bar1(); }
}
class OrientedEdge2
{
Edge2 * edge;
bool orientation;
void foo() { edge->foo(); }
void bar2() { edge->bar2(); }
}
实际上,OrientedEdge1 :: foo()和OrientedEdge2 :: foo()比调用单个方法要长得多,但想法是它们是相同的,只调用从AbstractEdge继承的方法。
您将使用什么样的设计来分解代码?我正在考虑三种方法:
foo_impl(AbstractEdge * edge) { edge->foo(); }
class OrientedEdge1
{
Edge1 * edge;
bool orientation;
void foo() { foo_impl(edge); }
void bar1() { edge->bar1(); }
}
class OrientedEdge2
{
Edge2 * edge;
bool orientation;
void foo() { foo_impl(edge); }
void bar2() { edge->bar2(); }
}
优点:
缺点:
并非所有方法都可以作为自由函数实现。
声明代码仍然重复。
class AbstractOrientedEdge
{
AbstractEdge * edge;
bool orientation;
void foo() { edge->foo(); }
}
class OrientedEdge1: public AbstractOrientedEdge
{
Egde1 * edge1() { return static_cast<Egde1*>(edge); }
void bar1() { edge1()->bar1(); }
}
class OrientedEdge2: public AbstractOrientedEdge
{
Egde2 * edge2() { return static_cast<Egde2*>(edge); }
void bar2() { edge2()->bar2(); }
}
优点:
更多因素化。
我不打算以多态方式使用这两个类,但谁知道,也许它们通过继承相关的事实可能在将来变得有用。
缺点:
在构造函数/ setter中需要注意强制OrientedEdge1 :: edge始终指向Egde1 *。
不知何故,static_cast感觉不对。
template <class EdgeT>
class OrientedEdge
{
EdgeT * edge;
bool orientation;
void foo() { edge->foo(); }
}
class OrientedEdge1: public OrientedEdge<Edge1>
{
void bar1() { edge->bar1(); }
}
class OrientedEdge2: public OrientedEdge<Edge2>
{
void bar2() { edge->bar2(); }
}
优点:
大部分因素化。
存储在两个类中的指针都具有正确的类型,不需要转换。
缺点:
问题:您倾向于使用哪种方法?你有其他解决方案或建议吗?
答案 0 :(得分:1)
1和3。
3删除重复的样板,1移动实现,无论我想要什么。