X

曜彤.手记

随记,关于互联网技术、产品与创业

吉 ICP 备10004938号

“单一职责类”设计模式(C++)


在软件组件的设计中,如果责任划分的不清晰,使用继承得到的结果往往是:随着需求的变化,子类急剧膨胀,同时充斥着重复代码的。而这时候的关键则是划清责任。

装饰模式(Decorator)

在某些情况下我们可能会“过度地使用继承扩展对象的功能”,由于继承为对象引入的静态特质,使得这种方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。如何使“对象功能的扩展”能够根据需求来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响降为最低?

模式定义:动态(组合)地给一些对象增加一些额外的职责。就增加功能而言,装饰模式比生成子类(继承)更为灵活(消除重复代码+减少子类数量)。

struct Component {
  virtual void foo() = 0;
  virtual ~Component() {}
};
// single responsibility;
struct ComponentA : public Component {
  void foo() {
    std::cout << "[Component A]" << std::endl;
  }
};
// decorator (用于基于原子功能进行扩展);
struct DecoratorComponent : public Component {  // 特征:对同一个类,即继承,又包含;
  DecoratorComponent(Component* component) : component(component) {}
 protected:
  Component* component;
};
struct DecoratorComponentA : public DecoratorComponent {
  DecoratorComponentA(Component* component) : DecoratorComponent(component) {}
  void foo() {
    component->foo();
    std::cout << "[DecoratorComponent A]" << std::endl;
  }
};
int main(int argc, char** argv) {
  auto componentA = new ComponentA();
  auto decoratorComponentA = new DecoratorComponentA(componentA);
  decoratorComponentA->foo();
  return 0;
}

总结:

桥模式(Bridge)

由于某些类型的固有实现逻辑,使得他们具有两个变化的纬度,乃至多个纬度的变化。如何应对这种“多维度的变化”?如何利用 OOP 技术来使得类型可以轻松地沿着两个乃至多个方向变化,而不引入额外的复杂度?

其中 Abstraction 与 Implementor 是稳定的。

模式定义:将抽象部分(业务功能)与实现部分(平台实现)分离。使它们都可以独立地变化。

struct Implementator {  // 对物体抽象的操作(实现),通常由物体调用;
  ~Implementator() {}
  virtual void implement() = 0;
};
struct ImplementatorA : public Implementator {  // 操作层面的变化纬度;
  void implement() {
    std::cout << "[Implementator A]" << std::endl;
  }
};
struct Abstraction {  // 抽象的物体;
  Abstraction(Implementator* impl) : impl(impl) {}
  ~Abstraction() {}
  virtual void foo() = 0;
 protected:
  Implementator *impl;
};
struct AbstractionA : public Abstraction {   // 物体层面的变化纬度;
  using Abstraction::Abstraction;
  void foo() {
    std::cout << "[Abstraction A]" << std::endl;
    impl->implement();
  }
};
int main(int argc, char **argv) {
  auto implementatorA = new ImplementatorA{};
  auto abstractionA = new AbstractionA(implementatorA);
  abstractionA->foo();
  return 0;
}

总结:

综合来看,装饰模式适用于为不同实现进行不同的扩展,重在基于实现的扩展;而桥模式适用于为某些固有实现,使得它们可以分别向两个或多个方向独立变化



这是文章底线,下面是评论
  暂无评论,欢迎勾搭 :)