当只能更改一侧时重构紧密耦合的类

Refactoring tightly coupled classes when only one side can be changed

本文关键字:重构 耦合      更新时间:2023-10-16

请提前接受我对这个有点冗长的问题的道歉。这是我能想到的最小的自包含示例......我很确定这个问题一定有一些明显/漂亮/整洁的解决方案,但我目前看不到它。

好的,问题来了:想象一下以下情况(注意,代码的可编译版本可在 http://goo.gl/dhRNex 获得(。假设

struct Thing1 {
public:
  void bar(class Implementation1 &i) {
    i.baz();
  }
  // ...various other methods like bar()
};
struct Thing2 {
public:
  void bar(class Implementation2 &i) {
    i.qux();
  }
  // ...various other methods like bar()
};

被给予。不幸的是,这些类是固定的,即不能更改/重构。

但是,Implementation1Implementation2是可变的。这两个类共享许多相似的代码,因此将共享代码放在公共基类中似乎是很自然的。但是,代码依赖于所使用的Thing类型,但是Thing1Thing2没有通用的基类,因此使用模板似乎也很自然。因此,我为基类提出了以下解决方案

template<class T, class S>
struct ImplementationBase {
public:
  S *self;
  void foo() {
    T thing;
    thing.bar(*self);
  }
  // ...lots more shared code like foo()
};

和具体实施

struct Implementation1 : public ImplementationBase<class Thing1, class Implementation1> {
public:
  Implementation1() {
    self = this;
  }
  void baz() {
    std::cout << "Qux!" << std::endl;
  }
};
struct Implementation2 : public ImplementationBase<class Thing2, class Implementation2> {
public:
  Implementation2() {
    self = this;
  }
  void qux() {
    std::cout << "Qux!" << std::endl;
  }
};

理想情况下,人们会在foo中使用this而不是self,但问题是thisImplementationBase<class Thing1, class Implementation1>类型,但Implementation1是必需的。显然,整个事情相当混乱,ImplementationThing类耦合得太紧密,但是如果不能够重构Thing类,我就看不到一个简单的出路。所以,最后,我的问题是:

  1. 除了使用上面的self技巧之外,有没有更好的选择?
  2. 有没有一种设计可以更好地解决这个问题?(我有一种感觉,有,但我错过了一些明显的东西(

如果您已经做到了这一点,非常感谢您抽出宝贵时间阅读整个故事,并为这个冗长的问题再次道歉。

你已经在使用 CRTP,所以你根本不需要自我:

template<class T, class S>
struct ImplementationBase {        
public:
  S* getThis() { return static_cast<S*>(this); }
  void foo() {
    T thing;
    thing.bar(*getThis());
  }
  // ...lots more shared code like foo()
};