240
ふるさとの雪
不可不趁三十以前立志猛进也。

设计模式(1)——简单工厂模式和策略模式的结合应用

一、前言

  设计,为蓝图,为构建之根本。个人对于设计模式的理解:设计模式是软件开发过程中一些常用pattern的概括总结。这些思想终究是别人实践过程中存在着背景因素的产物,可以用,但不可滥用。

  最近在学习软件设计模式方面的知识,在这里实现每个使用场景记录一下自己的学习过程。

二、功能

  简单工厂模式:是属于工厂模式的一种,它使用一个集中了所有实例(产品)的创建逻辑的工厂类去实例化对象。外界只需要告诉工厂所需生产产品的类型,而无需关注生产的过程。将“类实例化的操作”与“使用对象的操作”分开,让使用者不用知道具体参数就可以实例化出所需要的“产品”类,从而避免了在客户端代码中显式指定,降低类之间的耦合。

  策略模式:策略模式是一种定义一系列算法的方法,从概念上来看,所有这些算法完成的都是相同的工作,只是实现不同,它可以以相同的方式调用所有的算法,减少了各种算法类与使用算法类之间的耦合,其实就是用来封装变化。GOF里关于策略模式的功能描述——“策略模式的Strategy类层次为Context定义了一系列的可供重用的算法或行为。继承有助于析取出这些算法中的公共功能”    “当不同的行为堆砌在同一个类中时,就很难避免使用条件语句来选择合适的行为。将这些行为封装在一个个独立的Strategy类中,可以在使用这些行为的类中消除条件语句”。

三、实例

  以计算二维坐标空间两点间的不同类型距离(欧氏距离、曼哈顿距离和棋盘格距离)为例。

  在基类定义一个抽象接口Calculate,在派生类中实现它。

 1 // 距离计算基类
 2 class DistanceBase
 3 {
 4 public:
 5     virtual ~DistanceBase() = default;
 6 public:
 7     virtual double Calculate(cv::Point2d point1_, cv::Point2d point2_) = 0;
 8 };
 9 
10 // 欧几里得距离计算类
11 class EuclideanDistance : public DistanceBase
12 {
13 public:
14     double Calculate(cv::Point2d point1_, cv::Point2d point2_)
15     {
16         double result = 0.0;
17         result = pow((point1_.x - point2_.x), 2) + pow((point1_.y - point2_.y), 2);
18         result = sqrt(result);
19 
20         return result;
21     }
22 };
23 
24 // 曼哈顿距离计算类
25 class ManhattanDistance : public DistanceBase
26 {
27 public:
28     double Calculate(cv::Point2d point1_, cv::Point2d point2_)
29     {
30         double result = 0.0;
31         result = abs(point1_.x - point2_.x) + abs(point1_.y - point2_.y);
32 
33         return result;
34     }
35 };
36 
37 // 棋盘格距离计算类
38 class ChessboardDistance : public DistanceBase
39 {
40 public:
41     double Calculate(cv::Point2d point1_, cv::Point2d point2_)
42     {
43         double result = 0.0;
44         result = std::max(abs(point1_.x - point2_.x), abs(point1_.y - point2_.y));
45 
46         return result;
47     }
48 };

  工厂类的实现

 1 enum DistanceType
 2 {
 3     EUCLIDEAN = 0,
 4     MANHATTAN = 1,
 5     CHESSBOARD = 2,
 6 };
 7 
 8 
 9 class DistanceFactory
10 {
11 public:
12     static DistanceBase* creatCalculator(DistanceType type)
13     {
14         DistanceBase* p = NULL;
15         switch (type)
16         {
17         case DistanceType::EUCLIDEAN:
18             p = new EuclideanDistance();
19             break;
20         case DistanceType::MANHATTAN:
21             p = new ManhattanDistance();
22             break;
23         case DistanceType::CHESSBOARD:
24             p = new ChessboardDistance();
25             break;
26         default:
27             break;
28         }
29 
30         return p;
31     }
32 };

  Client端代码,根据输入的DistanceType来控制工厂类具体实例化哪个距离计算对象

    DistanceBase* calculator = DistanceFactory::creatCalculator(DistanceType::EUCLIDEAN);
    double result = calculator->Calculate(cv::Point2d(1, 1), cv::Point2d(4, 5));

  

  简单工厂模式的缺点除了违背了开放封闭原则以外,通过以上的Client端代码可以发现,Client需要认识DistanceBase基类和DistanceFactory工厂类两个类,可不可以让其只认识一个类?

  这个时候可以结合策略模式来实现all in one的目的,使计算算法彻底地与客户端分离。代码如下

 1 class DistanceCalculator
 2 {
 3 public:
 4     DistanceCalculator(DistanceType type)
 5     {
 6         distance_ = NULL;
 7 
 8         switch (type)
 9         {
10         case DistanceType::EUCLIDEAN:
11             distance_ = new EuclideanDistance();
12             break;
13         case DistanceType::MANHATTAN:
14             distance_ = new ManhattanDistance();
15             break;
16         case DistanceType::CHESSBOARD:
17             distance_ = new ChessboardDistance();
18             break;
19         default:
20             break;
21         }
22     }
23     
24     double Calculate(cv::Point2d point1_, cv::Point2d point2_)
25     {
26         if (distance_)
27             return distance_->Calculate(point1_, point2_);
28     }
29 
30 private:
31     DistanceBase* distance_;
32 };

  Client端调用

    DistanceCalculator* calculator = new DistanceCalculator(DistanceType::EUCLIDEAN);
    double result = calculator->Calculate(cv::Point2d(1, 1), cv::Point2d(4, 5));

  DistanceBase类为一个抽象策略,而EuclideanDistance、ManhattanDistance和ChessboardDistance类为三个具体策略,将实例化具体策略的的过程转移到DistanceCalculator类中,客户端只需实例DistanceCalculator一个类,使得具体的计算算法与客户端彻底分离。

  鄙人才疏学浅,如有错误还请指出。

 

posted @ 2018-08-08 17:02  _蓑衣客  阅读(734)  评论(0编辑  收藏  举报