zoukankan      html  css  js  c++  java
  • 设计模式(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一个类,使得具体的计算算法与客户端彻底分离。

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

  • 相关阅读:
    Mac 删除Openfire
    FMDB使用
    豆瓣restful api 状态和错误码
    豆瓣开放api
    常用文字配色方案
    电商网站参考
    HP后端跨域HEADER头
    PHP统计 图表实现方法
    PHP 全过程教程和测试网
    Ajax技术在购物车中的应用(PHP篇)
  • 原文地址:https://www.cnblogs.com/irvingluo/p/9415381.html
Copyright © 2011-2022 走看看