模板模式和适配器模式

一、模板模式

1、模板模式(Template Method pattern):指定义一个算法的骨架,并允许子类为一个或者多个步骤提供实现。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法的某些步骤。(属于行为型模式)

2、适用场景

  • 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现
  • 各子类中公共的行为被提取出来并集中到一个公共的父类中,从而避免代码重复

3、优点

  • 提高代码的复用性
  • 提高代码的扩展性
  • 符合开闭原则

4、缺点

  • 类数目的增加
  • 间接地增加了系统实现的复杂度
  • 继承关系自身缺点,如果父类添加新的抽象方法,所有子类都要改一遍

5、应用场景举例

比如办理入职流程:填写入职登记表-->打印简历-->复印学历-->复印身份证-->签订劳动合同-->办理工牌-->安排工位。

比如平时炒菜流程:洗锅-->点火--> 热锅-->上油-->下菜-->翻炒-->放调料-->出锅。

再如赵本山问宋丹丹:“如何把大象放进冰箱?”宋丹丹答:“第一步:打开冰箱门,第二步:把大象塞进冰箱,第三步:关闭冰箱门”。赵本山再问:“怎么把长颈鹿放进冰箱?”宋丹丹答:“第一步:打开冰箱门,第二步:把大象拿出来,第三步:把长颈鹿塞进去,第四步:关闭冰箱门”,这些都是模板模式的体现。

例子1:以简单的网校课程创建流程为例:发布预习资料-->在线直播-->提交笔记-->布置作业-->检查作业。

首先定义一个NetworkCourse网课抽象类:

上面代码中有个钩子方法,主要是用来干预执行流程,使得我们控制行为流程更加灵活、更符合实际业务的需求。钩子方法的返回值一般为适合条件分支语句的返回值(如boolean、int等),可根据真实业务场景来决定是否需要用钩子方法。

接下来定义一个JavaCourse课程类:

定义一个BigDataCourse课程类:

客户端测试代码:

运行结果:

例子2:利用模板模式重构JDBC操作业务场景。

定义一个JdbcTemplate模板类,封装所有的JDBC操作。以查询为例,每次查询的表不同,返回的数据结构也不一样。我们针对不同的数据,都要封装成不同的实体对象。而每个实体封装的逻辑都是不一样的,但封装前和封装后的处理流程是不变的,因此可以用模板模式来设计这样的业务场景。 先定义一个约束ORM逻辑的接口RowMapper:

再定义一个封装了所有处理流程的抽象类JdbcTemplate:

定义一个实体类User:

定义一个数据库操作类UserDao:

客户端测试代码:

模板模式在JDK源码中的体现:先看JDK中的AbstractList:

我们看到get()是一个抽象方法,那么它的逻辑就是交给子类来实现,ArrayList就是AbstractList的子类。同理,有AbstractList就有AbstractSet和AbstractMap,有兴趣可自行研究。还有一个每天都在用的HttpServlet,有service()、doGet()和doPost()方法,都是模板方法的抽象实现。

Mybatis框架中的BaseExecutor类,是一个基础的SQL执行类,实现了大部分的SQL执行逻辑,然后把几个方法交给子类定制化完成,源码如下:

如doUpdate()、doQuery()等方法都交由子类来实现,如下类图:

二、适配器模式

1、适配器模式(Adapter Pattern):指将一个类的接口转换成客户期望的另一个接口,使原本接口不兼容的类可以一起工作。(属于结构型设计模式)

2、适用场景

  • 已经存在的类,它的方法和需求不匹配(方法结果相同或相似)的情况
  • 适配器模式不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案(有点亡羊补牢的感觉)

3、优点

  • 能提高类的透明性和复用,现有的类复用但不需要改变
  • 目标类和适配器类解耦,提高程序的扩展性
  • 在很多业务场景中符合开闭原则

4、缺点

  • 适配器编写过程需要全面考虑,可能会增加系统的复杂性
  • 增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱

5、应用场景举例

比如电源插转换头、手机充电转换头、显示器转接头。

例子1:在中国民用电都是220V交流电,但我们手机使用的锂电池使用5V直流电。因此,我们给手机充电时就需要使用电源适配器来进行转换。下面代码还原场景:

定义一个AC220类,表示220V交流电:

定义一个DC5接口,表示5V直流电的标准:

定义一个电源适配器PowerAdapter类:

客户端测试代码:

上面的案例中,通过增加PowerAdapter电源适配器,实现了二者的兼容。

例子2:重构第三方登录自由适配的业务场景。

以前开发的老系统应该都有登录接口, 但随着业务的发展和社会的进步,单纯地依赖用户名密码登录显示不能满足用户需求了。现在,我们大部分系统都已经支持多种登录方式,如QQ登录、微信登录、手机登录等,同时保留用户名密码的登录方式。虽然登录形式丰富了,但登录后的处理逻辑可不必改变,同样是将登录状态保存到session,遵循开闭原则。

首先定义统一的返回结果Result类:

假设老系统的登录逻辑SignInService:

为了遵循开闭原则,老系统的代码我们不去修改。下面开始重构,先定义User类:

定义一个第三方登录新类SignInForThirdService继承原来的逻辑,运行非常稳定的代码我们不去改动:

客户端测试代码:

通过这么一个简单的适配,完成了代码兼容。当然,代码还可以更加优雅,根据不同的登录方式,创建不同的Adapter。

首先,定义一个LoginAdapter接口:

分别实现不同的登录适配,QQ登录LoginForQQAdapter类:

微信登录LoginForWechatAdapter类:

然后定义第三方登录兼容接口IPassportForThird:

实现兼容PassportForThirdAdapter类:

客户端测试代码:

类结构图:

至此,我们在遵循开闭原则的前提下,完整地实现了一个兼容多平台登录的业务场景。适配器模式主要解决的是功能兼容问题,且适配器的实现逻辑并不依赖于接口,我们完全可以将LoginAdapter接口去掉,加上接口只是为了代码规范。上面的代码可以说是策略模式、简单工厂模式和适配器模式的综合运用。

简单看看适配器模式在源码中的应用,SpringMVC的HandlerAdapter类,它也有多个子类:

原文地址:https://www.cnblogs.com/ZekiChen/p/12571428.html

时间: 2024-11-05 22:51:04

模板模式和适配器模式的相关文章

12. 星际争霸之php设计模式--模板模式

题记==============================================================================本php设计模式专辑来源于博客(jymoz.com),现在已经访问不了了,这一系列文章是我找了很久才找到完整的,感谢作者jymoz的辛苦付出哦! 本文地址:http://www.cnblogs.com/davidhhuan/p/4248192.html============================================

模板模式

模板模式:解决某类事情的步骤有些是固定的,有些是会发生变化的,那么这时候我们可以为这类事情提供一个模板代码,从而提高效率. 模板模式的步骤: 1.先写出解决该类事件中的一件的解决方案. 2.分析代码,把会发生变化的代码抽取出来独立成一个方法.把该方法描述成一个抽象的方法. 3.是用final关键字修饰模板方法,防止别人重写你的模板方法. 例子:需求:编写一个计算程序运行时间的模板. 代码示例: 1 abstract class ProgramRuntime 2 { 3 public final

设计模式之 - 模板模式(Template Pattern)

引入:这几天在看一本讲spring源码的书<SPRING技术内幕>里面在讲加载配置文件的时候,可以有不同的加载方式,如根据文件系统目录加载配置文件(FileSystemXmlApplicationContext),类路径加载配置文件(ClassPathXmlApplicationContext),以及根据项目上下文目录(XmlWebApplicationContext)加载配置文件.这个在加载的过程中就使用了模板设计模式,所以就来学习下模板设计模式. 1. 模板设计模式在书中定义:  定义一个

设计模式整理_模板模式

模板模式在父类中定义了一个方法的模板,而子类可以动态的实现模板成分方法,但是模板中的方法顺序无法改变. 父类中的模板方法往往申明为final,用来保证方法不被子类覆盖,因为作为模板,是不可以改变的,但是模板方法内的一系列方法,可以由子类自己静态实现,同时在父类的模板方法中,可以定义钩子(hook)方法.方便子类对于模板方法的优化.下面用两个例子说明. /*没有钩子(hook)的模板方法,此时模板方法无法修改*/ public abstract class Model { public final

行为模式之Template(模板模式)

模板模式定义一系列的操作流程,并将其中的一个或多个操作的实现延迟到子类之中. 我们以牛奶加工过程为例,当然对其做了简化,具体流程如下图: 首先,将加工过程定义成一个抽象类: AbstractMilkProcess package com.design; /**牛奶加工过程 * @author wobendiankun *2015-1-21 下午08:01:57 */ public abstract class AbstractMilkProcess { /** *挤奶 */ protected

设计模式——模板模式(C++实现)

模板模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 模板模式通过把不变的行为搬移到超类,去除子类中的重复代码来体现它的优势. 通过继承和多态来实现. 行为型模式. spp业务框架中的server_task(CServerTask类)就是这么一个东西.非常常用的一个模式. 使用场景: 1.有多个子类共有的方法,且逻辑相同. 2.重要的.复杂的方法,可以考虑作为模板方法. 1 #include <iostream>

设计模式(7)--模板模式

//7.模板模式 //ver1 //考试试卷类 class TestPaper { public: void TestQuestion1(){} void TestQuestion2(){} virtual string Answer1() { return ""; } virtual string Answer2() { return ""; } }; class TestPaperA : public TestPaper { public: void TestQ

模板模式讲解二

一.何为模板 在阎宏博士的<JAVA与模式>一书中开头是这样描述模板方法(Template Method)模式的: 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现.这就是模板方法模式的用意. 二.模式结构设计 父类定义成一个抽象类,有一个具体实现方法,在这个具体实现方法会去调用此抽象类定义的抽象方法,这些抽象方法由子类继承实现,因为

咸蛋系列一●《模板模式构建随机对象生成》2 构思

随机对象生成可以说是随机数生成的一个延伸,在实际使用中,我们可能要生成的不是一个简简单单的数字,而是像数字.大小写字符.中文汉字.算数表达式等. 由于其实现相对简单,取各种随机对象的源码网上也比比皆是,因而貌似也没人做一个通用的.可扩展的随机对象生成. 博主要不是因为闲得蛋疼也是不会想到做这个东西的,好了,言归正传.分析随机对象生成,其要点无外乎三点: 1. 设置随机对象集: 2. 获取一个或多个随机对象: 3. 获取一个或多个不重复随机对象: 在这三点中,后两者算法皆固定,仅设置对象集不同,故