前文c++ 装饰者模式一
讲到的装饰者模式是一个自外向里包含的模式,有点不符合一般人的习惯
本文介绍的是
obj.withDecorator(other1).withDecorator(other2)
这种更加符合一般人习惯的装饰者模式
#include <iostream>
#include <string>
#include <memory>
#include <cassert>
using namespace std;
// 反射相关
class funcValidPolicy {
public:
template<typename , typename ... >
static false_type Valid(...);
template<typename F, typename ... Args, typename = decltype(declval<F>()(declval<Args>()...))>
static true_type Valid(void *);
};
template<typename T>
struct TypeT {
using type = T;
};
template<typename T>
constexpr auto type = TypeT<T>{};
template<typename T>
T ValueT(TypeT<T>);
auto is_valid = [](auto f) {
return [](auto ...args) {
return decltype(funcValidPolicy::template Valid<decltype(f), decltype(args)...>(nullptr)){};
//return isInvokeAble<decltype(f), decltype(args)...>::value;
};
};
// 类型必须要getInstance函数
auto has_getInstance = is_valid([](auto t) -> decltype(decltype(ValueT(t))::getInstance()) {
});
string doubleToStr(double price) {
char buffer[128];
snprintf(buffer, sizeof(buffer), "%.2lf", price);
return buffer;
}
string descriptionFormat(const string &name, double price) {
return "with " + name + "(" + doubleToStr(price) + ")\n";
}
#define shared_instance_func(name) \
static shared_ptr<name> getInstance() { \
return shared_ptr<name>(new name); \
}
#define DecoratorDefaultFunc(name) \
private: \
shared_ptr<Beverage> beverage; \
explicit name(Beverage* bev = nullptr) : beverage(bev){} \
\
public: \
void setBeverage(const shared_ptr<Beverage>& bev) override{ \
beverage = bev; \
}\
shared_instance_func(name)
class Decorator;
class Beverage : public enable_shared_from_this<Beverage> {
public:
string _description;
virtual string getDescription() {
return _description + "(" + doubleToStr(totalCost()) + ")\n";
}
virtual double totalCost() = 0;
virtual ~Beverage() = default;
virtual void setBeverage(const shared_ptr<Beverage> &) {}
template<typename T, typename = enable_if_t<
is_base_of_v<Decorator, decay_t<T>> &&
has_getInstance(type<T>)
>>
auto withDecorator();
template<typename T, typename = enable_if_t<
is_base_of_v<Decorator, decay_t<T>> &&
has_getInstance(type<T>)
>>
auto withDecorator(shared_ptr<T>);
};
// 抽象类,带数据
class Decorator : public Beverage {
public:
//
string getDescription() override = 0;
double totalCost() override = 0;
virtual double cost() = 0;
};
template<typename T, typename>
auto Beverage::withDecorator() {
auto beverage = T::getInstance();
beverage->setBeverage(shared_from_this());
return beverage;
}
template<typename T, typename>
auto Beverage::withDecorator(shared_ptr<T> beverage) {
beverage->setBeverage(shared_from_this());
return beverage;
}
class Espresso : public Beverage {
private:
Espresso() {
_description = "Espresso";
}
public:
shared_instance_func(Espresso)
double totalCost() override {
return 1.99;
}
};
class Mocha : public Decorator {
public:
DecoratorDefaultFunc(Mocha)
string getDescription() override {
assert(nullptr != beverage);
return beverage->getDescription() + descriptionFormat("Mocha", cost());
}
double totalCost() override {
assert(nullptr != beverage);
return beverage->totalCost() + cost();
}
double cost() override {
return .32;
}
};
class Whip : public Decorator {
public:
DecoratorDefaultFunc(Whip)
string getDescription() override {
return beverage->getDescription() + descriptionFormat("Whip", cost());
}
double totalCost() override {
return beverage->totalCost() + cost();
}
double cost() override {
return .23;
}
};
class NoGetInstance : public Decorator {
public:
string getDescription() override {
return Decorator::getDescription();
}
double totalCost() override {
return Decorator::totalCost();
}
double cost() override {
return 0;
}
};
int main() {
// 用法一
auto a = Espresso::getInstance();
auto ab = a->withDecorator<Mocha>()->withDecorator<Whip>()->withDecorator<Mocha>();
cout << ab->getDescription() << "total : ";
cout << ab->totalCost() << endl << endl;
// 用法二
auto d = Espresso::getInstance();
auto de = d->withDecorator(Mocha::getInstance())->withDecorator(Whip::getInstance())->withDecorator(
Mocha::getInstance());
cout << de->getDescription() << "total : ";
cout << de->totalCost() << endl;
}