C++ 设计模式----组件协作型模式

这篇具有很好参考价值的文章主要介绍了C++ 设计模式----组件协作型模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

面向对象设计,为什么?

回答:变化是复用的天敌!面向对象设计最大的优势在于:抵御变化

重新认识面向对象

理解隔离变化

​ 从宏观层面来看,面向对象的构建方式更能适应软件的变化,能将变化所带来的影响减为最小

各司其职

​ • 从微观层面来看,面向对象的方式更强调各个类的“责任”

​ • 由于需求变化导致的新增类型不应该影响原来类型的实现——是所谓各负其责

对象是什么?

​ • 从语言实现层面来看,对象封装了代码和数据。

​ • 从规格层面讲,对象是一系列可被使用的公共接口。

​ • 从概念层面讲,对象是某种拥有责任的抽象。

GOF-23 模式分类

从目的来看:

​ • 创建型(Creational)模式:将对象的部分创建工作延迟到子类或者其他对象,从而应对需求变化为对象创建时具体类型实现引来的冲击。

​ • 结构型(Structural)模式:通过类继承或者对象组合获得更灵活的结构,从而应对需求变化为对象的结构带来的冲击。

​ • 行为型(Behavioral)模式:通过类继承或者对象组合来划分类与对象间的职责,从而应对需求变化为多个交互的对象带来的冲击。

从范围来看:

​ • 类模式处理类与子类的静态关系。

​ • 对象模式处理对象间的动态关系。

从封装变化角度对模式分类

C++ 设计模式----组件协作型模式

重构获得模式 Refactoring to Patterns

 面向对象设计模式是“好的面向对象设计”,所谓“好的面向对象设计”指是那些可以满足 “应对变化,提高复用”的设计 。

 现代软件设计的特征是**“需求的频繁变化”。设计模式的要点是“寻找变化点,然后在变化点处应用设计模式,从而来更好地应对需求的变化”.“什么时候、什么地点应用设计模式”**比“理解设计模式结构本身”更为重要。

 设计模式的应用不宜先入为主,一上来就使用设计模式是对设计模式的最大误用。没有一步到位的设计模式。**敏捷软件开发实践提倡的“Refactoring to Patterns”**是目前普遍公认的最好的使用设计模式的方法。

重构关键技法

 静态 ->  动态

早绑定 ->  晚绑定

​  继承 ->  组合

 编译时依赖 ->  运行时依赖

 紧耦合 ->  松耦合

模板方法模式(c++)

一、组件协作型模式

“组件协作”模式 :现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。

早绑定——————>晚绑定

早绑定:在应用程序中调用库

晚绑定:在库中调用应用程序,模板方法模式就是把主流程放在库里,库的使用者只需要实现子步骤就可以了

典型模式

• Template Method

• Observer / Event

• Strategy

【1】TemplateMethod

**动机(Motivation)**💡:

  • 在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因 (比如框架与应用之间的关系)子步骤无法和任务的整体结构同时实现

**问题思考(Consider)**🤔:

  • 如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求

对某一项任务,用结构化软件设计流程(使用了早绑定)和面向对象设计软件流程(使用了晚绑定)的区别:

C++ 设计模式----组件协作型模式

(1)结构化软件设计流程

C++ 设计模式----组件协作型模式
C++执行代码:

template1_lib.cpp

#include<iostream>
using namespace std;

//程序库开发人员
class Library {
public:
	void Step1() {
		cout << "Step1" << endl;
	}

	void Step3() {
		cout << "Step3" << endl;
	}

	void Step5() {
		cout << "Step5" << endl;
	}
};

template1_app.cpp

#include "template1_lib.cpp"

//应用程序开发人员
class Application {
public:
	bool Step2() {
		cout << "myStep2" << endl;
		return true;
	}

	void Step4() {
		cout << "myStep4" << endl;
	}
};

int main() {
	Library lib;
	Application app;
	lib.Step1();

	if (app.Step2()) {
		lib.Step3();
	}

	for (int i = 0; i < 4; i++) {
		app.Step4();
	}

	lib.Step5();
}

C++ 设计模式----组件协作型模式

(2)面向对象软件设计流程

C++ 设计模式----组件协作型模式

C++执行代码:

template2_lib.cpp

#include<iostream>
using namespace std;

//程序库开发人员
class Library {
public:
	//稳定 template method
	void Run() {
		Step1();
		if (Step2()) {
			//支持变化 ==> 虚函数的多态调用
			Step3();
		}

		for (int i = 0; i < 4;i++) {
			Step4();//支持变化 ==> 虚函数的多态调用
		}
		Step5();
	}

	virtual ~Library() {};
protected:
	void Step1() {
		//稳定
		cout << "Step1" << endl;
	}

	void Step3() {
		//稳定
		cout << "Step3" << endl;
	}

	void Step5() {
		//稳定
		cout << "Step5" << endl;
	}

	virtual bool Step2() = 0;//变化
	virtual void Step4() = 0;//变化
};

template2_app.cpp

#include "template2_lib.cpp"
#include <iostream>

using namespace std;

//应用程序开发人员
class Application : public Library {
protected:
	virtual bool Step2() {
		//... 子类重写实现
		cout << "override Step2" << endl;
		return true;
	}

	virtual void Step4() {
		//... 子类重写实现
		cout << "override Step4" << endl;
	}
};

int main() {
	Library* pLib = new Application();
	pLib->Run();
	 
	delete pLib;
	return 0;
}

C++ 设计模式----组件协作型模式

模式定义

定义一个操作中的算法的骨架 (稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override 重写)该算法的某些特定步骤。
——《设计模式》GoF

结构(Structure)

C++ 设计模式----组件协作型模式

要点总结

 Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制**(虚函数的多态性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构**。

 除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是Template Method的典型应用

 在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将它们设置为protected方法

【2】Strategy 策略模式

动机(Motivation)💡:

  • 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。

**问题思考(Consider)**🤔:

  • 如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题?

C++执行代码:

strategy1.cpp(无使用Strategy策略模式)

若想新增法国税法,如何实现?

#include<iostream>
using namespace std;
enum TaxBase {
    CN_Tax,
    US_Tax,
    DE_Tax,
    FR_Tax       //更改(增加法国税法计算方式)
};

class SalesOrder {
    TaxBase tax;
    double sum = 0;
public:
    double CalculateTax(TaxBase tax) {
        //...
        if (tax == CN_Tax) {
            //CN***********
            cout << "中国税法计算" << endl;
            sum += 1;
            
        }
        else if (tax == US_Tax) {
            //US***********
            cout << "美国税法计算" << endl;
            sum += 2;
        }
        else if (tax == DE_Tax) {
            //DE***********
            cout << "德国税法计算" << endl;
            sum += 3;
        }
        else if (tax == FR_Tax) {  //更改(增加法国税法计算方式)
            cout << "法国税法计算" << endl;
            sum += 4;
        }

        //....
        return sum;
    }

};

int main() {
    TaxBase tax;
    tax = FR_Tax;
    SalesOrder *so =  new SalesOrder();
    cout << so->CalculateTax(tax) << endl;
    return 0;
}

缺点:第一种方法需要去改枚举类型,需要往方法内部补充一些代码,打破了开放封闭原则,违背了复用性(二进制层面的复用性)。

strategy2.cpp(使用Strategy策略模式)

// 这两个类的具体实现不重要
class Context {

};

class StrategyFactory {
public:
    TaxStrategy* NewStrategy() {
        return nullptr; // ...
    }
};

//税率策略模式类
class TaxStrategy {
public:
    virtual double Calculate(const Context& context) = 0;
    virtual ~TaxStrategy() {}
};

//CNTax 中国税法
class CNTax : public TaxStrategy {
public:
    virtual double Calculate(const Context& context) {
        //***********
    }
};

//USTax 美国税法
class USTax : public TaxStrategy {
public:
    virtual double Calculate(const Context& context) {
        //***********
    }
};

//DETax 德国税法
class DETax : public TaxStrategy {
public:
    virtual double Calculate(const Context& context) {
        //***********
    }
};


//扩展
//*********************************
//FRTax 法国税法
class FRTax : public TaxStrategy {
public:
    virtual double Calculate(const Context& context) {
        //.........
    }
};

//不需要变化的
class SalesOrder {
private:
    TaxStrategy* strategy;

public:
    // 工厂模式
    SalesOrder(StrategyFactory* strategyFactory) {
        this->strategy = strategyFactory->NewStrategy();
    }
    ~SalesOrder() {
        delete this->strategy;
    }

    double CalculateTax() {
        //...
        Context context;

        double val = strategy->Calculate(context); //多态调用
        //...
    }

};

第二种写法遵循了开放封闭原则

模式定义

定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化)。该模式使得算法可独立于使用它的客户程序(稳定)而变化(扩展,子类化)。

——《设计模式》GoF

结构(Structure)

C++ 设计模式----组件协作型模式

要点总结

 Strategy及其子类为组件提供了一系列可重用的算法,从而可以使得类型在运行时方便地根据需要在各个算法之间进行切换。

 Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。

 如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。

【3】Observer 观察者模式

动机(Motivation)💡:

 在软件构建过程中,我们需要为某些对象建立一种**“通知依赖关系”** ——一个对象(目标对象)的状态发生改变,所有的依赖对

象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。

 使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合

**问题思考(Consider)**🤔:

C++执行代码:

FileSplitter1.cpp

#include <string>
#include <iostream>
using std::string;

class ProgressBar{
public:
	void setValue(float value){
		// ...
	}
};

class FileSplitter
{
	string m_filePath;
	int m_fileNumber;
	ProgressBar* m_progressBar;//具体通知机制

public:
	FileSplitter(const string& filePath, int fileNumber, ProgressBar* progressBar) :
		m_filePath(filePath), 
		m_fileNumber(fileNumber),
		m_progressBar(progressBar){

	}

	void split(){

		//1.读取大文件

		//2.分批次向小文件中写入
		for (int i = 0; i < m_fileNumber; i++){
			//...
			float progressValue = m_fileNumber;
			progressValue = (i + 1) / progressValue;
			m_progressBar->setValue(progressValue);
		}

	}
};

MainForm1.cpp

#include <string>
#include <iostream>
using std::string;

// 以下几个类的具体实现不重要
class Form{

};

class TextBox{
public:
	string getText(){
		// ...
		return "";
	}
};

class ProgressBar;

class FileSplitter{
public:
	FileSplitter(string filePath, int number, ProgressBar* progressBar){
		// ...
	}

	void split(){
		// ...
	}
};



// 
class MainForm : public Form
{
	TextBox* txtFilePath;
	TextBox* txtFileNumber;
	ProgressBar* progressBar;

public:
	void Button1_Click(){

		string filePath = txtFilePath->getText();
		int number = atoi(txtFileNumber->getText().c_str());

		FileSplitter splitter(filePath, number, progressBar);

		splitter.split();

	}
};


FileSplitter1.cpp

class IProgress{
public:
	virtual void DoProgress(float value)=0;
	virtual ~IProgress(){}
};


class FileSplitter
{
	string m_filePath;
	int m_fileNumber;
	//ProgressBar* m_progressBar; //具体通知机制
	//IProgress* m_iprogressList;//抽象通知机制,支持1个观察者
	List<IProgress*>  m_iprogressList; // 抽象通知机制,支持多个观察者
	
public:
	FileSplitter(const string& filePath, int fileNumber) :
		m_filePath(filePath), 
		m_fileNumber(fileNumber){

	}


	void split(){

		//1.读取大文件

		//2.分批次向小文件中写入
		for (int i = 0; i < m_fileNumber; i++){
			//...

			float progressValue = m_fileNumber;
			progressValue = (i + 1) / progressValue;
			onProgress(progressValue);//发送通知
		}

	}


	void addIProgress(IProgress* iprogress){
		m_iprogressList.push_back(iprogress);
	}

	void removeIProgress(IProgress* iprogress){
		m_iprogressList.remove(iprogress);
	}


protected:
	virtual void onProgress(float value){
		
		List<IProgress*>::iterator itor=m_iprogressList.begin();

		while (itor != m_iprogressList.end() )
			(*itor)->DoProgress(value); //更新进度条
			itor++;
		}
	}
};

MainForm2.cpp

class MainForm : public Form, public IProgress
{
	TextBox* txtFilePath;
	TextBox* txtFileNumber;

	ProgressBar* progressBar;

public:
	void Button1_Click(){

		string filePath = txtFilePath->getText();
		int number = atoi(txtFileNumber->getText().c_str());

		ConsoleNotifier cn;

		FileSplitter splitter(filePath, number);

		splitter.addIProgress(this); //订阅通知
		splitter.addIProgress(&cn)//订阅通知

		splitter.split();

		splitter.removeIProgress(this);

	}

	virtual void DoProgress(float value){
		progressBar->setValue(value);
	}
};

class ConsoleNotifier : public IProgress {
public:
	virtual void DoProgress(float value){
		cout << ".";
	}
};


网上代码(来子这个博主):https://github.com/chouxianyu/design-patterns-cpp

Observer.cpp:

#include <iostream>
#include <vector>

class Subject;

/// Observer 和 ConcreteObserver ///
//抽象观察者
class Observer
{
public:
	virtual ~Observer() {}

	virtual int getState() = 0;
	virtual void update(Subject* subject) = 0;
};

//具体观察者
class ConcreteObserver : public Observer
{
public:
	ConcreteObserver(const int state) :
		observer_state(state) {} //osbserver_state = state

	//析构函数
	~ConcreteObserver() {}

	//获取observer_state
	int getState()
	{
		return observer_state;
	}
	
	void update(Subject* subject);

private:
	int observer_state;
};

/// Subject 和 ConcreteObserver ///

class Subject
{
public:
	virtual ~Subject() {}
	//往observers添加observer
	void attach(Observer* observer)
	{
		observers.push_back(observer);
	}
	//从observers删除指定index的observer
	void detach(const int index)
	{
		observers.erase(observers.begin() + index);
	}
	//遍历observers,调用ConcreteObserver的update函数
	void notify()
	{
		for (unsigned int i = 0; i < observers.size(); i++)
		{
			observers.at(i)->update(this);
		}
	}

	virtual int getState() = 0;
	virtual void setState(const int s) = 0;

private:
	std::vector<Observer*> observers;// 抽象通知机制,支持多个观察者
};

class ConcreteSubject : public Subject
{
public:
	~ConcreteSubject() {}

	int getState()
	{
		return subject_state;
	}

	void setState(const int s)
	{
		subject_state = s;
	}

private:
	int subject_state;
};


void ConcreteObserver::update(Subject* subject)
{
	observer_state = subject->getState();
	std::cout << "Observer state updated." << std::endl;
}

int main()
{
	ConcreteObserver observer1( 1 );
	ConcreteObserver observer2( 2 );
  
	std::cout << "Observer 1 state: " << observer1.getState() << std::endl;//Observer 1 state: 1
	std::cout << "Observer 2 state: " << observer2.getState() << std::endl;//Observer 2 state: 2
  
	Subject *subject = new ConcreteSubject();
	subject->attach( &observer1 ); //将observer1 放进observers
	subject->attach( &observer2 ); //将observer2 放进observers
  
	subject->setState( 10 );//设置subject的subject_state = 10
	subject->notify();//遍历observers,调用ConcreteObserver的update(Subject *subject)函数,将subject的subject_state=10 给 observers里的每一个对象设置 observer_state = 10
  
	std::cout << "Observer 1 state: " << observer1.getState() << std::endl;//Observer 1 state: 10
	std::cout << "Observer 2 state: " << observer2.getState() << std::endl;//Observer 2 state: 10
  
	delete subject;
	return 0;
}

C++ 设计模式----组件协作型模式

模式定义

定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。

——《设计模式》GoF

结构(Structure)

C++ 设计模式----组件协作型模式

要点总结

 使用面向对象的抽象,Observer模式使得我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。

 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。

 观察者自己决定是否需要订阅通知,目标对象对此一无所知。

 Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分。文章来源地址https://www.toymoban.com/news/detail-483361.html

到了这里,关于C++ 设计模式----组件协作型模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【设计模式】Head First 设计模式——抽象工厂模式 C++实现

    设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。 提供一个接口,让该接口负责创建一系列“相关或者相互依赖的对象”,无需指定他们具

    2024年02月10日
    浏览(39)
  • 【设计模式】Head First 设计模式——工厂方法模式 C++实现

    设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。 定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使得一个类的实

    2024年02月10日
    浏览(47)
  • 【设计模式】Head First 设计模式——构建器模式 C++实现

    设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。 ​ 将一个复杂对象的构建与其表示相分离,使得同样的构建过程(稳定)可以创建不同

    2024年02月09日
    浏览(38)
  • 【设计模式】Head First 设计模式——装饰者模式 C++实现

    设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而管理变化。将变化像小兔子一样关到笼子里,让它在笼子里随便跳,而不至于跳出来把你整个房间给污染掉。 动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

    2024年02月10日
    浏览(42)
  • 设计模式:命令模式(C++实现)

    命令模式(Command Pattern)是一种行为设计模式,它将请求封装成一个对象,从而使您可以使用不同的请求对客户端进行参数化。这使得客户端可以独立于具体的请求和接收者对请求进行操作。 以下是一个简单的C++命令模式的示例: 在上述示例中,Command是命令的基类,定义了

    2024年02月07日
    浏览(38)
  • C++ 设计模式之外观模式

    【声明】本题目来源于卡码网(题目页面 (kamacoder.com)) 【提示:如果不想看文字介绍,可以直接跳转到C++编码部分】 【简介】什么是外观模式         外观模式 Facade Pattern , 也被称为“⻔⾯模式”,是⼀种 结构型设计模式 ,外观模式定义了⼀个⾼层接⼝,这个接⼝使得

    2024年01月17日
    浏览(39)
  • C++ 设计模式之策略模式

    【声明】本题目来源于卡码网(题目页面 (kamacoder.com)) 【提示:如果不想看文字介绍,可以直接跳转到C++编码部分】 【设计模式大纲】 【简介】什么是策略模式 (第14种模式)         策略模式是⼀种 ⾏为型设计模式 ,它定义了⼀系列算法(这些算法完成的是相同的⼯作

    2024年01月17日
    浏览(38)
  • C++ 设计模式之组合模式

    【声明】本题目来源于卡码网(题目页面 (kamacoder.com)) 【提示:如果不想看文字介绍,可以直接跳转到C++编码部分】 【简介】什么是组合模式         组合模式是⼀种 结构型设计模式 ,它将对象组合成树状结构来表示“部分-整体”的层次关系。组合模式使得客户端可

    2024年01月18日
    浏览(33)
  • 【C++】设计模式-单例模式

    目录 一、单例模式 单例模式的三个要点 针对上述三要点的解决方案 常用的两类单例模式  二、懒汉模式实现 1.基本实现 2.锁+静态成员析构单例 3.双层检查锁定优化 4.双层检查锁定+智能指针 三、饿汉模式实现 1.基础实现 2.嵌套内部类解决内存泄漏 3.智能指针解决内存泄漏

    2024年02月16日
    浏览(38)
  • 设计模式之模板模式(C++)

    作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处        模板模式是一种行为型的软件设计模式,在父类中定义了一个模板算法,只实现模板中的公共部分,将可变部分放在子类中实现,不同的子类对同一模板有不同的

    2023年04月10日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包