黄国强 2023/06/12
这篇文章我们引入新的概念,即输入(Input)。类似 Output ,Input 也有多种输入形式。同样我们也需要做个设计,封装后续的变化。继续上代码。
/
// 输入类
class Input;
using InputPtr = std::shared_ptr<Input>;
class Input
{
public:
Input();
public:
// 如果对象是一个组合,返回 Index 指定的第几个子对象,否则返回一个空对象
Input * At(int Index) { return DoAt(Index); }
// 连接一个 Data 对象
void DataLink(Data * p);
// 是否是组合对象
bool IsComposite() const { return DoComposite(); }
// 是否是空对象
bool IsNullObj() const { return DoNullObj(); }
// 获得一个空对象
static InputPtr NullObj();
// 如果对象是一个组合,返回子对象个数,否则返回 0
int Size() const { return DoSize(); }
// 获取 Input 的值
double Val_d() const { return DoVal_d(); }
int Val_i() const { return DoVal_i(); }
Json::Value Val_j() const { return DoVal_j(); }
std::string Val_s() const { return DoVal_s(); }
// 触发通知给 Data, Input 中数据更新, pOutputNotPublish 是不需要推送的 Ouput 对象指针
void TriggerChanged(Output * pOutputNotPublish) {
DoTriggerChanged(pOutputNotPublish); }
protected: // 下面是 NVI 模式的虚函数
virtual Input * DoAt(int Index) const { return NullObj().get(); }
virtual bool DoComposite() const { return false; }
virtual bool DoNullObj() const { return false; }
virtual int DoSize() const { return 0; }
virtual void DoTriggerChanged(Output * pOutputNotPublish) {}
virtual double DoVal_d() const { return 0.; }
virtual int DoVal_i() const { return 0; }
virtual Json::Value DoVal_j() const { return Json::Value(); }
virtual std::string DoVal_s() const { return ""; }
protected:
Data * _pData{ nullptr };
};
AfcQtEdit 既是 Output 也是 Input,故需要同时继承 Output 和 Input。AfcQtEdit 修改后的代码如下。
///
// QT LineEdit Input
class AfcQtEdit : public AFC::Output, public AFC::Input
{
public:
AfcQtEdit(QLabel * pLable, QLineEdit * pEdit);
protected: // Output
virtual void DoSubjectInfo(const Json::Value& val) override;
virtual void DoSubjectUpdate(const std::string& val) override;
protected: // Input
virtual void DoTriggerChanged(Output * pOutputNotPublish) override;
virtual std::string DoVal_s() const override;
private:
QLabel * _pLable{ nullptr };
QLineEdit * _pEdit{ nullptr };
};
整个调用时序图。
过程有些复杂,为什么简单的一个赋值需要绕这么大的弯子?达到了什么目的?答案是,这三个基类 Ouput、Input 和 Data 可以在不必知道派生类的情况下进行交互。这点很重要。Ouput、Input 和 Data 以及后续基本类本质上是桥接模式(bridge pattern),在我看来,所有架构都可以看做桥接模式或桥接模式的变体。
[参考]
1 软件之禅(四)用观察者模式连接 Data 和 Output