策略模式-实践

news2024/11/22 16:51:38

俗话说:条条大路通罗马。在很多情况下,实现某个目标的途径不止一条,例如我们在外出
旅游时可以选择多种不同的出行方式,如骑自行车、坐汽车、坐火车或者坐飞机,可根据实
际情况(目的地、旅游预算、旅游时间等)来选择一种最适合的出行方式。在制订旅行计划
时,如果目的地较远、时间不多,但不差钱,可以选择坐飞机去旅游;如果目的地虽远、但
假期长、且需控制旅游成本时可以选择坐火车或汽车;如果从健康和环保的角度考虑,而且
有足够的毅力,自行车游或者徒步旅游也是个不错的选择。


在软件开发中,我们也常常会遇到类似的情况,实现某一个功能有多条途径,每一条途径对
应一种算法,此时我们可以使用一种设计模式来实现灵活地选择解决途径,也能够方便地增
加新的解决途径。本章我们将介绍一种为了适应算法灵活性而产生的设计模式——策略模
式。

(1) MovieTicket类的calculate()方法非常庞大,它包含各种打折算法的实现代码,在代码中出现
了较长的if…else…语句,不利于测试和维护。
(2) 增加新的打折算法或者对原有打折算法进行修改时必须修改MovieTicket类的源代码,违反
了“开闭原则”,系统的灵活性和可扩展性较差。
(3) 算法的复用性差,如果在另一个系统(如商场销售管理系统)中需要重用某些打折算法,
只能通过对源代码进行复制粘贴来重用,无法单独重用其中的某个或某些算法(重用较为麻
烦)。

如何解决这三个问题?导致产生这些问题的主要原因在于MovieTicket类职责过重,它将各种
打折算法都定义在一个类中,这既不便于算法的重用,也不便于算法的扩展。因此我们需要
对MovieTicket类进行重构,将原本庞大的MovieTicket类的职责进行分解,将算法的定义和使
用分离,这就是策略模式所要解决的问题,下面将进入策略模式的学习。

策略模式
符合"依赖倒转原则"
策略模式Strategy Pattern:定义一系列算法类,
将每一个算法封装起来,并让他们可以相互替换,
策略模式让算法独立于使用它的客户而变化。
策略模式的主要目的是将算法的定义与使用分开。

  // Helper method to update card data based on tag
    private static void updateCardData(String tagName, byte [] data, Card card) {
        // Update card data based on the tag
        Logs.d(TAG,"dataOut.length: "+data.length);
        String ordata =  tools.hexString(data);
        Logs.d(TAG,tagName + "原始数据 "+ ordata);
        switch (tagName) {
            case eICCardNumber:
                // Skip the first two bytes, the first one is the tag, and the second is the length
                byte[] tagBytes = Arrays.copyOfRange(data, 2, 2 + data[1] & 0xFF);
                String tagString = tools.hexString(tagBytes);
                System.out.println(tagString);
                card.setPan(tagString);
                break;
            case epanSeqNo:
                // 解析Tag
                int tag = data[0] & 0xFF;
                // 解析Length
                int length = data[1] & 0xFF;
                // 获取PAN Sequence Number的值
                byte panSequenceNumber = data[2];
                System.out.println("Tag: " + Integer.toHexString(tag));
                System.out.println("Length: " + length);
                System.out.println("PAN Sequence Number: " + panSequenceNumber);
                card.setPanSeqNo((int)panSequenceNumber);
                break;
            case ecardHolderName:
                byte[] cardHolderName = Arrays.copyOfRange(data, 3, 3 + data[2] & 0xFF);
                String resultString = new String(cardHolderName, StandardCharsets.UTF_8);
                System.out.println(resultString);
                System.out.println("ecardHolderName: " + resultString);
                card.setCardHolderName(resultString);
                break;
            case eserviceCode:
                byte[] serviceCode = Arrays.copyOfRange(data, 3, 3 + data[2] & 0xFF);
                String sserviceCode = tools.hexString(serviceCode);
                card.setServiceCode(sserviceCode);
                break;
            case eissuerCountryCode:
                byte[] issuerCountryCode = Arrays.copyOfRange(data, 3, 3 + data[2] & 0xFF);
                String ssuerCountryCode = tools.hexString(issuerCountryCode);
                Log.d(TAG,"ssuerCountryCode"+ ssuerCountryCode);
                int CountryCode = Integer.parseInt(ssuerCountryCode, 10);
                Log.d(TAG,"CountryCode"+ CountryCode);
                card.setIssuerCountryCode(CountryCode);
                break;
            case elabel:
                byte[] label = Arrays.copyOfRange(data, 2, 2 + data[1] & 0xFF);
                String slabel = new String(label, StandardCharsets.UTF_8);
                System.out.println(slabel);
                card.setLabel(slabel);
                break;
            case ecardExpirationDate:
                byte[] cardExpirationDate = Arrays.copyOfRange(data, 3, 3 + data[2] & 0xFF);
                String scardExpirationDate = tools.hexString(cardExpirationDate);
                Log.d(TAG,"scardExpirationDate"+ scardExpirationDate);
                Date parsedDate = null;    
                SimpleDateFormat sdf = new SimpleDateFormat("MMddyy");
                try {
                    parsedDate = sdf.parse(scardExpirationDate);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                card.setCardExpirationDate(parsedDate);
                break;
            default:
                break;
        }
    }

使用策略模式修改后的代码

public interface CardDataUpdateStrategy {
    void updateCardData(byte[] data, Card card);
}
public class LabelStrategy implements CardDataUpdateStrategy {
    @Override
    public void updateCardData(byte[] data, Card card) {
        byte[] label = Arrays.copyOfRange(data, 2, 2 + data[1] & 0xFF);
        String slabel = new String(label, StandardCharsets.UTF_8);
        System.out.println(slabel);
        card.setLabel(slabel);
    }
}

public class ICCData {

    private static final String TAG = ICCData.class.getSimpleName();
    static  Card card;
    static final private  int expectDataLen = 20;  // 期望TLV返回的长度
    static final String eICCardNumber ="ICCardNumber";
    static final String epanSeqNo ="panSeqNo";
    static final String ecardHolderName ="cardHolderName";
    static final String eserviceCode ="serviceCode";
    static final String eissuerCountryCode ="issuerCountryCode";
    static final String elabel ="label";
    static final String ecardExpirationDate ="cardExpirationDate";

    private static final Map<String, CardDataUpdateStrategy> strategyMap;

    static {
        strategyMap = new HashMap<>();
        strategyMap.put(eICCardNumber, new PANUpdateStrategy());
        strategyMap.put(epanSeqNo, new PanSeqNoUpdateStrategy());
        strategyMap.put(ecardHolderName, new CardHolderNameStrategy());
        strategyMap.put(eserviceCode, new ServiceCodeStrategy());
        strategyMap.put(eissuerCountryCode, new IssuerCountryCodeStrategy());
        strategyMap.put(elabel, new LabelStrategy());
        strategyMap.put(ecardExpirationDate, new ExpirationDateStrategy());
    }

    // 获取 Card 实例的方法
    public static Card getCardInstance() {
        if (card == null) {
            card = new Card();
        }
        return card;
    }

    private static void updateCardData(TagInfo tagInfo, Card card) {
        String ordata = tools.hexString(tagInfo.tag);
        Logs.d(TAG, tagInfo.getTagName() + "原始数据 " + ordata);
        CardDataUpdateStrategy strategy = strategyMap.get(tagInfo.getTagName());
        // Check if a valid strategy is found
        if (strategy != null) {
            strategy.updateCardData(tagInfo.getTag(), card);
        }
    }

    public static Card getICCardNumber() {

        List<TagInfo> tagInfoList = Arrays.asList(
                new TagInfo(new byte[]{(byte) 0x5A}, eICCardNumber),
                new TagInfo(new byte[]{(byte) 0x5F, (byte) 0x34}, epanSeqNo),
                new TagInfo(new byte[]{(byte) 0x5F, (byte) 0x20}, ecardHolderName),
                new TagInfo(new byte[]{(byte) 0x5F, (byte) 0x30}, eserviceCode),
                new TagInfo(new byte[]{(byte) 0x5F, (byte) 0x28}, eissuerCountryCode),
                new TagInfo(new byte[]{(byte) 0x50}, elabel),
                new TagInfo(new byte[]{(byte) 0x5F, (byte) 0x24}, ecardExpirationDate)
        );
        Card card = getCardInstance();
        for (TagInfo tagInfo : tagInfoList) {
            getICCardData(tagInfo, card);
        }
        card.setType(ICC);
        return card;

    }
    public static Card getICCardData(TagInfo tagInfo, Card card) {
        ByteArray dataOut = new ByteArray(expectDataLen);
        int result = EMV_GetTLVDataList(tagInfo.tag, (byte) tagInfo.tag.length, expectDataLen, dataOut);
        switch (result) {
            case EMV_OK:
                tagInfo.tag = Arrays.copyOfRange(dataOut.data, 0, dataOut.length);
                updateCardData(tagInfo, card);
                break;
            case EMV_PARAM_ERR:
                System.out.println("Error: Parameters error (null pointer).");
                break;
            case EMV_DATA_ERR:
                System.out.println("Error: Data error, illegal tags.");
                break;
            case EMV_NO_DATA:
                System.out.println("Error: The tag is not present.");
                break;
            case EMV_OVERFLOW:
                System.out.println("Warning: Data overflow. Actual data cut off to the length of expectDataLen.");
                break;
            default:
                // Handle other return codes as needed
                break;
        }
        return card;
    }

    // 处理卡号数据
    static private String processCardNumber(byte[] cardNumberData) {
        // 在此处实现卡号数据的处理逻辑,例如格式化和解析
        // 返回处理后的卡号字符串
        return new String(cardNumberData);
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux第26步_在虚拟机中安装stm32wrapper4dbg工具

在Ubuntu下编译TF-A 或者 Uboot时&#xff0c;我们需要用到ST公司提供的stm32wrapper4dbg工具。stm32wrapper4dbg工具的源码下载地址为: GitHub - STMicroelectronics/stm32wrapper4dbg 记得我们在前面已经创建过的目录如下&#xff1a; 1&#xff09;、在根目录下&#xf…

螺纹钢负公差轧制中的测径仪应用

1、负公差轧制意义 为了满足生产使用要求&#xff0c;并根据轧制水平&#xff0c;在产品标准冲规定钢材尺寸的波动范围&#xff0c;允许钢材的实际尺寸与公称尺之间有一定的偏差&#xff0c;这个偏差一般称公差&#xff0c;公差分正、负公差&#xff0c;钢材按负公差轧制时&…

TS 36.331 V12.0.0-过程(4)-测量

​本文的内容主要涉及TS 36.331&#xff0c;版本是C00&#xff0c;也就是V12.0.0。

【检索稳定】第三届新能源、储能与电力工程国际学术会议(NESP 2024)

第三届新能源、储能与电力工程国际学术会议&#xff08;NESP 2024&#xff09; 2024 3rd International Conference on New Energy, Energy Storage and Power Engineering (NESP 2024) 近几十年来&#xff0c;全球能源消耗迅速增加&#xff0c;因此寻找和开发性能优良的环保…

试试这个开源神器 55K star! 开箱即用

还记得以前工作上遇到困难&#xff0c;会申请开发大神远程帮忙&#xff0c;那时候用的都是TeamViewer&#xff0c;但是随着TeamViewer的收费&#xff0c;这些都已成为过往。 今天我们推荐的开源项目就是让你可以轻松平替TeamViewer&#xff0c;一款远程桌面神器&#xff0c;本…

Kotlin程序设计(一)基础语法

Kotlin程序设计初级篇 **注意&#xff1a;**在开始学习之前&#xff0c;推荐各位小伙伴有一定的编程语言基础&#xff0c;前置课程&#xff1a;《JavaSE 教程》或《C 语言程序设计》如果没有其他语言的基础&#xff0c;在学习Kotlin时会非常吃力&#xff0c;这门语言语法糖多到…

基于C++的ORM框架sqlpp11入门介绍(附MySQL运行实例)

基本介绍 sqlpp11 是 C 的类型安全的 SQL 模版库。 Sqlpp11的官方下载地址是&#xff0c; GitHub - rbock/sqlpp11: A type safe SQL template library for C 在这里&#xff0c;可以找到官方的详细介绍文档&#xff0c; https://github.com/rbock/sqlpp11/tree/main/docs…

解锁Python库中操作系统级别模块psutil

目录 一、psutil库简介 二、安装psutil库 三、获取系统信息 1、获取CPU信息&#xff1a; 2、获取内存信息&#xff1a; 3、获取磁盘信息&#xff1a; 4、获取网络信息&#xff1a; 四、进程管理 五、系统信息和监控 六、总结 随着Python的普及&#xff0c;越来越多的…

nuxt pm2使用、启动、问题解决方案

pm2简介 pm2是一个进程管理工具,可以用它来管理node进程&#xff0c;并查看node进程的状态&#xff0c;当然也支持性能监控&#xff0c;进程守护&#xff0c;负载均衡等功能&#xff0c;在前端和nodejs的世界中用的很多 pm2安装 安装pm2: $ npm install -g pm2查看pm2的安装…

iPad Pro如何使用SSH远程连接服务器云端编程开发【内网穿透】

文章目录 1. 在iPad下载Code APP2.安装cpolar内网穿透2.1 cpolar 安装2.2 创建TCP隧道 3. iPad远程vscode4. 配置固定TCP端口地址4.1 保留固定TCP地址4.2 配置固定的TCP端口地址4.3 使用固定TCP地址远程vscode 正文开始前给大家推荐个网站&#xff0c;前些天发现了一个巨牛的 …

JavaScript 增加数组中指定元素(5种方法)

、 文章目录 目录 文章目录 前言 一、数组是什么&#xff1f; 二、数组增步骤 总结 前言 在现代的Web开发中&#xff0c;JavaScript是一种不可或缺的编程语言。它具有强大的功能和灵活的语法&#xff0c;使得开发人员能够轻松地处理各种任务。其中&#xff0c;处理数组是JavaS…

基于JavaWeb+BS架构+SpringBoot+Vue基于web的多媒体素材管理系统的设计和实现

基于JavaWebBS架构SpringBootVue基于web的多媒体素材管理系统的设计和实现 文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 文末获取源码 Lun文目录 1 绪 论 1 1.1选题背景与意义 1 1.1 研究背景 1 1.2 研究意义…

Python办公自动化 – 数据预处理和数据校验

Python办公自动化 – 数据预处理和数据校验 以下是往期的文章目录&#xff0c;需要可以查看哦。 Python办公自动化 – Excel和Word的操作运用 Python办公自动化 – Python发送电子邮件和Outlook的集成 Python办公自动化 – 对PDF文档和PPT文档的处理 Python办公自动化 – 对Ex…

网络基础学习(3):交换机

1.交换机结构 &#xff08;1&#xff09;网线接口和后面的电路部分加在一起称为一个端口&#xff0c;也就是说交换机的一个端口就相当于计算机上的一块网卡。 如果在计算机上安装多个网卡&#xff0c;并让网卡接收所有网络包&#xff0c;再安装具备交换机功能的软件&#xff0…

QT开发 2024最新版本优雅的使用vscode开发QT

▬▬▬▬▬▶VS开发QT◀▬▬▬▬▬ &#x1f384;先看效果 &#x1f384;编辑环境变量 如图添加环境变量&#xff01;&#xff01;&#xff01; 东西全在QT的安装目录&#xff01;&#xff01;&#xff01; 找到的按照我的教程再装一次&#xff01;&#xff01;&#xff01; 点…

文心一言 VS 讯飞星火 VS chatgpt (176)-- 算法导论13.3 5题

五、用go语言&#xff0c;考虑一棵用 RB-INSERT 插人 n 个结点而成的红黑树。证明&#xff1a;如果 n>1&#xff0c;则该树至少有一个红结点。 文心一言&#xff1a; 要证明这个问题&#xff0c;我们首先需要理解红黑树的性质。红黑树是一种自平衡二叉搜索树&#xff0c;它…

test Property-based Testing-03-QuickTheories Java的属性驱动测试框架入门介绍

拓展阅读 开源 Auto generate mock data for java test.(便于 Java 测试自动生成对象信息) 开源 Junit performance rely on junit5 and jdk8.(java 性能测试框架。性能测试。压测。测试报告生成。) QuickTheories QuickTheories 是针对Java 8的属性驱动测试框架。 如果你…

python代码练习:双指针法

题目一&#xff1a;移除元素 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不…

源码:RecyclerView核心知识点

一、简单使用 1.导包 implementation androidx.recyclerview:recyclerview:1.1.0 2.使用 mAdapter new MyAdapter(getActivity());LinearLayoutManager layoutManager new LinearLayoutManager(getActivity());//设置布局方向// layoutManager.setOrientation(LinearLayoutM…

第十一章 后端编译与优化

文章目录 11.1 概述11.2 即时编译器11.2.1 解释器与编译器11.2.2 编译对象与触发条件11.2.3 编译过程 11.3 提前编译器11.4 编译器优化技术11.4.1 方法内联11.4.2 逃逸分析11.4.3 公共子表达式11.4.4 数组边界检查消除 11.1 概述 如果我们把字节码看作是程序语言的一种中间表示…