软件之禅(五)Input 出场

黄国强 2023/06/12

        这篇文章我们引入新的概念,即输入(Input)。类似 Output ,Input 也有多种输入形式。同样我们也需要做个设计,封装后续的变化。继续上代码。

/
// 输入类

class Input;
using InputPtr = std::shared_ptr;

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 };
};

整个调用时序图。

软件之禅(五)Input 出场_第1张图片

        过程有些复杂,为什么简单的一个赋值需要绕这么大的弯子?达到了什么目的?答案是,这三个基类 Ouput、Input 和 Data 可以在不必知道派生类的情况下进行交互。这点很重要。Ouput、Input 和 Data 以及后续基本类本质上是桥接模式(bridge pattern),在我看来,所有架构都可以看做桥接模式或桥接模式的变体。

[参考]
  1 软件之禅(四)用观察者模式连接 Data 和 Output 
  2 软件之禅(六)图灵机

你可能感兴趣的:(c++,面向对象编程)