本文為 C++ Software Design 書的第 28 節內容。
Bridge pattern 的目的是將 implementation 與 abstraction 盡可能分離開來。舉個例子:
class ElectricEngine {
};
class ElectricCar {
public:
ElectricCar() : engine_{ /*ElectricEngine params*/ } { ... };
private:
ElectricEngine engine_;
};
上述例子中當 ElectricEngine 改變時,ElectricCar 也得跟著改變。使用 forward declaration 與指標為解決這個問題的一種方法:
//--- ElectricCar.h ---
struct ElectricEngine; // Forward declaration
class ElectricCar {
private:
std::unique_ptr<ElectricEngine> engine_;
};
//--- ElectricCar.cpp ---
#include "ElectricEngine.h" // Include the real header here!
ElectricCar::ElectricCar() : engine_{ std::make_unique(...) }
而 Bridge pattern 則是將 Engine 再加一層 abstraction 讓引擎可以有多種實作方式:
//--- Engine.h ---
class Engine {
};
//--- ElectricCar.h ---
#include "Engine.h"
class ElectricCar {
private:
std::unique_ptr<ElectricEngine> engine_;
};
//--- ElectricEngine.h ---
#include "Engine.h"
class ElectricEngine : public Engine {
};
//--- ElectricCar.cpp ---
#include "ElectricCar.h"
#include "ElectricEngine.h"
ElectricCar::ElectricCar() : engine_{ std::make_unique<ElectricEngine>(...) }
如此一來就能將需要 dependency 降到最低。
Pointer-to-implementation (Pimpl) 是實作 bridge pattern 的一種方法。雖然概念簡單但其中有不少細節:
//--- Person.h ---
class Person {
public:
Person();
// Rule of 5
~Person();
Person(Person const& other);
Person& operator=(Person const& other);
Person(Person&& other);
Person& operator=(Person&& other);
private:
struct Impl;
std::unique_ptr<Impl> const pimpl_;
};
//--- Person.cpp ---
#include "Person.h"
struct Person::Impl {
//...
};
Person::Person() : pimpl_{std::make_unique<Impl>()} {...}
Person::~Person() = default;
Person::Person(Person const& other)
: pimpl_{std::make_unique<Impl>(*other.pimpl_)} {...}
Person& operator=(Person const& other) {
*pimpl_ = *other.pimpl_;
return *this;
}
Person::Person(Person&& other)
: pimpl_{std::make_unique<Impl>(std::move(*other.pimpl_))} {...}
Person& operator=(Person&& other) {
*pimpl_ = std::move(*other.pimpl_);
return *this;
}
最重要的細節是 destructor 必須 declare 在 Person.h,但是得 define 在 Person.cpp。因為 pimpl_ 內的類別為在 Person.h 中沒有 definition 的 Impl,在 Person.cpp 中加入 default destructor (而不是寫在 Person.h)即可。由於我們自己寫了 destructor,我們同時得符合 rule of 5。
沒有留言:
張貼留言