设计模式——行为型模式(一)

行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配

行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。

行为型模式分为:

  • 模板方法模式
  • 策略模式
  • 命令模式
  • 职责链模式
  • 状态模式
  • 观察者模式
  • 中介者模式
  • 迭代器模式
  • 访问者模式
  • 备忘录模式
  • 解释器模式

以上 11 种行为型模式,除了模板方法模式和解释器模式是类行为型模式,其他的全部属于对象行为型模式。

6.1 模板方法模式

6.1.1 概述

在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。

例如,去银行办理业务一般要经过以下4个流程:取号、排队、办理具体业务、对银行工作人员进行评分等,其中取号、排队和对银行工作人员进行评分的业务对每个客户是一样的,可以在父类中实现,但是办理具体业务却因人而异,它可能是存款、取款或者转账等,可以延迟到子类中实现。

定义:

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

6.1.2 结构

模板方法(Template Method)模式包含以下主要角色:

  • 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。

    • 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。

    • 基本方法:是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:

      • 抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。

      • 具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。

      • 钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。

        一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。

  • 具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。

6.1.3 案例实现

【例】炒菜

炒菜的步骤是固定的,分为倒油、热油、倒蔬菜、倒调料品、翻炒等步骤。现通过模板方法模式来用代码模拟。类图如下:

代码如下:

abstract class AbstractClass {//模板方法,为防止恶意操作,一般模板方法都加上 final 关键词。public final void cookProcess() {//第一步:倒油this.pourOil();//第二步:热油this.heatOil();//第三步:倒蔬菜this.pourVegetable();//第四步:倒调味料this.pourSauce();//第五步:翻炒this.fry();}public void pourOil() {System.out.println("倒油");}//第二步:热油是一样的,所以直接实现public void heatOil() {System.out.println("热油");}//第三步:倒蔬菜是不一样的(一个下包菜,一个是下菜心)public abstract void pourVegetable();//第四步:倒调味料是不一样public abstract void pourSauce();//第五步:翻炒是一样的,所以直接实现public void fry(){System.out.println("炒啊炒啊炒到熟啊");}
}
class ConcreteClass_BaoCai extends AbstractClass {@Overridepublic void pourVegetable() {System.out.println("下锅的蔬菜是包菜");}@Overridepublic void pourSauce() {System.out.println("下锅的酱料是辣椒");}
}
class ConcreteClass_CaiXin extends AbstractClass {@Overridepublic void pourVegetable() {System.out.println("下锅的蔬菜是菜心");}@Overridepublic void pourSauce() {System.out.println("下锅的酱料是蒜蓉");}
}
public class Client {public static void main(String[] args) {//炒手撕包菜ConcreteClass_BaoCai baoCai = new ConcreteClass_BaoCai();baoCai.cookProcess();//炒蒜蓉菜心ConcreteClass_CaiXin caiXin = new ConcreteClass_CaiXin();caiXin.cookProcess();}
}

倒油
热油
下锅的蔬菜是包菜
下锅的酱料是辣椒
炒啊炒啊炒到熟啊
倒油
热油
下锅的蔬菜是菜心
下锅的酱料是蒜蓉
炒啊炒啊炒到熟啊

6.1.3 优缺点

优点:

  • 提高代码复用性

    将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中。

  • 实现了反向控制

    通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制 ,并符合“开闭原则”。

缺点:

  • 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象。
  • 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度

6.1.4 适用场景

  • 算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现。
  • 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制

6.2 策略模式

6.2.1 概述

先看下面的图片,我们去旅游选择出行模式有很多种,可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。

作为一个程序猿,开发需要选择一款开发工具,当然可以进行代码开发的工具有很多,可以选择Idea进行开发,也可以使用eclipse进行开发,也可以使用其他的一些开发工具。

定义:

该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

6.2.2 结构

策略模式的主要角色如下:

  • 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
  • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
  • 环境(Context)类:持有一个策略类的引用,最终给客户端调用。

6.2.3 案例实现

【例】促销活动

一家百货公司在定年度的促销活动。针对不同的节日(春节、中秋节、圣诞节)推出不同的促销活动,由促销员将促销活动展示给客户。类图如下:

//抽象策略类
interface Strategy {void show();
}
//具体策略类,为春节准备的促销活动A
class StrategyA implements Strategy {public void show() {System.out.println("买一送一");}
}
//为中秋准备的促销活动B
class StrategyB implements Strategy {public void show() {System.out.println("满200元减50元");}
}
//为圣诞准备的促销活动C
class StrategyC implements Strategy {public void show() {System.out.println("满1000元加一元换购任意200元以下商品");}
}
//环境类
class SalesMan {//持有抽象策略角色的引用private Strategy strategy;public SalesMan(Strategy strategy) {this.strategy = strategy;}//向客户展示促销活动public void salesManShow() {strategy.show();}
}
class Test {public static void main(String[] args) {Strategy strategy = new StrategyB();SalesMan salesMan = new SalesMan(strategy);salesMan.salesManShow();}
}

6.2.4 优缺点

1,优点:

  • 策略类之间可以自由切换

    由于策略类都实现同一个接口,所以使它们之间可以自由切换

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/214139.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Adobe的组织工具程序Bridge 2024 版本下载与安装

目录 前言一、Bridge 2024安装二、使用配置总结 前言 Adobe Bridge是由 Adobe 公司开发的一款用于管理和组织创意资产的工具。它是Adobe Creative Cloud 套件的一部分,为设计师、摄影师和其他创意专业人员提供了一个集中管理和浏览其多媒体文件的平台。注&#xff…

Unity UGUI图片锯齿严重怎么解决

在开发的时候,发现图片锯齿严重,打包到移动端或者在编辑器都这样,如下图 原因: 查了一些资料,找到了原因如下:关于为什么会发生这种情况:看起来你的源资源比你在屏幕上显示的大小大得多。所以当…

基于Vue+SpringBoot的个人健康管理系统

项目编号: S 040 ,文末获取源码。 \color{red}{项目编号:S040,文末获取源码。} 项目编号:S040,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 健康档案模块2.2 体检档案模块2.3 健…

软件设计不是CRUD(6):低耦合模块设计实战——组织机构模块(上)

组织机构功能是应用系统中常见的业务功能之一,但是不同性质、不同行业背景、不同使用场景的应用系统对组织机构功能的要求可能完全不一样。所以使用这样的功能对低耦合模块设计进行示例性的讲解是比较具有代表性的。在后续的几篇文章中,我们会首先进行示…

系列四、编程式事务

一、概述 编程式事务是指程序员手动的在业务代码中控制事务执行的流程&#xff0c;业务方法正常执行提交事务&#xff0c;业务方法执行过程中出现异常则回滚事务。 二、编程式事务环境搭建 2.1、项目概览 2.2、pom.xml <dependencies><!--spring基本依赖--><d…

csrf漏洞修复

漏洞说明&#xff1a;通过篡改请求头中的Referer值依旧能够访问到接口。 通过http请求头里面的Referer随意访问接口 通过下面两个代码类程序来实现你的程序不会被攻击&#xff0c;里面有两个实体&#xff0c;如果你感觉这个程序对你有用&#xff0c;联系我&#xff0c;我私发…

PyQt基础_004_ 按钮类控件QPushButton以及自定义按钮控件

Qpushbutton基本操作 1.热键 2.按钮加图标 3.按钮事件等 import sys from PyQt5.QtCore import * from PyQt5.QtGui import * from PyQt5.QtWidgets import *class Form(QDialog):def __init__(self, parentNone):super(Form, self).__init__(parent)layout QVBoxLayout()se…

云安全之盾:ZStack 云主机安全防护解决方案全方位保护云环境

随着云计算的蓬勃发展&#xff0c;网络威胁愈发复杂&#xff0c;涵盖了从勒索病毒到APT攻击的各种威胁类型。在这一风云变幻的网络安全环境下&#xff0c;云主机安全不再仅仅是一个选项&#xff0c;它是信息系统安全的核心要素。云轴科技ZStack 云主机安全防护解决方案是为了满…

局域网协议:动态主机配置协议(Dynamic Host Configuration Protocol,DHCP)

在局域网络中&#xff0c;DHCP协议通过自动化和简化网络配置过程&#xff0c;提高网络的可管理性和灵活性&#xff0c;使得设备可以更轻松地连接到网络并获得所需的网络配置信息。 文章目录 What is DHCP?DHCP的组成1. DHCP客户端2. DHCP服务器&#xff1a;3. 中继代理&#…

OpenAI研发神秘“Q*”模型:科学家认输,AI赢了人类关键一战

图片来源&#xff1a;视觉中国 作者丨叶蓁 编辑丨康晓 出品丨深网腾讯新闻小满工作室 在山姆奥特曼&#xff08;Sam Altman&#xff09;被OpenAI前董事会突然罢免之前&#xff0c;数位研究人员向董事会发送了一封信&#xff0c;警告称他们发现了一种能够威胁到人类的强大人工…

Jenkins Ansible 参数构建

首先在Jenkins中创建自由项目 在web端配置完成后在另一台机子上下载nginx 在gitlab端创建项目并创建文件配置代码 在有Jenkins的机器上下载Ansible [rootslave1 ~]# yum -y install epel-release [rootslave1 ~]# yum -y install ansible再进入下载nginx机器中克隆gitlab项目…

【linux】服务器CPU占用50%,top/htop/ps却看不到异常进程?使用unhide可以查看!

问题描述 htop发现前32个核全被占满了&#xff0c;但是却找不到对应进程号 查杀 安装unhide查看隐藏进程 apt-get install unhideunhide使用 unhide proc果然发现了隐藏进程 治标&#xff1a;杀死隐藏进程 kill -9 [pid]这么多pid号&#xff0c;我这边杀了其中一个&am…