引入
对于一个银行账户对象,与其对应的log类
struct Logger {
virtual ~Logger() = default;
virtual void info(const string& s)=0;
virtual void warn(const string& s)=0;
};
class BankAccount {
shared_ptr< Logger>log;
public:
string name;
int balance = 0;
BankAccount( const string& name, int balance, const shared_ptr<Logger>& logger)
:log{ logger }, name{ name }, balance{ balance }{}
void deposit(int amount) {
balance += amount;
log->info("Deposited $");
}
};
//正常使用的对象
struct ConsoleLogger :Logger {
void info(const string& s)override {
cout << "INFO:" << s << endl;
}
void warn(const string& s)override {
cout << "WARN:" << s << endl;
}
};
当输入参数shared_ptr为空指针时候将会报错,如何避免呢?
空对象
可以预测到何时适用空对象时,可以显式将该类传入
//空对象类
struct NULLLogger :Logger {
void info(const string& s)override {
}
void warn(const string& s)override {
}
};
隐式空对象
//隐式空对象
struct OptionalLogger :Logger {
shared_ptr<Logger> impl;
static shared_ptr<Logger> no_logging;
OptionalLogger(const shared_ptr<Logger>& logger) :impl{ logger } {}
void info(const string& s)override {
if (impl)impl->info(s);
}
void warn(const string& s)override {
if (impl)impl->warn (s);
}
};
隐式空对象将适用log分为调用和操作,通过将一个空对象设置为静态成员变量,当且仅当存在impl时,才进行调用。
总结
通过代码我们可以知道:空对象模式是为了解决不使用某个子成员变量时的问题,如果我们可以提前预支,那么可以传递一个什么都不做的空类,否则我们需要使用隐式空对象来实现,