热门标签 | HotTags
当前位置:  开发笔记 > 人工智能 > 正文

C#设计模式系列教程-模板方法模式

模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码,子类实现算法的某些细节,有助于算法的扩展。

1. 概述

  定义一个操作中的算法的骨架,而将步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义算法的某些特定步骤。

2. 模式中的角色

  2.1 抽象类(AbstractClass):实现了模板方法,定义了算法的骨架。

  2.2 具体类(ConcreteClass):实现抽象类中的抽象方法,已完成完整的算法。

3. 模式解读

  3.1 模板方法类图

//img.jbzj.com/file_images/article/201606/2016060110441417.png

  3.2 模板方法模式代码实现

 /// 
 /// 抽象类
 /// 
 public abstract class AbstractClass
 {
  // 一些抽象行为,放到子类去实现
  public abstract void PrimitiveOperation1();
  public abstract void PrimitiveOperation2();

  /// 
  /// 模板方法,给出了逻辑的骨架,而逻辑的组成是一些相应的抽象操作,它们推迟到子类去实现。
  /// 
  public void TemplateMethod()
  {
   PrimitiveOperation1();
   PrimitiveOperation2();
   Console.WriteLine("Done the method.");
  }
 }

 /// 
 /// 具体类,实现了抽象类中的特定步骤
 /// 
 public class ConcreteClassA : AbstractClass
 {
  /// 
  /// 与ConcreteClassB中的实现逻辑不同
  /// 
  public override void PrimitiveOperation1()
  {
   Console.WriteLine("Implement operation 1 in Concreate class A.");
  }

  /// 
  /// 与ConcreteClassB中的实现逻辑不同
  /// 
  public override void PrimitiveOperation2()
  {
   Console.WriteLine("Implement operation 2 in Concreate class A.");
  }
 }

 /// 
 /// 具体类,实现了抽象类中的特定步骤
 /// 
 public class ConcreteClassB : AbstractClass
 {
  /// 
  /// 与ConcreteClassA中的实现逻辑不同
  /// 
  public override void PrimitiveOperation1()
  {
   Console.WriteLine("Implement operation 1 in Concreate class B.");
  }

  /// 
  /// 与ConcreteClassA中的实现逻辑不同
  /// 
  public override void PrimitiveOperation2()
  {
   Console.WriteLine("Implement operation 2 in Concreate class B.");
  }
 }

  3.3 客户端代码

 class Program
 {
  static void Main(string[] args)
  {
   // 声明抽象类
   AbstractClass c;

   // 用ConcreteClassA实例化c
   c = new ConcreteClassA();
   c.TemplateMethod();

   // 用ConcreteClassB实例化c
   c = new ConcreteClassB();
   c.TemplateMethod();

   Console.Read();
  }
 }

  运行结果

//img.jbzj.com/file_images/article/201606/2016060110441418.png

5. 模式总结

  5.1 优点

    5.1.1 模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。

    5.1.2 子类实现算法的某些细节,有助于算法的扩展。

    5.1.3 通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”。

  5.2 缺点

    5.2.1 每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。

  5.3 适用场景

    5.1 在某些类的算法中,用了相同的方法,造成代码的重复。

    5.2 控制子类扩展,子类必须遵守算法规则。

6. 模式举例: 用冒泡算法非别对整型数组、浮点数数组、日期数组实现排序。

  6.1 实现类图

//img.jbzj.com/file_images/article/201606/2016060110441419.png

  6.2 实现代码

 /// 
 /// 抽象类,定义冒泡排序的骨架
 /// 
 public abstract class BubbleSorter
 {
  private int operatiOns= 0;
  protected int length = 0;

  /// 
  /// 冒泡排序算法
  /// 
  /// 
  protected int DoSort()
  {
   operatiOns= 0;
   if (length <= 1)
   {
    return operations;
   }

   for (int nextToLast = length - 2; nextToLast >= 0; nextToLast--)
   {
    for (int index = 0; index <= nextToLast; index++)
    {
     if (OutOfOrder(index))
     {
      Swap(index);
     }

     operations++;
    }
   }

   return operations;
  }

  /// 
  /// 留给子类实现的交换位置方法
  /// 
  /// 
  protected abstract void Swap(int index);
  /// 
  /// 留给子类实现的比较方法
  /// 
  /// 
  /// 
  protected abstract bool OutOfOrder(int index);
 }

 /// 
 /// 整型类型的冒泡算法实现
 /// 
 public class IntBubbleSorter:BubbleSorter
 {
  private int[] array = null;

  /// 
  /// 用冒泡算法排序
  /// 
  /// 
  /// 
  public int Sort(int[] theArray)
  {
   array = theArray;
   length = array.Length;
   // 调用冒泡算法
   return DoSort();
  }

  /// 
  /// 实现冒泡算法中的交换操作
  /// 
  /// 
  protected override void Swap(int index)
  {
   int temp = array[index];
   array[index] = array[index + 1];
   array[index + 1] = temp;
  }

  /// 
  /// 实现冒泡算法中的比较操作
  /// 
  /// 
  /// 
  protected override bool OutOfOrder(int index)
  {
   return (array[index] > array[index + 1]);
  }
 }

 /// 
 /// 浮点数类型的冒泡算法
 /// 
 public class FloatBubbleSorter:BubbleSorter
 {
  private float[] array = null;

  /// 
  /// 用冒泡算法排序
  /// 
  /// 
  /// 
  public int Sort(float[] theArray)
  {
   array = theArray;
   length = array.Length;
   // 调用冒泡算法
   return DoSort();
  }

  /// 
  /// 实现冒泡算法中的交换操作
  /// 
  /// 
  protected override void Swap(int index)
  {
   float temp = array[index];
   array[index] = array[index + 1];
   array[index + 1] = temp;
  }

  /// 
  /// 实现冒泡算法中的比较操作
  /// 
  /// 
  /// 
  protected override bool OutOfOrder(int index)
  {
   return (array[index] > array[index + 1]);
  }
 }

  6.3 客户端调用

 class Program
 {
  static void Main(string[] args)
  {

   // 对整型数组排序
   int[] intArray = new int[]{5, 3, 12, 8, 10};
   BubbleSorter.IntBubbleSorter sorter = new BubbleSorter.IntBubbleSorter();
   sorter.Sort(intArray);
   foreach (int item in intArray)
   {
    Console.Write(item+" ");
   }

   Console.WriteLine("");

   // 对浮点数排序
   float[] floatArray = new float[] { 5.0f, 3.0f, 12.0f, 8.0f, 10.0f };
   BubbleSorter.FloatBubbleSorter floatSorter = new BubbleSorter.FloatBubbleSorter();
   floatSorter.Sort(floatArray);
   foreach (float item in floatArray)
   {
    Console.Write(item + " ");
   }

   Console.Read();
  }
 }

  运行结果

//img.jbzj.com/file_images/article/201606/2016060110441520.png

以上就是本文的全部内容,希望能给大家一个参考,也希望大家多多支持。


推荐阅读
  • 计算机网络复习:第五章 网络层控制平面
    本文探讨了网络层的控制平面,包括转发和路由选择的基本原理。转发在数据平面上实现,通过配置路由器中的转发表完成;而路由选择则在控制平面上进行,涉及路由器中路由表的配置与更新。此外,文章还介绍了ICMP协议、两种控制平面的实现方法、路由选择算法及其分类等内容。 ... [详细]
  • 本文将介绍如何使用 Go 语言编写和运行一个简单的“Hello, World!”程序。内容涵盖开发环境配置、代码结构解析及执行步骤。 ... [详细]
  • 题目描述:给定n个半开区间[a, b),要求使用两个互不重叠的记录器,求最多可以记录多少个区间。解决方案采用贪心算法,通过排序和遍历实现最优解。 ... [详细]
  • 深入理解C++中的KMP算法:高效字符串匹配的利器
    本文详细介绍C++中实现KMP算法的方法,探讨其在字符串匹配问题上的优势。通过对比暴力匹配(BF)算法,展示KMP算法如何利用前缀表优化匹配过程,显著提升效率。 ... [详细]
  • 探讨一个显示数字的故障计算器,它支持两种操作:将当前数字乘以2或减去1。本文将详细介绍如何用最少的操作次数将初始值X转换为目标值Y。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • 本文探讨如何设计一个安全的加密和验证算法,确保生成的密码具有高随机性和低重复率,并提供相应的验证机制。 ... [详细]
  • 深入解析:手把手教你构建决策树算法
    本文详细介绍了机器学习中广泛应用的决策树算法,通过天气数据集的实例演示了ID3和CART算法的手动推导过程。文章长度约2000字,建议阅读时间5分钟。 ... [详细]
  • 在金融和会计领域,准确无误地填写票据和结算凭证至关重要。这些文件不仅是支付结算和现金收付的重要依据,还直接关系到交易的安全性和准确性。本文介绍了一种使用C语言实现小写金额转换为大写金额的方法,确保数据的标准化和规范化。 ... [详细]
  • 在给定的数组中,除了一个数字外,其他所有数字都是相同的。任务是找到这个唯一的不同数字。例如,findUniq([1, 1, 1, 2, 1, 1]) 返回 2,findUniq([0, 0, 0.55, 0, 0]) 返回 0.55。 ... [详细]
  • 本文探讨了卷积神经网络(CNN)中感受野的概念及其与锚框(anchor box)的关系。感受野定义了特征图上每个像素点对应的输入图像区域大小,而锚框则是在每个像素中心生成的多个不同尺寸和宽高比的边界框。两者在目标检测任务中起到关键作用。 ... [详细]
  • 网络攻防实战:从HTTP到HTTPS的演变
    本文通过一系列日记记录了从发现漏洞到逐步加强安全措施的过程,探讨了如何应对网络攻击并最终实现全面的安全防护。 ... [详细]
  • 本文深入探讨了Linux系统中网卡绑定(bonding)的七种工作模式。网卡绑定技术通过将多个物理网卡组合成一个逻辑网卡,实现网络冗余、带宽聚合和负载均衡,在生产环境中广泛应用。文章详细介绍了每种模式的特点、适用场景及配置方法。 ... [详细]
  • 本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ... [详细]
  • 深度学习理论解析与理解
    梯度方向指示函数值增加的方向,由各轴方向的偏导数综合而成,其模长表示函数值变化的速率。本文详细探讨了导数、偏导数、梯度等概念,并结合Softmax函数、卷积神经网络(CNN)中的卷积计算、权值共享及池化操作进行了深入分析。 ... [详细]
author-avatar
诚心诚意1997_514
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有