我有两个类似的类.你会使用什么设计来分解代码

I have these two similar classes. What design would you use to factorize code?

本文关键字:什么 代码 分解 两个      更新时间:2023-10-16

我有一个相当复杂的类似图形的数据结构。为了清楚起见,让我们将其简化为:

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 继承的方法。

你会使用什么设计来分解代码?我正在考虑三种方法:

1. 使用自由函数

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(); }
}

优点:

  • 非常简单的解决方案,总比完全不分解要好得多。

缺点:

  • 并非所有方法都可以作为自由函数实现。

  • 声明代码仍然重复。

2. 使用继承

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中需要小心,以强制执行Oriented Edge1::edge始终指向Egde1*。

  • 不知何故,static_cast感觉不对劲。

3. 使用模板

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(); }
}

优点:

  • 大多数因子分解。

  • 存储在两个类中的指针具有正确的类型,无需强制转换。

缺点:

  • 需要在标头中保留共享代码的实现,这强制包含 AbstractEdge.h(可以通过使用以前的方法进行前向声明来避免(。

问题:您倾向于使用哪种方法?您还有其他解决方案或建议吗?

1 和 3。

3 删除重复的样板,1 将实现移动到我想要的任何地方。