c++ - 如何处理已发布的抽象基类的变化?

标签 c++ oop design-patterns object-oriented-analysis

我开发了一个“犬舍”应用程序来照顾各种狗。我的客户需要允许他们的狗加入我的应用程序以使用这些服务。

因此,我定义了一个通用的“Dog”接口(interface)。客户端需要实现接口(interface)来创建具体的狗类型(比如拉布拉多犬、 Poodle 等),实例化它们并将它们接纳到我的犬舍应用程序(使用 say,kennel::admitDog(dog *dog ).

这是 Dog 抽象基类:

class Dog {
public:
    Dog()
    {

    }

    virtual ~Dog()
    {

    }

    virtual void eatFood() = 0;
    virtual void takeBath() = 0;
    virtual void play() = 0;
    virtual void sleep() = 0;
};

我发布了这个接口(interface),我的客户已经开始使用它来创建他们自己的具体 Dog 类型。在下一版本的应用程序中,我计划在狗窝中支持机器狗。

问题来了。机器狗需要上述抽象基类中的Dog::r​​echargeBattery()。而且,它不需要现有的 Dog::eatFood() 函数。将 Dog::r​​echargeBattery() 添加到上述抽象基类会影响所有已经在使用此接口(interface)的现有客户端。他们将被迫执行 Dog::r​​echargeBattery() 并重新编译。这可能是不可取的。

  1. 此时的解决方案是什么?
  2. 在初始设计中我应该怎么做才能避免这个问题?

最佳答案

这个:

class Dog {
    virtual void eatFood() = 0;
    virtual void takeBath() = 0;
    virtual void play() = 0;
    virtual void sleep() = 0;
};

class Kennel {
    void admit (Dog*);
}

变成这样:

class DogLike {
    // virtual void eatFood() = 0; <-- removed
    virtual void takeBath() = 0;
    virtual void play() = 0;
    virtual void sleep() = 0;
};

class Dog : public DogLike {
    virtual void eatFood() = 0; // <-- added
};

class RoboticDog : public DogLike {
    virtual void rechargeBatteries() = 0;
};

class Kennel {
    void admit (DogLike*);
};

现有客户端应该与您修改后的库源代码兼容(但几乎肯定不是二进制兼容)。实现二进制兼容性可能可行也可能不可行,但对已发布的 Dog 类进行任何更改都是如此。

既然客户应该知道他们交给狗舍的是哪种狗,就可以修改狗舍界面以将活狗与机器狗分开:

class Kennel {
  public:
    void admit (Dog*);
    void admit (RoboticDog*);
};

其他种类的犬类不得入内。

下一步是什么?据推测,犬舍有设施可以为所有回答 DogLike 界面的人提供服务,并为活狗和机器狗提供单独的设施。

void Kennel::admit (Dog* dog) {
    commonFacilities.admit(dog);
    messHall.admit(dog);
}

void Kennel::admit (RoboticDog* dog) {
    commonFacilities.admit(dog);
    chargingStation.admit(dog);
}

仍然没有类型转换。如果不希望有两个公共(public) admit 方法,可以将它们隐藏在一个在幕后检查动态类型的外观后面。

class Kennel {
    void admit (Dog*);
    void admit (RoboticDog*);
  public:
    void admit (DogLike* dog) {
      if (auto d = dynamic_cast<Dog*>(dog)) 
        admit (d);
      else if (auto d = dynamic_cast<RoboticDog*>(dog)) 
        admit (d);
      else
        throw UnknownDogTypeError;
    }
};

关于c++ - 如何处理已发布的抽象基类的变化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47379250/

相关文章:

C++ - 在模板类之外但在头文件中定义成员函数

c++ - 结构指针的运算符重载

matlab - 是否可以使用枚举作为 MATLAB 矢量或 map 的下标?

oop - 是否存在确定方法或字段是否属于类的启发式方法?

c++ - std::span 是 View 吗?

c++ - 在 Windows 上跟踪移动到回收站的进度

ios - objective-c : Need suggestion for my way of having protected method?

c++ - Barton-Nackman 技巧中使用的 C++ 非模板成员是什么?

javascript - 如何在javascript中实现观察者模式?

design-patterns - 规范数据模型的缺点是什么?