当前位置: 首页 > news >正文

设计模式の状态策略责任链模式

文章目录

  • 前言
  • 一、状态模式
  • 二、策略模式
  • 三、责任链模式


前言

  本篇是关于设计模式中的状态模式、策略模式、以及责任链模式的学习笔记。


一、状态模式

  状态模式是一种行为设计模式,核心思想在于,使某个对象在其内部状态改变时,改变该对象的行为,使对象看起来像是改变了其类。将状态的相关行为封装到独立的状态类中,并通过在运行时切换状态对象来改变对象的行为。实现方式在于,将状态抽取成单独的类,并由上下文类统一管理。
  状态模式的结构包括以下几个主要角色:

  1. 上下文类:它维护一个当前状态的实例,并且对客户端公开其接口。
  2. 抽象状态类:定义了所有具体状态类需要实现的接口,抽取出所有状态下共有的方法。
  3. 具体状态类:实现了抽象状态类,根据自身状态的特点,有选择性第重写父类方法的逻辑。

  假设需要设计一个抽奖系统,有四种状态:

  • 不能抽奖的状态
  • 可以抽奖的状态
  • 发放奖品的状态
  • 奖品发放完成的状态

  状态流转方式如下:
在这里插入图片描述  体现在代码上,首先设计一个抽象状态接口,该接口将各种状态下可能的操作进行聚合:

/*** 状态接口* 将各种状态下可能的操作聚合成一个接口* 实现类根据各自状态可能的业务去重写其中的方法*/
public interface State {/*** 扣除积分*/void deduceMoney();/*** 抽奖* @return*/boolean raffle();/*** 发放奖品*/void dispensePrice();
}

  抽象接口具体的实现
  不能抽奖状态,在此状态下只能去做出扣减积分的操作,扣减完成积分后,状态会变更为可抽奖状态

/*** 不能抽奖的状态*/
public class NoRaffleState implements State{RaffleActivity raffleActivity;public NoRaffleState(RaffleActivity raffleActivity) {this.raffleActivity = raffleActivity;}/*** 扣除积分*/@Overridepublic void deduceMoney() {System.out.println("扣除50积分,可以抽奖");raffleActivity.setState(raffleActivity.getCanRaffleState());}/*** 抽奖** @return*/@Overridepublic boolean raffle() {System.out.println("扣除积分方能抽奖");return false;}/*** 发放奖品*/@Overridepublic void dispensePrice() {System.out.println("不能发放奖品");}
}

  可抽奖状态,只能进行抽奖操作:

  • 未抽中奖品,重新回到不可抽奖状态
  • 抽中了奖品,流转到发送奖品状态
/*** 可以抽奖的状态*/
public class CanRaffleState implements State{RaffleActivity raffleActivity;public CanRaffleState(RaffleActivity raffleActivity) {this.raffleActivity = raffleActivity;}/*** 扣除积分*/@Overridepublic void deduceMoney() {System.out.println("已经扣除积分,可以抽奖");}/*** 抽奖** @return*/@Overridepublic boolean raffle() {System.out.println("正在抽奖,请稍等");int num = new Random().nextInt(10);if (num == 0){//中奖了,发放奖品raffleActivity.setState(raffleActivity.getDispenseState());return true;}else {System.out.println("很遗憾,您没有中奖");//回到不能抽奖的状态raffleActivity.setState(raffleActivity.getNoRaffleState());return false;}}/*** 发放奖品*/@Overridepublic void dispensePrice() {System.out.println("没中奖,不能发放奖品");}
}

  发放奖品状态,只能进行发放奖品的操作:

  • 奖品数量充足,流转到奖品发送完成状态。
  • 奖品数量不足,改变状态为不能抽奖
/*** 发放奖品的状态*/
public class DispenseState implements State{RaffleActivity raffleActivity;public DispenseState(RaffleActivity raffleActivity) {this.raffleActivity = raffleActivity;}/*** 扣除积分*/@Overridepublic void deduceMoney() {System.out.println("不能扣除积分");}/*** 抽奖** @return*/@Overridepublic boolean raffle() {System.out.println("不能抽奖");return false;}/*** 发放奖品*/@Overridepublic void dispensePrice() {if (raffleActivity.getCount()>0){System.out.println("恭喜中奖了");//改变状态为不能抽奖raffleActivity.setState(raffleActivity.getNoRaffleState());}else {System.out.println("很遗憾,奖品发送完了");//改变状态为奖品发送完成raffleActivity.setState(raffleActivity.getDispenseOutState());}}
}

  奖品发放完成,则不可以进行任何操作

/*** 奖品发放完成的状态*/
public class DispenseOutState implements State{RaffleActivity raffleActivity;public DispenseOutState(RaffleActivity raffleActivity) {this.raffleActivity = raffleActivity;}/*** 扣除积分*/@Overridepublic void deduceMoney() {System.out.println("奖品发送完了,请下次再参加");}/*** 抽奖** @return*/@Overridepublic boolean raffle() {System.out.println("奖品发送完了,请下次再参加");return false;}/*** 发放奖品*/@Overridepublic void dispensePrice() {System.out.println("奖品发送完了,请下次再参加");}
}

  创建一个上下文类,对状态进行统一管理,同时对状态进行初始化,并且上面的具体状态类,也聚合了上下文类的对象:

/*** 抽奖的行为*/
public class RaffleActivity {/*** 初始的状态*/State state = null;/*** 初始的数量*/int count = 0;State canRaffleState = new CanRaffleState(this);State noRaffleState = new NoRaffleState(this);State dispenseOutState = new DispenseOutState(this);State dispenseState = new DispenseState(this);public RaffleActivity(int count) {//初始状态,不能抽奖this.state = getNoRaffleState();this.count = count;}/*** 扣除积分*/public void deduceMoney(){state.deduceMoney();}/*** 抽奖*/public void raffle(){if (state.raffle()){//领取奖品state.dispensePrice();}}public State getState() {return state;}public void setState(State state) {this.state = state;}public int getCount() {int curCount = this.count;count--;return curCount;}public void setCount(int count) {this.count = count;}public State getCanRaffleState() {return canRaffleState;}public void setCanRaffleState(State canRaffleState) {this.canRaffleState = canRaffleState;}public State getNoRaffleState() {return noRaffleState;}public void setNoRaffleState(State noRaffleState) {this.noRaffleState = noRaffleState;}public State getDispenseOutState() {return dispenseOutState;}public void setDispenseOutState(State dispenseOutState) {this.dispenseOutState = dispenseOutState;}public State getDispenseState() {return dispenseState;}public void setDispenseState(State dispenseState) {this.dispenseState = dispenseState;}
}
public class Client {public static void main(String[] args) {RaffleActivity raffleActivity = new RaffleActivity(1);for (int i = 0; i < 3; i++) {//扣积分raffleActivity.deduceMoney();//抽奖raffleActivity.raffle();}}
}

小结
状态模式的优缺点
优点:

  • 遵循单一职责原则:将与状态相关的代码封装到独立类中。
  • 开闭原则:添加新状态非常方便,无需修改现有代码。
  • 消除大量条件语句:状态切换通过对象替换实现,而非复杂的条件判断。

缺点:

  • 类的数量增加:每个状态都需要创建一个类,可能导致类数量增多。
  • 状态之间的耦合:状态类之间可能需要频繁切换,会导致一定程度的耦合。

二、策略模式

  策略模式是一种行为设计模式,核心思想在于,定义了一组算法,将每个算法封装到独立的类中,使它们可以相互替换。
  策略模式通常包括以下角色:

  1. 上下文类:持有一个策略对象的引用,并且初始化具体策略。
  2. 抽象策略类:定义了所有具体策略类需要实现的接口。
  3. 具体策略类:实现抽象策略类,包含具体的算法或行为。

  假设目前有一个方法,需要根据参数中传入的不同的业务类型,执行不同业务的分派,如果使用传统方式,则会利用switch或者if-else实现,将来需要扩展的时候,需要对分支代码进行修改:

/*** 业务处理接口*/
public interface BusinessClass {/*** 处理业务*/void handleBusiness(int type);
}
public class BusinessClassImpl implements BusinessClass{/*** 处理业务* 根据传入的参数进行分发*/@Overridepublic void handleBusiness(int type) {switch (type){case 1:this.handleBusiness1();break;case 2:this.handleBusiness2();break;case 3:this.handleBusiness3();break;default:break;}}private void handleBusiness3() {System.out.println("业务3的具体逻辑");}private void handleBusiness2() {System.out.println("业务2的具体逻辑");}private void handleBusiness1() {System.out.println("业务1的具体逻辑");}
}

  使用策略模式改造,则可以抽取一个策略接口

/*** 业务策略接口*/
public interface BusinessStrategy {/*** 处理具体的业务逻辑*/void handleBusiness();
}

  将传统方式中,每个分支中的方法都抽取到一个单独的类中,实现策略接口

public class Business1 implements BusinessStrategy{/*** 处理具体的业务逻辑*/@Overridepublic void handleBusiness() {System.out.println("处理业务逻辑1");}
}
public class Business2 implements BusinessStrategy{/*** 处理具体的业务逻辑*/@Overridepublic void handleBusiness() {System.out.println("处理业务逻辑2");}
}
public class Business3 implements BusinessStrategy{/*** 处理具体的业务逻辑*/@Overridepublic void handleBusiness() {System.out.println("处理业务逻辑3");}
}

  在上下文类中,对其进行统一的管理,业务代码只需要注入上下文类,调用其中的方法即可。

public class Context {private Map<Integer, BusinessStrategy> strategyMap = new HashMap<>();/*** 初始化上下文,k业务类型 v 业务类型具体的逻辑*/public Context(){strategyMap.put(1, new Business1());strategyMap.put(2, new Business2());strategyMap.put(3, new Business3());}/*** 处理业务* 根据传入的参数进行分发*/public void handleBusiness(int type) {BusinessStrategy strategy = strategyMap.get(type);if (strategy != null) {strategy.handleBusiness();} else {System.out.println("无效的业务类型");}}
}

小结
策略模式的优缺点
优点:

  • 遵循开闭原则:添加新策略无需修改现有代码,只需扩展新策略类。
  • 消除条件语句:避免了复杂的 if-else 或 switch-case 语句。
  • 提高灵活性:客户端可以动态选择策略。

缺点:

  • 类数量增加:每种策略需要创建一个类,可能导致类的数量过多。
  • 客户端需要了解不同策略:客户端必须知道有哪些策略才能选择合适的策略。

三、责任链模式

  责任链模式是一种行为设计模式,核心目的在于,将请求的处理责任沿着一条链传递,直到有对象处理这个请求为止。责任链模式将请求的发送者和接收者解耦,且可以动态地调整链条上的处理顺序。
  责任链模式通常包含以下角色:

  1. 抽象处理者:定义了处理请求的接口,以及一个指向下一个处理者的引用。(即将自身作为属性存放在类中)
  2. 具体处理者:继承了抽象处理者,具体去实现各自处理请求的逻辑,以及无法处理时/处理完成时,应该调用的下一个处理者
  3. 客户端:创建并组装责任链,通常会将请求发送给责任链的首个处理者

  下面来看一个案例:假设某个学校,购买教材,器材,根据金额不同,需要审批的级别也不同。
  首先构建一个请求对象

public class Request {/*** 请求id*/protected int id = 0;/*** 价格*/protected int price = 0;public Request() {}public Request(int id, int price) {this.id = id;this.price = price;}public int getId() {return id;}public void setId(int id) {this.id = id;}public int getPrice() {return price;}public void setPrice(int price) {this.price = price;}
}

  然后定义一个抽象处理者

/*** 抽象审批人*/
public abstract class Approver {/*** 审批人名称*/protected String name;/*** 持有自己的引用*/protected Approver approver;public Approver() {}public Approver(String name) {this.name = name;}public void setApprover(Approver approver) {this.approver = approver;}/*** 子类具体去实现处理请求的逻辑* @param request*/abstract void handleReq(Request request);}

  定义具体处理人,继承抽象处理人,编写自己处理的判断逻辑:

public class TeachingDirector extends Approver{public TeachingDirector(String name){super(name);}/*** 子类具体去实现处理请求的逻辑** @param request*/@Overridevoid handleReq(Request request) {if (request.getPrice()<= 5000){System.out.println("请求编号"+ request.id + "已经被" + name + "处理");}else {approver.handleReq(request);}}
}
public class Dean extends Approver{public Dean(String name){super(name);}/*** 子类具体去实现处理请求的逻辑** @param request*/@Overridevoid handleReq(Request request) {if (request.getPrice()<= 10000){System.out.println("请求编号"+ request.id + "已经被" + name + "处理");}else {approver.handleReq(request);}}
}
public class Principal extends Approver{public Principal(String name){super(name);}/*** 子类具体去实现处理请求的逻辑** @param request*/@Overridevoid handleReq(Request request) {if (request.getPrice()<= 20000){System.out.println("请求编号"+ request.id + "已经被" + name + "处理");}else {approver.handleReq(request);}}
}

  最后由客户端对其进行统一组装:

public class Client {public static void main(String[] args) {Request request = new Request(1, 8000);Dean dean = new Dean("院长");TeachingDirector teachingDirector = new TeachingDirector("教学主任");Principal principal = new Principal("校长");//设置下一个审批者teachingDirector.setApprover(dean);dean.setApprover(principal);principal.setApprover(teachingDirector);//8000 教学主任处理不了,交给下一级(院长)处理teachingDirector.handleReq(request);}
}

小结
责任链模式的优缺点

优点:

  • 降低耦合度:请求发送者与接收者解耦,无需关心由谁处理请求。
  • 动态灵活:可以在运行时动态调整责任链的结构。
  • 增强扩展性:新增处理者无需修改现有代码。

缺点:

  • 链条可能过长:请求可能需要经过多个处理者,性能可能受影响。
  • 调试困难:由于请求的处理流程不明确,可能导致调试复杂。

相关文章:

设计模式の状态策略责任链模式

文章目录 前言一、状态模式二、策略模式三、责任链模式 前言 本篇是关于设计模式中的状态模式、策略模式、以及责任链模式的学习笔记。 一、状态模式 状态模式是一种行为设计模式&#xff0c;核心思想在于&#xff0c;使某个对象在其内部状态改变时&#xff0c;改变该对象的行为…...

DevOps流程CICD之Jenkins使用操作

一、jenkins的docker-compose安装部署 请参考 jenkins的docker安装部署配置全网最详细教程-CSDN博客 二、创建repository 三、创建ssh 四、创建视图 五、创建任务 六、配置gitlab钩子 七、自动构建部署CI/CD验证...

【玩转23种Java设计模式】行为型模式篇:备忘录模式

软件设计模式&#xff08;Design pattern&#xff09;&#xff0c;又称设计模式&#xff0c;是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。 汇总目录链接&…...

Unity Shader TexelSize的意义

TexelSize在制作玻璃折射效果时会用到。 // Get the normal in tangent space fixed3 bump UnpackNormal(tex2D(_BumpMap, i.uv.zw)); // Compute the offset in tangent space float2 offset bump.xy * _Distortion * _RefractionTex_TexelSize.xy; i.scrPos.xy offset * i…...

三、STM32MP257系列之定制Yocto Machine

文章目录 STM32MP257系列之定制的Yocto Machine1. TFA 定制2. OPTEE OS定制3. Uboot 定制3.1 创建 board3.2 创建 board的头文件3.3 创建 board的配置文件3.4 添加我们自己的dtb文件3.5 生成新patch打包到uboot recipe中3.6 修改yocto中的配置 4. Kernel 定制4.1 定制设备树 5.…...

小程序信息收集(小迪网络安全笔记~

免责声明&#xff1a;本文章仅用于交流学习&#xff0c;因文章内容而产生的任何违法&未授权行为&#xff0c;与文章作者无关&#xff01;&#xff01;&#xff01; 附&#xff1a;完整笔记目录~ ps&#xff1a;本人小白&#xff0c;笔记均在个人理解基础上整理&#xff0c;…...

使用 Docker 搭建 Drogon 框架

使用 Docker 搭建 Drogon 框架 Drogon 是一个基于 C 的高性能 Web 框架&#xff0c;支持异步 I/O 和协程。使用 Docker 可以快速搭建 Drogon 开发环境&#xff0c;避免依赖冲突和配置问题。 以下是使用 Docker 搭建 Drogon 框架的详细步骤&#xff1a; 1. 准备工作 安装 Doc…...

【Linux报告】实训一:GNME桌面环境的设置及应用

实训一&#xff1a;GNME桌面环境的设置及应用 【练习1】在图形模式和文本模式下登录Linux系统。 1、开启Linux虚拟机。 答&#xff1a;打开此虚拟机如图所示 2、观察屏幕上显示的启动信息。 3、当系统启动到图形界面时&#xff0c;用普通用户身份登录。 答&#xff1a;如图…...

活动预告 |【Part1】Microsoft Azure 在线技术公开课:基础知识

课程介绍 参加“Azure 在线技术公开课&#xff1a;基础知识”活动&#xff0c;培养有助于创造新的技术可能性的技能并探索基础云概念。参加我们举办的本次免费培训活动&#xff0c;扩充自身的云模型和云服务类型知识。你还可以查看以计算、网络和存储为核心的 Azure 服务。 活…...

vulnhub靶场【Hogwarts】之bellatrix

前言 靶机&#xff1a;hotwarts-dobby&#xff0c;ip地址为192.168.1.69 攻击&#xff1a;kali&#xff0c;ip地址为192.168.1.16 都采用虚拟机&#xff0c;网卡为桥接模式 主机发现 使用arp-scan -l或netdiscover -r 192.168.1.1/24扫描发现主机 信息收集 使用nmap扫描端…...

移动 APP 设计规范参考

一、界面设计规范 布局原则&#xff1a; 内容优先&#xff1a;以内容为核心进行布局&#xff0c;突出用户需要的信息&#xff0c;简化页面导航&#xff0c;提升屏幕空间利用率.一致性&#xff1a;保持界面元素风格一致&#xff0c;包括颜色、字体、图标等&#xff0c;使用户在…...

HarmonyOS:@Require装饰器:校验构造传参

一、前言 Require是校验Prop、State、Provide、BuilderParam和普通变量(无状态装饰器修饰的变量)是否需要构造传参的一个装饰器。 说明 从API version 11开始对Prop/BuilderParam进行校验。 从API version 11开始&#xff0c;该装饰器支持在元服务中使用。 从API version 12开…...

github提交不上去,网络超时问题解决

问题出现的原因&#xff1a; DNS服务器数据不同步&#xff0c;github的服务器发送迁移&#xff0c;在本地缓存的ip地址现在无效了。 解决方案&#xff1a; 1&#xff09;点击这里&#xff0c;查询github.com最新的ip地址 2.0&#xff09;编辑linux系统地址缓存文件&#x…...

国产数据库OceanBase从入门到放弃教程

1. 介绍 是由蚂蚁集团&#xff08;Ant Group&#xff0c;原蚂蚁金服&#xff09;自主研发的分布式关系型数据库。它旨在解决海量数据存储和高并发访问的问题&#xff0c;特别适合金融级应用场景&#xff0c;如支付宝等对数据一致性、可靠性和性能有极高要求的服务。以下是关于…...

风力涡轮机缺陷检测数据集,91.4%准确识别率,18912张图片,支持yolo,PASICAL VOC XML,COCO JSON格式的标注

风力涡轮机缺陷检测数据集&#xff0c;91.4&#xff05;准确识别率&#xff0c;18912张图片&#xff0c;支持yolo&#xff0c;PASICAL VOC XML&#xff0c;COCO JSON格式的标注 数据集下载&#xff1a; &#xff59;&#xff4f;&#xff4c;&#xff4f; &#xff56;&#…...

Rabbitmq追问2

分析rabbitmq 默认使用姿势是什么 direct fanout还是什么 public void convertAndSend(String exchange, String routingKey, Object object, CorrelationData correlationData) throws AmqpException { this.send(exchange, routingKey, this.convertMessageIfNecessary(obje…...

郑州时空-TMS运输管理系统 GetDataBase 信息泄露漏洞复现

0x01 产品简介 郑州时空-TMS运输管理系统是一款专为物流运输企业设计的综合性管理软件,旨在提高运输效率、降低运输成本,并实现供应链的协同运作。系统基于现代计算机技术和物流管理方法,结合了郑州时空公司的专业经验和技术优势,为物流运输企业提供了一套高效、智能的运输…...

如何使用React,透传各类组件能力/属性?

在23年的时候&#xff0c;我主要使用的框架还是Vue&#xff0c;当时写了一篇“如何二次封装一个Vue3组件库&#xff1f;”的文章&#xff0c;里面涉及了一些如何使用Vue透传组件能力的方法。在我24年接触React之后&#xff0c;我发现这种扩展组件能力的方式有一个专门的术语&am…...

汇编点灯练习

要求&#xff1a; 1、轮流将LED1、LED2、LED3及蜂鸣器点亮 2、基于STM32MP157AAA&#xff0c;阅读原理图和STM32MP157芯片手册 3、ARM汇编指令点灯 1、运行效果 汇编点灯 2、通过查询原理图和芯片手册&#xff0c;得到以下结论&#xff1a; 3、汇编源码 .text .global _start…...

数据结构与算法之动态规划: LeetCode 213. 打家劫舍 II (Ts版)

打家劫舍 II https://leetcode.cn/problems/house-robber-ii/description/ 描述 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋&#xff0c;每间房内都藏有一定的现金这个地方所有的房屋都 围成一圈 &#xff0c;这意味着第一个房屋和最后一个房屋是紧挨着的同时&#…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

FFmpeg 低延迟同屏方案

引言 在实时互动需求激增的当下&#xff0c;无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作&#xff0c;还是游戏直播的画面实时传输&#xff0c;低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架&#xff0c;凭借其灵活的编解码、数据…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

【JavaSE】绘图与事件入门学习笔记

-Java绘图坐标体系 坐标体系-介绍 坐标原点位于左上角&#xff0c;以像素为单位。 在Java坐标系中,第一个是x坐标,表示当前位置为水平方向&#xff0c;距离坐标原点x个像素;第二个是y坐标&#xff0c;表示当前位置为垂直方向&#xff0c;距离坐标原点y个像素。 坐标体系-像素 …...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...