Template 模式和Strategy 模式

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 17:12   1670   0

应用场景:在面向对象系统的分析与设计过程中经常会遇到这样一种情况:对于某一个业务逻辑(算法实现) 在不同的对象中有不同的细节实现,但是逻辑(算法)的框架(或通用的应用算法)是相同的。 Template 提供了这种情况的一个实现框架。

Template模式是采用继承的方式作为强制约束实现这一点:将逻辑(算法)框架放在抽象基类中, 并定义好细节的接口,子类中实现细节。

Strategy 模式解决的是和 Template 模式类似的问题;Strategy 模式是将逻辑(算法)封装到一个类中,并采取组合(委托)的方式解决这个问题。

  • Template模式:

实现:

  1. 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
  1. 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...PrimitiveOperation1"<<endl;
}
void ConcreteClass1::PrimitiveOperation2()
{
    cout<<"ConcreteClass1...PrimitiveOperation2"<<endl;
}
ConcreteClass2::ConcreteClass2(){}
ConcreteClass2::~ConcreteClass2(){}
void ConcreteClass2::PrimitiveOperation1()
{
    cout<<"ConcreteClass2...PrimitiveOperation1"<<endl;
}
void ConcreteClass2::PrimitiveOperation2()
{
    cout<<"ConcreteClass2...PrimitiveOperation2"<<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;
}

总结:

(1)Template 模式是很简单模式,但是也应用很广的模式。如上面的分析和实现中阐明的Template 是采用继承的方式实现算法的异构,其关键点就是将通用算法封装在抽象基类中,并将不同的算法细节放到子类中实现。
(2)Template 模式获得一种反向控制结构效果, 这也是面向对象系统的分析和设计中一个原则 DIP(依赖倒置: Dependency Inversion Principles)。 其含义就是父类调用子类的操作(高层模块调用低层模块的操作),低层模块实现高层模块声明的接口。这样控制权在父类(高层模块),低层模块反而要依赖高层模块。
(3)不足:基于继 承 的 强 制 性 约 束 关 系 , 我 们 可 以 看 到 对 于ConcreteClass 类中的实现的原语方法 Primitive1(),是不能被别的类复用。Template 模式暴露的问题也正是继承所固有的问题, Strategy 模式则通过组合(委托)来达到和 Template 模式类似的效果, 其代价就是空间和时间上的代价。

  • Strategy 模式

Strategy 模式将逻辑(算法) 封装到一个类( Context)里面, 通过组合的方式将具体算法的实现在组合对象中实现, 再通过委托的方式将抽象接口的实现委托给组合对象实现。


将算法的逻辑抽象接口( DoAction)封装到一个类中( Context),再通过委托的方式将具体的算法实现委托给具体的 Strategy 类来实现( ConcreteStrategeA类)。

实现:

1.Strategy.h

#ifndef _STRATEGY_H_
#define _STRATEGY_H_
class Strategy
{
  public:
   Strategy();
   virtual ~Strategy();
   virtual void AlgrithmInterface() = 0;
};
class ConcreteStrategyA:public Strategy
{
  public:
   ConcreteStrategyA();
   virtual ~ConcreteStrategyA();
   void AlgrithmInterface();
};
class ConcreteStrategyB:public Strategy
{
  public:
   ConcreteStrategyB();
   virtual ~ConcreteStrategyB();
   void AlgrithmInterface();
};

#endif

2.Strategy.cpp

#include "Strategy.h"
#include <iostream>
using namespace std;
Strategy::Strategy(){}
Strategy::~Strategy()
{
    cout<<"~Strategy....."<<endl;
}
void Strategy::AlgrithmInterface()
{}
ConcreteStrategyA::ConcreteStrategyA()
{}
ConcreteStrategyA::~ConcreteStrategyA()
{
    cout<<"~ConcreteStrategyA....."<<endl;
}
void ConcreteStrategyA::AlgrithmInterface()
{
    cout<<"test ConcreteStrategyA....."<<endl;
}
ConcreteStrategyB::ConcreteStrategyB()
{}
ConcreteStrategyB::~ConcreteStrategyB()
{
    cout<<"~ConcreteStrategyB....."<<endl;
}
void ConcreteStrategyB::AlgrithmInterface()
{
    cout<<"test ConcreteStrategyB....."<<endl;
}

3.Context.h

#ifndef _CONTEXT_H_
#define _CONTEXT_H_
class Strategy;
/**
 *这个类是 Strategy 模式的关键,也是 Strategy 模式和 Template 模式的根本区别所在。
 *Strategy 通过“组合”(委托) 方式实现算法(实现) 的异构,而 Template 模式则采取的是继承的方式
 *这两个模式的区别也是继承和组合两种实现接口重用的方式的区别
**/
class Context
{
  public:
    Context(Strategy* stg);
    ~Context();
    void DoAction();
  private:
    Strategy* _stg;
};
#endif

4.Context.cpp

//Client.c
//Context.cpp

#include "Context.h"
#include "Strategy.h"
#include <iostream>
using namespace std;
Context::Context(Strategy* stg)
{
  _stg = stg;
}
Context::~Context()
{
  if (!_stg)
  delete _stg;
}
void Context::DoAction()
{
   _stg->AlgrithmInterface();
}

5.main.cpp

#include "Context.h"
#include "Strategy.h"
#include <iostream>
using namespace std;
int main(int argc,char* argv[])
{
  Strategy* ps = new ConcreteStrategyA();
  Context* pc = new Context(ps);
  pc->DoAction();
  if (NULL != pc)
  delete pc;
  return 0;
}

总结:

(1)Strategy 模式和 Template 模式实际是实现一个抽象接口的两种方式: 继承和组合之间的区别。 要实现一个抽象接口, 继承是一种方式: 我们将抽象接口声明在基类中, 将具体的实现放在具体子类中。 组合(委托) 是另外一种方式: 我们将接口的实现放在被组合对象中,将抽象接口放在组合类中。

(2)继承方式:易于修改和扩展那些实现(类中具体的操作函数),但是

破坏力封装的特性,父类的实现细节暴露给子类;

父类发生改变,所有子类都要改变;

父类继承来的实现--------------------------静多态(编译时期确定)

(3)组合方式:封装性好,内部细节外部不可见;组合对象和非组合对象之间依赖性小;可以在运行期间动态定义实现(通过抽象基类的指针)

系统中对象过多;

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP