策略模式原来这么简单!

C#策略模式(Strategy Pattern)实例教程 主要介绍了C#策略模式(Strategy Pattern),以一个简单的实例讲述了C#策略模式的实现方法,包括策略模式的用途以及具体实现方法,需要的朋友可以参考下 立即下载

前言

只有光头才能变强

回顾前面:

无论是面试还是个人的提升,设计模式是必学的。今天来讲解策略模式~

一、策略模式介绍

我一次听到策略模式这个词,是在我初学JDBC的时候。不知道大家有没有用过DBUtils这个组件。当时初学跟着视频学习,方立勋老师首先是让我们先自己封装一下JDBC的一些常用的操作(实际上就是模仿DBUtils这个组件)。

当时候的问题是这样的:我们打算封装一下query()查询方法,传入的参数有String sql , Object[] objects(指定SQL语句和对应的参数)。我们想根据不同的业务返回不同的值。

  • 比如说,有的时候我们返回的是一条数据,那我们想将这条数据封装成一个Bean对象
  • 比如说,有的时候我们返回的是多条数据,那我们想将这多条数据封装成一个List<Bean> 集合
  • 比如说,有的时候我们返回的是xxxx数据,那我们想将这多条数据封装成一个Map<Bean> 集合
  • …等等等

当时解决方案是这样的:

  • 先定义一个接口:ResultSetHandler(调用者想要对结果集进行什么操作,只要实现这个接口即可)
    • 这个接口定义了行为。Object hanlder(ResultSet resultSet);
  • 然后实现上面的接口,比如我们要封装成一个Bean对象,就是public class BeanHandler implements ResultSetHandler
  • 调用的时候,实际上就是query()查询方法多一个参数query(String sql, Object[] objects, ResultSetHandler rsh)。调用者想要返回什么类型,只要传入相对应的ResultSetHandler实现类就是了。

代码如下:


	query方法:

    //这个方法的返回值是任意类型的,所以定义为Object。
    public static Object query(String sql, Object[] objects, ResultSetHandler rsh) {

        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;

        try {
            connection = getConnection();
            preparedStatement = connection.prepareStatement(sql);

            //根据传递进来的参数,设置SQL占位符的值
            if (objects != null) {
                for (int i = 0; i < objects.length; i++) {
                    preparedStatement.setObject(i + 1, objects[i]);
                }
            }


            resultSet = preparedStatement.executeQuery();

            //调用调用者传递进来实现类的方法,对结果集进行操作
            return rsh.hanlder(resultSet);
    }

	接口:

	/*
    * 定义对结果集操作的接口,调用者想要对结果集进行什么操作,只要实现这个接口即可
    * */
    public interface ResultSetHandler {
         Object hanlder(ResultSet resultSet);
    
    }

	接口实现类(Example):

	//接口实现类,对结果集封装成一个Bean对象
	public class BeanHandler implements ResultSetHandler {
	
	
	    //要封装成一个Bean对象,首先要知道Bean是什么,这个也是调用者传递进来的。
	    private Class clazz;
	
	    public BeanHandler(Class clazz) {
	        this.clazz = clazz;
	    }
	
	    @Override
	    public Object hanlder(ResultSet resultSet) {
	
	        try {
	
	            //创建传进对象的实例化
	            Object bean = clazz.newInstance();
	
	            if (resultSet.next()) {
	
	                //拿到结果集元数据
	                ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
	
	                for (int i = 0; i < resultSetMetaData.getColumnCount(); i++) {
	
	                    //获取到每列的列名
	                    String columnName = resultSetMetaData.getColumnName(i+1);
	
	                    //获取到每列的数据
	                    String columnData = resultSet.getString(i+1);
	
	                    //设置Bean属性
	                    Field field = clazz.getDeclaredField(columnName);
	                    field.setAccessible(true);
	                    field.set(bean,columnData);
	                }
	
	                //返回Bean对象
	                return bean;
	            }

这就是策略模式??就这??这不是多态的使用吗??

1.1策略模式讲解

《设计模式之禅》:

定义一组算法,将每个算法都封装起来,并且使他们之间可以互换

策略模式的类图是这样的:

策略模式通用类图

策略的接口和具体的实现应该很好理解:

  • 策略的接口相当于我们上面所讲的ResultSetHandler接口(定义了策略的行为)
  • 具体的实现相当于我们上面所讲的BeanHandler实现(接口的具体实现)
    • 具体的实现一般还会有几个,比如可能还有ListBeanHandler、MapBeanHandler等等

令人想不明白的可能是:策略模式还有一个Context上下文对象。这对象是用来干什么的呢?

《设计模式之禅》:

Context叫做上下文角色,起承上启下封装作用,屏蔽高层模块对策略、算法的直接访问,封装可能存在的变化。

在知乎上也有类似的问题(为什么不直接调用,而要通过Person?):

知乎问题

说白了,通过Person来调用更符合面向对象(屏蔽了直接对具体实现的访问)。

首先要明白一个道理,就是——到底是 “人” 旅游,还是火车、汽车、自行车、飞机这些交通工具旅游?

如果没有上下文的话,客户端就必须直接和具体的策略实现进行交互了,尤其是需要提供一些公共功能或者是存储一些状态的时候,会大大增加客户端使用的难度;引入上下文之后,这部分工作可以由上下文来完成,客户端只需要和上下文进行交互就可以了。这样可以让策略模式更具有整体性,客户端也更加的简单

具体的链接:

所以我们再说回上文的通用类图,我们就可以这样看了:

DBUtils策略模式类图

1.2策略模式例子

现在3y拥有一个公众号,名称叫做Java3y。3y想要这让更多的人认识到Java3y这个公众号。所以每天都在想怎么涨粉(hahah

于是3y就开始想办法了(操碎了心),同时3y在这一段时间下来发现涨粉的方式有很多。为了方便,定义一个通用的接口方便来管理和使用呗。

接口:


/**
 * 增加粉丝策略的接口(Strategy)
 */
interface IncreaseFansStrategy {

    void action();
}

涨粉的具体措施,比如说,请水军:


/**
 * 请水军(ConcreteStrategy)
 */
public class WaterArmy implements IncreaseFansStrategy {
    
    @Override
    public void action() {
        System.out.println("3y牛逼,我要给你点赞、转发、加鸡腿!");
    }
}

涨粉的具体措施,比如说,认真写原创:


/**
 * 认真写原创(ConcreteStrategy)
 */
public class OriginalArticle implements IncreaseFansStrategy{

    @Override
    public void action() {
        System.out.println("3y认真写原创,最新一篇文章:《策略模式,就这?》");

    }
}

3y还想到了很多涨粉的方法,比如说送书活动啊、商业互吹啊等等等…(这里就不细说了)

说到底,无论是哪种涨粉方法,都是通过3y去执行的。


/**
 * 3y(Context)
 */
public class Java3y {

    private IncreaseFansStrategy strategy ;

    public Java3y(IncreaseFansStrategy strategy) {
        this.strategy = strategy;
    }

    // 3y要发文章了(买水军了、送书了、写知乎引流了...)。
    // 具体执行哪个,看3y选哪个
    public void exec() {
        strategy.action();
    }
}

所以啊,每当到了发推文的时候,3y就可以挑用哪种方式涨粉了:

public class Main {

    public static void main(String[] args) {

        // 今天2018年12月24日
        Java3y java3y = new Java3y(new WaterArmy());
        java3y.exec();

        // 明天2018年12月25日
        Java3y java4y = new Java3y(new OriginalArticle());
        java4y.exec();
        
        // ......
    }
}

执行结果:

执行结果

1.3策略模式优缺点

优点:

  • 算法可以自由切换
    • 改一下策略很方便
  • 扩展性良好
    • 增加一个策略,就多增加一个类就好了。

缺点:

  • 策略类的数量增多
    • 每一个策略都是一个类,复用的可能性很小、类数量增多
  • 所有的策略类都需要对外暴露
    • 上层模块必须知道有哪些策略,然后才能决定使用哪一个策略

调用方必须要知道有哪些策略

1.4JDK的策略模式应用

不知道大家还能不能想起ThreadPoolExecutor(线程池):线程池你真不来了解一下吗?

学习ThreadPoolExecutor(线程池)就肯定要知道它的构造方法每个参数的意义:


    /**
     * Handler called when saturated or shutdown in execute.
     */
    private volatile RejectedExecutionHandler handler;

	public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        //....
        this.handler = handler;
    }

    /**
     * Invokes the rejected execution handler for the given command.
     * Package-protected for use by ScheduledThreadPoolExecutor.
     */
    final void reject(Runnable command) {
        handler.rejectedExecution(command, this);
    }

其中我们可以找到RejectedExecutionHandler,这个参数代表的是拒绝策略(有四种具体的实现:直接抛出异常、使用调用者的线程来处理、直接丢掉这个任务、丢掉最老的任务)

其实这就是策略模式的体现了。

最后

看完会不会觉得策略模式特别简单呀?就一个算法接口、多个算法实现、一个Context来包装一下,就完事了。

推荐阅读和参考资料:

乐于分享和输出干货的Java技术公众号:Java3y。

帅的人都关注了

文章的目录导航:

DFT实战:如何用Synopsys工具搞定多时钟域Scan Chain设计(附避坑指南) 本文详细解析了使用Synopsys DFT Compiler工具链实现多时钟域Scan Chain设计的全流程,包括时钟混合策略、跨时钟域平衡技巧和实战脚本剖析。通过量产验证的工程实践方案,帮助DFT工程师有效解决复杂SoC设计中的Scan Chain挑战,提升测试效率和质量。 阅读详情

相关推荐

基于MediaPipe的智能俯卧撑计数与姿势矫正系统

在现代健身和体能训练中,俯卧撑是最基础也是最有效的自重训练动作之一。然而,许多人在进行俯卧撑训练时常常存在姿势不正确、计数不准确等问题。本文将介绍如何利用计算机视觉和姿态估计技术,开发一个智能的俯卧撑计数与姿势矫正系统。

qq_36224726的博客 916

策略模式原来就这么简单!

前言只有光头才能变强回顾前面:给女朋友讲解什么是代理模式包装模式就是这么简单啦单例模式你会几种写法?工厂模式理解了没有?无论是面试还是个人的提升,设计模式是必学的。今天来...

3y 558

esp32 python开发环境搭建_eclipse esp32开发环境搭建

安装方法基本是按照官网提供的方法来操作https://github.com/espressif/idf-eclipse-plugin#GettingStarted但是官网的方法安装之后还是不能编译成功的,第一次编译会出现一下问题问题1:Building in: E:\eclipse-workspace\helloworlk\buildcmake -G Ninja -DCMAKE_TOOLCHAIN...

weixin_39978276的博客 1263

嵌入式GUI LVGL『Tableview选项卡控件』介绍

一. LVGL GUI开关控件的概念 选项卡视图对象可用于组织选项卡中的内容。 二. LVGL GUI开关小部件和样式 Tab 视图对象包含几个部分。主要是 LV_TABVIEW_PART_BG 。它是一个矩形容器,用于容纳 Tab 视 图的其他部分。 在背景上创建了两个重要的真实部分: LV_TABVIEW_PART_BG_SCRL :这是 Page 的可滚动部分。它使选项卡的内容彼此相邻。页面的背景始终是透明的,不能从外部访问。 LV_TABVIEW_PART_TAB_BG :选项卡按钮,它是

朝气蓬勃 6939

ERA5数据驱动WRFV4.4实战:单层嵌套配置与关键报错排查指南

本文详细介绍了使用ERA5再分析数据驱动WRFV4.4模式进行单层嵌套模拟的完整实战流程。内容涵盖从数据精准下载、WPS前处理配置、WRF核心参数设置到高频报错的深度排查与解决方案,旨在帮助初学者在有限服务器资源下,高效完成WRF模拟并规避常见陷阱。

q5r6s7的博客 770

告别代码移植烦恼:STM32CubeMX 6.4.0 + STM32F407ZGT6 + YT8512C PHY芯片的LWIP网络配置全攻略

本文详细介绍了如何使用STM32CubeMX 6.4.0配置STM32F407ZGT6与YT8512C PHY芯片的LWIP网络适配,包括硬件特性解析、STM32CubeMX基础配置、专用驱动适配和LWIP协议栈定制化配置,帮助开发者解决PHY芯片差异导致的网络问题。

weixin_28718793的博客 290

LVGL 8.3 Tabview控件使用Keypad导航

LVGL 8.3 Tabview控件使用Keypad导航

四文鱼Max的博客 2694

荔枝派Lichee Nano全志F1C100s烧录避坑指南:从Fel模式到SPI Flash完整流程

本文详细介绍了荔枝派Lichee Nano基于全志F1C100s芯片的SPI Flash烧录完整流程,从FEL模式进入技巧到定制化sunxi-tools编译,再到分区策略与实战烧录步骤。针对开发者常见的烧录程序问题提供了专业解决方案,帮助用户高效完成嵌入式系统部署。

tea88的博客 788

C#之策略模式

策略模式定义为:定义算法家族,封装每一个算法,并使它们可以替换。策略可以让算法独立于使用它的客户端。 这个模式涉及到三个角色: 环境(Context)角色:持有一个Strategy的引用。 抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。 具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。 案例展示: 在...

lisa丶 1612

影刀RPA之成绩批量查询系统

自动化登录账号,读取数据表中内容去填写信息去查询,并判断多个数据不同的页面去不同的读取查询结果内容,如考生各项信息与各科成绩,总分和查询时间,采集出来到指定的数据表格中,等待时间并依次循环运行。主要功能。

2201_75330891的博客 1084

基于Matlab生成并可视化多架飞机轨迹仿真(附源码)

这使我们可以轻松地对直线和恒定转弯进行建模,并具有额外的自由度,可以在直线段和曲线段之间平滑过渡。同样,空气中的物体会经历重力的影响,遵循抛物线(二次)路径。需要更多的航点来适应这些变化,但是轨迹的其余部分需要更少的点。第三个轨迹,如下所示,代表了一架速度更高的飞机。它由两个恒定的转弯组成,飞机在第二个转弯的中间减速。一旦知道(并设置了)物体穿过空间的物理路径,物体的速度作为行进距离的函数就通过三次埃尔米特插值来确定。在此示例中,学习了内部使用的插值符背后的概念,并展示了如何使用少量航点重现场景。

珞瑜的博客 5464

【C#设计模式】19.策略模式(Strategy Pattern)【行为型】

1.1 动机(Motivate) 在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。如何在运行时根据需要透明地更改对象的算法?将算法与对象本身解耦,从而避免上述问题? 1.2 意图(Intent) 定义一系列算法,把它们一个个封装起来,并且使它们可互相替换。该模式使得算法可独立于使用它的客户而变化。       ——《设计模式》GoF .........

星Yeah 的博客 3687

Kalibr 安装+制作采集的图片和IMU数据生成 .bag 文件 (坑最全,解决方法最简单,最详细哈哈)

方法一、Kalibr标定工具实现 开源代码连接:https://github.com/ethz-asl/kalibr 1.1 创建工作空间 ——下载程序——编译 mkdir -p ~/kalibr_workspace/src cd /kalibr_workspace/src git clone https://github.com/ethz-asl/Kalibr.git cd .. //返回上一级 catkin_make source devel/setup.bash ......

努力努力努力 6939

原来使用 Spring 实现策略模式可以这么简单!

策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法,可以替代代码中大量的 if-else。比如我们生活中的场景:买东西结账可以使用微信支付、支付宝...

武培轩 8462

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

别只知道策略模式+简单工厂,试试更香的策略模式+抽象工厂!

我的相关博文 三种工厂模式详解购优惠 www.fenfaw.cn 策略模式 在GOF的《设计模式:可复用面向对象软件的基础》一书中对策略模式是这样说的: 定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。该模式使得算法可独立于使用它的客户而变化。 策略模式为了适应不同的需求,只把变化点封装了,这个变化点就是实现不同需求的算法,例如加班工资,不同的加班情况,有不同的计算加班工资的方法。 我们不能在程序中将计算工资的算法进行硬编码,而能够自由变化。 这就是策略模式。 ...

nidongla的博客 234

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

上一篇: 三分钟学会门面模式!
下一篇: 三分钟学会《门面模式》
Java3y
Java3y 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 1万+粉丝 509原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值