GeekBand C++ C++设计模式 第八周笔记

  课程上的C++模式分类太细,整理起来比较繁琐。这次通过最近看的一本《设计模式精解-GoF 23 种设计模式解析》来写笔记。因为经典设计模式种类太多,一一列举实在过于冗长。所以设计模式的两周笔记,第一周通过创建型,结构型和行为模式三个大类,每一类里系统整理一个设计模式作为例子。第二周来说设计模式的体验与思考。

  设计模式对于面对像系统的设计和开发的作用好比数据结构于面向过程开发的作用一般重要。面向对象西永的分析和设计实际上追求的就是两点,一是高内聚(Cohesion),二是低耦合(Coupling)。

  创建型模式:Factory模式

  在面向对象系统设计中经常遇到两类问题。1,为了提高内聚(Cohesion)和松耦合(Coupling),经常会抽象出一些类的公共接口以形成抽象基类或者接口。这样可以通过声明一个指向基类的指针来指向实际的子类实现,达到了多态的目的。2.还有一种情况就是在父类中并不知道具体要实例化哪一个具体的子类。这里的意思为:假设我们在类A中要使用到类B,B是一个抽象父类,在A中并不知道具体要实例化那一个B的子类,但是在类A的子类D中是可以知道的。在A中我们没有办法直接使用类似于new ×××的语句,因为根本就不知道×××是什么。由此两个问题引出了Factory模式的两个最重要的功能-----定义创建对象的接口,封装了对象的创建。以及使具体化类的工作延迟到了子类中。

  通常使用Factory模式来解决这两个问题。在第一个问题中,经常就是声明一个创建对象的接口,并封装了对象的创建过程。Factory这里类似于一个真正意义上的工厂(生产对象)。在第二个问题中,需要提供一个对象创建对象的接口,并在子类中提供其具体实现(因为只有在子类中可以决定到底实例化哪一个类)。

  第一种情况的Factory的结构示意图如下:


  所以的Factory模式经常在系统开发中用到,但是这并不是Factory模式的最大威力所在(因为这可以通过其他方式解决这个问题)。Factory模式不单是提供了创建对象的接口,其最重要的是延迟了子类的实例化(第二个问题),以下是这种情况的一个Factory的结构示意图:


  上图中关键中Factory模式的应用并不是只是为了封装对象的创建,而是要把对象的创建放到子类中实现:Factory中只是提供了对象创建的接口,其实现将放在Factory的子类ConcreteFactory中进行。

  示例代码:

代码片断1:Product.h //Product.h
#ifndef _PRODUCT_H_ 
#define _PRODUCT_H_
class Product
 { 
public: virtual ~Product() =0;
protected: 
Product();
private:
};
class ConcreteProduct:publicProduct 
{
 public: 
~ConcreteProduct();
ConcreteProduct(); 
protected:
private:
};
#endif //~_PRODUCT_H_

代码片断2:Product.cpp //Product.cpp
#include "Product.h"
#include<iostream> 
using namespace std;
Product::Product() 
{ 
}
Product::~Product()
{
}
ConcreteProduct::ConcreteProduct()
{
 cout<<"ConcreteProduct...."<<endl; 
}
ConcreteProduct::~ConcreteProduct()
{
}

代码片断3:Factory.h //Factory.h
#ifndef _FACTORY_H_ 
#define _FACTORY_H_
class Product;
class Factory 
{ 
public:
 virtual ~Factory() = 0;
 virtual Product* CreateProduct() = 0;
protected: 
Factory();
private:
};
class ConcreteFactory:public Factory 
{ 
public:
~ConcreteFactory();
ConcreteFactory();
Product* CreateProduct();
protected:
private:
};
#endif //~_FACTORY_H_

代码片断4:Factory.cpp 
//Factory.cpp
#include "Product.h"
#include <iostream> 
using namespace std;
Factory::Factory() 
{
}
Factory::~Factory() 
{
}
ConcreteFactory::ConcreteFactory() 
{ 
cout<<"ConcreteFactory....."<<endl; 
}
ConcreteFactory::~ConcreteFactory() 
{
}
Product* ConcreteFactory::CreateProduct() 
{ 
return new ConcreteProduct(); 
}

代码片断5:main.cpp
 //main.cpp
#include "Factory.h" 
#include "Product.h"
#include <iostream> 
using namespace std;
int main(int argc,char* argv[]) 
{ 
Factory* fac = new ConcreteFactory();
Product* p = fac->CreateProduct();
return 0; 
}

  示例代码中给出的是Factory模式解决父类中并不知道具体要实例化哪一个具体的子类的问题,至于为创建对象提供接口问题,可以由Factory中附加相应的创建操作。

  Factory模式在实际开发中应用非常广泛,面向对象的系统经常面临着对象创建问题:要创建的类实在是太多了。而Factory提供的创建对象的接口封装(第一个功能),以及其将类的实例化推迟到子类(第二个功能)都部分地解决了实际问题。

  结构型模式:Bridge

  总结面向对象实际上就两句话:一是松耦合(Coupling),二是高内聚(Cohesion)。面向对象系统追求的目标就是尽可能地提高系统模块内部的内聚(Cohesion)、尽可能降低模块间的耦合(Coupling)。然而这也是面向对象设计过程中最为难把握的部分,如果开发过程中遇到这样的问题:
1)客户给了你一个需求,于是使用一个类来实现(A);
2)客户需求变化,有两个算法实现功能,于是改变设计,我们通过一个抽象的基类,再定义两个具体类实现两个不同的算法(A1和A2);
3)客户又告诉我们说对于不同的操作系统,于是再抽象一个层次,作为一个抽象基类A0,在分别为每个操作系统派生具体类(A00和A01,其中A00表示原来的类A)实现不同操作系统上的客户需求,这样我们就有了一共4个类。
4)可能用户的需求又有变化,比如说又有了一种新的算法。
5)我们陷入了一个需求变化的郁闷当中,也因此带来了类的迅速膨胀。

  Bridge模式则正是解决了这类问题。

  Bridge模式典型的结构图为:


  在Bridge模式的结构图中可以看到,系统被分为两个相对独立的部分,左边是抽象部分,右边是实现部分,这两个部分可以互相独立地进行修改:例如上面问题中的客户需求
变化,当用户需求需要从Abstraction派生一个具体子类时候,并不需要像上面通过继承方式实现时候需要添加子类A1和A2了。另外当上面问题中由于算法添加也只用改变右边实现(添加一个具体化子类),而右边不用在变化,也不用添加具体子类了。

  示例代码:

代码片断1:Abstraction.h
//Abstraction.h
#ifndef _ABSTRACTION_H_ 
#define _ABSTRACTION_H_
class AbstractionImp;
class Abstraction 
{ 
public: virtual ~Abstraction();
virtual void Operation() = 0;
protected: Abstraction();
private:
};
class RefinedAbstraction:public Abstraction 
{ 
public: RefinedAbstraction(AbstractionImp* imp);
~RefinedAbstraction();
void Operation();
protected:
private: 
AbstractionImp* _imp;
};
#endif //~_ABSTRACTION_H_

代码片断2:Abstraction.cpp 
//Abstraction.cpp
#include "Abstraction.h" 
#include "AbstractionImp.h"
#include <iostream> 
using namespace std;
Abstraction::Abstraction() 
{
}
Abstraction::~Abstraction() 
{
}
RefinedAbstraction::RefinedAbstraction(AbstractionImp* imp) 
{ 
_imp = imp; 
}
RefinedAbstraction::~RefinedAbstraction()
{
}
void RefinedAbstraction::Operation() 
{ 
_imp->Operation(); 
}

代码片断3:AbstractionImp.h 
//AbstractionImp.h
#ifndef _ABSTRACTIONIMP_H_ 
#define _ABSTRACTIONIMP_H_
class AbstractionImp 
{
 public: virtual ~AbstractionImp();
virtual void Operation() = 0;
protected:
 AbstractionImp();
private:
};
class ConcreteAbstractionImpA:public AbstractionImp 
{ 
public:
 ConcreteAbstractionImpA();
~ConcreteAbstractionImpA();
virtual void Operation();
protected:
private:
};
class ConcreteAbstractionImpB:public AbstractionImp 
{ 
public:
ConcreteAbstractionImpB();
~ConcreteAbstractionImpB();
virtual void Operation();
protected: private:
};
#endif //~_ABSTRACTIONIMP_H_

代码片断4:AbstractionImp.cpp 
//AbstractionImp.cpp
#include "AbstractionImp.h"
#include <iostream> 
using namespace std;
AbstractionImp::AbstractionImp() 
{
}
AbstractionImp::~AbstractionImp() 
{
}
void AbstractionImp::Operation() 
{ 
cout<<"AbstractionImp....imp..."<<endl; 
}
ConcreteAbstractionImpA::ConcreteAbstractionImpA() 
{
}
ConcreteAbstractionImpA::~ConcreteAbstractionImpA() 
{
}
void ConcreteAbstractionImpA::Operation() 
{ 
cout<<"ConcreteAbstractionImpA...."<<endl; }
ConcreteAbstractionImpB::ConcreteAbstractionImpB() 
{
}
ConcreteAbstractionImpB::~ConcreteAbstractionImpB() 
{
}
void ConcreteAbstractionImpB::Operation() 
{ 
cout<<"ConcreteAbstractionImpB...."<<endl
}

代码片断5:main.cpp 
//main.cpp
#include "Abstraction.h" 
#include "AbstractionImp.h"
#include <iostream> 
using namespace std;
int main(int argc,char* argv[]) 
{ 
AbstractionImp* imp = new ConcreteAbstractionImpA();
Abstraction* abs = new RefinedAbstraction(imp);
abs->Operation(); 
return 0; 
}
  Bridge模式将抽象和实现分别独立实现,在代码中就是Abstraction类和AbstractionImp类。

  Bridge是设计模式中比较复杂和难理解的模式之一,也是开发与设计中经常会用到的模式之一。使用组合(委托)的方式将抽象和实现彻底地解耦,这样的好处是抽象和实现可以分别独立地变化,系统的耦合性也得到了很好的降低。

  行为模式:Template

  在面向对象系统的分析与设计过程中经常会遇到这样一种情况:对于某一个业务逻辑(算法实现)在不同的对象中有不同的细节实现,但是逻辑(算法)的框架(或通用的应用算法)是相同的。Template提供了这种情况的一个实现框架。Template模式是采用继承的方式实现这一点:将逻辑(算法)框架放在抽象基类中,并定义好细节的接口,子类中实现细节。

  Template模式的结构图为:


  Template模式实际上就是利用面向对象中多态的概念实现算法实现细节和高层接口的松耦合。可以看到Template模式采取的是继承方式实现这一点的,由于继承是一种强约束性的条件,因此也给Template模式带来一些许多不方便的地方。

  示例代码:

代码片断1:Template.h
//Template.h
#ifndef _TEMPLATE_H_
#define _TEMPLATE_H_ class AbstractClass
{
public:
virtual ~AbstractClass();
void TemplateMethod();
protected:
virtual void PrimitiveOperation1() = 0;
virtual void PrimitiveOperation2() = 0;
AbstractClass(); 
private:
};
class ConcreteClass1:public AbstractClass
{
public:
ConcreteClass1();
~ConcreteClass1(); 
protected:
void PrimitiveOperation1();
void PrimitiveOperation2(); 
private:
};
class ConcreteClass2:public AbstractClass
{
public:
ConcreteClass2();
~ConcreteClass2(); 
protected:
void PrimitiveOperation1();
void PrimitiveOperation2(); 
private:
};
#endif //~_TEMPLATE_H_

代码片断2:Template.cpp
#include "Template.h" 
#include <iostream>
using namespace std; 
AbstractClass::AbstractClass()
{
} 
AbstractClass::~AbstractClass()
{
} 
void AbstractClass::TemplateMethod()
{
this->PrimitiveOperation1();
this->PrimitiveOperation2();
} 
ConcreteClass1::ConcreteClass1()
{
}
ConcreteClass1::~ConcreteClass1()
{
} 
void ConcreteClass1::PrimitiveOperation1()
{
cout<<"ConcreteClass1...PrimitiveOperat
ion1"<<endl;
} void ConcreteClass1::PrimitiveOperation2()
{
cout<<"ConcreteClass1...PrimitiveOperat
ion2"<<endl;
} 
ConcreteClass2::ConcreteClass2()
{
} 
ConcreteClass2::~ConcreteClass2()
{
} 
void ConcreteClass2::PrimitiveOperation1()
{
cout<<"ConcreteClass2...PrimitiveOperat
ion1"<<endl;
} 
void ConcreteClass2::PrimitiveOperation2()
{
cout<<"ConcreteClass2...PrimitiveOperat
ion2"<<endl;
}

代码片断3:main.cpp
#include "Template.h" 
#include <iostream>
using namespace std; 
int main(int argc,char* argv[])
{
AbstractClass* p1 = new ConcreteClass1();
AbstractClass* p2 = new ConcreteClass2();
p1->TemplateMethod();
p2->TemplateMethod();
return 0;
}
  由于Template模式的实现代码其关键是将通用算法(逻辑)封装起来,而将算法细节让子类实现(多态)。需要注意将原语操作(细节算法)定义未保护(Protected)成员,只供模板方法调用(子类可以)。

  Template模式是很简单模式,但是也应用很广的模式。如上面的分析和实现中阐明的Template是采用继承的方式实现算法的异构,其关键点就是将通用算法封装在抽象基类中,并将不同的算法细节放到子类中实现。Template模式获得一种反向控制结构效果,这也是面向对象系统的分析和设计中一个原则DIP(依赖倒置:Dependency Inversion Principles)。其含义就是父类调用子类的操作(高层模块调用低层模块的操作),低层模块实现高层模块声明的接口。这样控制权在父类(高层模块),低层模块反而要依赖高层模块。 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值