设计模式 - 最简单最有趣的方式讲述

别名《我替你看Head First设计模式》

    本文以故事的形式带你从0了解设计模式,在其中你仅仅是一名刚入职的实习生,在项目中摸爬滚打。(以没有一行真正代码的形式,让你无压力趣味学习)

设计模式

  • 策略模式
  • 观察者模式
  • 装饰者模式

策略模式

故事背景:
    你们公司打算开发一款鸭塘模拟游戏《SimUDuck》,于是公司主管找上实习生的你,并提出了简单的需求:


功能需求:
    需要表达两只鸭子,绿鸭子和红鸭子。它们都需要会嘎嘎叫游泳,并区分它们之间的颜色以显示(绿鸭子显示绿色、红鸭子显示红色)


开始设计:
    作为实习生的你十分自信,拿出了 “引以为豪” 的继承,并做出了设计。

  • 父类Duck:有三个方法嘎嘎叫quack游泳swim显示display
  • 子类GreenDuck、RedDuck:分别覆盖了显示display方法,实现各自的显示颜色。

故事背景:
    你最好的朋友产品经理找到你,让你改一个小小的功能:


功能需求:
    需要加上一个的功能。


开始设计:
    你临机一动,认为只需要在父类Duck中添加一个飞fly方法,所有鸭子就都会飞了,你十分的笃定。


故事背景:
    目前一切都很完美。过一段时间,产品经理又来找你了,你以为是夸奖你不错的,但实际上他是来告诉你,你的设计有bug!bug!bug!:


bug发现:
    bug出现在,现在不止有绿鸭子红鸭子,后来又加入了橡皮鸭子,造成了橡皮鸭子在屏幕上飞来飞去的戏剧一幕。


开始设计:
    作为父类继承给橡皮鸭子会飞的 “有趣特色” ,却不被理解的你很伤心,于是你的第一个想法是让橡皮鸭子覆盖掉父类继承的飞fly方法。

    本就聪明的你这一次开始深度思考继承。发现,虽然这一次能够通过覆盖特殊行为勉强过关,但是如果又添加木制鸭子纸制鸭子呢?就需要在每个鸭子内部判断它是否会飞、是否会嘎嘎叫进行选择性覆盖,太复杂了。


故事背景:
    你收到一条备忘录,公司说将会每六个月为周期更新产品。没错!正是如你所想,因此你需要更干净利落的设计:


开始设计:
    头脑风暴中你想到了 java / Qt 中的able结尾的接口,于是你开始往这个方向思索,能否将fly写为flyable接口,quack写为quackable接口,让只有鸭子具备这个行为时才实现该接口。


故事背景:
    在你给同事讲述后,同事却说:“这是你最愚蠢的主意,干嘛不直接说 ‘重复代码’ 算了?当你需要对成百上千个子类的行为做不同的描述时,你感觉会怎么样?”。随后同事为你指出根本问题:


根本问题:
    实际上是像flyquack这些方法,都是一直会随着需求的变化而变化,并不是所有的鸭子都会flyquack,因此继承并不是正确答案!采用able结尾的接口设计,也仅仅只是解决了橡皮鸭会飞的 “有趣特性” 的部分问题,对于变化部分任然需要不断的针对性实现(运维噩梦)
    你渴求的是:变更时对现有代码影响最小的方式。你却将变化融入不变使得常常被迫往下追踪到定义了该行为的子类并修改它。

设计原则:
    识别应用中变化的方面,将它们和不变的方面分开。


开始设计:
    “取得真经” 的你茅舍顿开,意识到正确的做法是取出变化的部分,并将它 “封装起来” 让它不会影响到其他代码。

设计原则:
    针对接口(超类型/基类型)编程,而不是针对实现编程。 - 要点是通过针对超类型/基类型编程来利用多态

设计原则:
    优先使用组合而不是继承。


故事背景:
   沉浸在技术提升中的你,通过自己发现了这个设计的又一个妙处,并在询问同事后的赞扬中,知道了通过setter方法可以动态的设计行为:


设计报告:

   你如今的设计,关键在于Duck系列类将行为需求委托而出了,而不是通过自行实现行为方法。如:飞行行为,通过将行为需求委托给FlyBehavior* flyBehavior所引用的对象,而flyBehavior中引用的是哪一个对象无需关心,flyBehavior->fly()就对了,并且可以通过setter方式动态的设计行为。


伪代码:

测试:


故事背景:
    通过这次项目经历,作为实习生的你成长了,你明白了策略模式以及三个设计原则,你明白了不应该将鸭子的行为看作一组行为,而是开始将它们看作多种策略族(算法家族),如飞行算法家族中:普通飞是一个策略、不能飞是一个策略、飞的和火箭一样快也是一个策略。

策略模式: 定义了一个算法族,分别封装起来,使得它们之间可以互相变换。策略让算法的变化独立于使用它的客户。


故事概述:
    面对场景:在日常开发中,往往渴望通过继承的方式让子类们继承父类的方法,实现代码的复用,但是仅使用继承终究是编译时决议,运行时的硬编码。导致变化融入不变从而常常需要向下追踪到行为独特的子类针对性实现。
    策略模式(在我看来)可以说是算法族模式,通过:不变分离针对封装的行为父类实现采取组合的多态使用。实现对于设计使用时,仅需为子类多态指针new算法族子类行为,子类自会通过继承于父类的多态调用方法,实际运行。


观察者模式

故事背景:
    你们公司喜欢培养实习生,于是你再一次挂帅出征。这一次是你们公司赢下了Weather-O-Rama公司想基于Internet气象观测台建立显示平台的合同:


功能需求:
    Internet气象观测台提供:温度数据湿度数据气压数据,你需要编写代码作用于显示设备(告知显示设备新数据),让用户可以及时查看这三个数据的预报。并且Weather-O-Rama公司书写提供了一个WeatherData对象,你需要适配该对象(因为它可以获得更新的气象数据)。

  • 数据更新measurementsChanged会被调用。
  • measurementsChanged中可以通过getter系列方法获取数据。
  • 通过measurementsChanged可以高效告知所有用户新数据。

开始设计:
    对于设计模式,你刚刚初窥门径,无法做到一蹴而就,所以对需求先给出了简易的第一版设计。


故事背景:
    有过《SimUDuck》游戏设计的经历的你,一眼就看出了这个设计的bug(运维噩梦):


bug发现:
    针对具体实现编程了!你提出一个变化:气象站如果成功,很可能会使得未来多于三个数据显示需求,那么你便没有办法在不修改代码的情况下添加或移除其它显示元素。


故事背景:
    你:“看起来显示设备的update调用参数传递是一个变化的地方,我应该需要封装一下这里!并且gatter获取数据后,又指定特定显示设备的update调用,这明显是根据实现编程了”。但是你想了半天任然无明确头绪,于是决定询问 “大佬” 同事,他立马发现是你不具备一种思维。


根本问题:
    你需要认识到观察者模式(出版者 + 订阅者 = 观察者模式),让我们换一个简单且有趣的例子来描述一下:报纸/杂志的订阅

  1. 报社开始运营,其作为出版者需负责出版报纸。
  2. 你到报社登记订阅,作为订阅者他们有新报纸就会交付给你。
  3. 你看腻了,告知报社取消订阅,新报纸就不再有你的份了。
  4. 而在其中有无数的订阅者

观察者模式: 定义对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。


故事背景:
    在此期间你提出疑问:“为什么是一对多,还是依赖关系”?同事:“因为主题是一个数据的拥有管理者,另一方面,众多的观察者是数据的需求者,并且主题是数据的唯一拥有者,所以观察者需要依赖于主题来获取数据!”。


开始设计:
    受到触动你的立马开始了新的设计。

  • 观察者对象们需便于维护(多态指向):Observer*
  • 主题对象需一个结构用于维护订阅的观察者对象们:list<Observer*> observers;
  • 主题对象需提供维护是否订阅的方法:registerObservers()removeObservers()notifyObservers()

故事背景:
    大佬同事:“很不错,你已经了解我所表达的模式思维了,但你是不是忘记了分离变与不变?并且在其中有松耦合的魅力,你可以自己发现一下。”


开始设计:
   你恍然大悟,对设计进行了优化。


松耦合:
   当有太多依赖到另一个对象时,我们就说一个对象紧耦合到另一个对象。换一句话就是一个对象对另一个对象说:“你知道的太多了!”。而观察者模式是松耦合的一个很棒的例子。

  1. 主题只用知道观察者实现了某个接口update —— 如同信件箱。
       无需知道观察者具体是什么样的观察者,想要做什么等。
  2. 主题可以在任意时刻添加依赖其的新观察者。
       因为主题依赖的是实现观察者多态对象列表。
  3. 观察者的新增无需修改主题。
       只需实现新类,在其中实现新观察者接口并注册新类为一个观察者。
  4. 任意一方修改都不会影响另一方,更可以彼此独立的复用主题或观察者。
       关联的地方仅在:多态对象列表多态对象的update方法

设计原则:
    尽量做到交互的对象之间的松耦合设计。 - 主题与观察者的联系在于各自的接口上,仅需知道对象的接口,其他事情毫不知情。


伪代码:

测试:
   为便于数据的显示,给WeatherData类添加一个setMeasurements()方法,以提供新数据。


故事背景:
    目前一切都很完美,“完美的” 解耦合。过了一段时间,你的好朋友产品经理又来了:“最新消息Weather-O-Rama公司最近进行了问卷采集,所以为了对齐用户需求,希望用户仅仅拿到他们所想要的数据,而不是强迫的接收所有的数据”。
    你:“呀!这不正是我最初的发现吗(未来很可能多于三个数据显示需求)?


开始设计:
    显而易见正是你如今设计中的update参数传递部分的硬编码(上述伪代码中标红部分)行为所导致的。解决点在于:主题并不知观察者的数据所求意图,只有观察者懂自己,即观察者所需时自行通过getter系列函数拉取数据。


设计报告:

   你如今的设计,关键在于主题与观察者皆采取组合(多态)编程。并优化为观察者所需时自行通过getter系列函数拉取数据,避免主题硬编码的强制发送数据行为。


故事背景:
    Weather-O-Rama公司来信:

观察者模式: 定义对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。


故事概述:
    面对场景:对于日常开发中,渴望将数据类的新数据及时告知数据需求类们,这时新数据的来到仅数据类知道,而通过数据类的方法调用数据需求类们update方法传递数据,会出现针对实现的硬编码问题:update方法的固定调用。
    观察者模式:通过组合的链表,实现主题观察者一对多关系,观察者的新增、删除仅需修改链表,主题的通知仅需调用观察者的特定接口update(),做到了交互对象之间的解耦合设计。


装饰者模式

故事背景:
    是的!又是你!由于你实在是太爱使用继承编写代码了,所以公司立志要将你磨成一把 “宝剑”,但你听说小道消息,这是专门给你安排的项目就是为了给你打开 “设计之眼”!


功能需求:
    星巴兹 (Starbuzz) 咖啡是最近兴起的连锁咖啡店,因为扩张速度太快所以他们着急更新下单系统。如下是他们老旧的下单系统设计:


故事背景:
    了解完的你,不经感叹:“确实是专门为我准备,和我曾经的设计习惯如出一辙,对于继承真是情有独钟!容我大胆想想这样设计的后果”。


设计分析:
    按照他们的旧设计,在加上星巴兹 (Starbuzz) 咖啡如今蓬勃的发展,每多一个饮料就需要根据其价格进行实现 (真是针对实现编程的愚蠢设计…)

    (这才30个左右哟~~)更进一步来说,任性的客户就不能配料double?然后因此你需要完美预判写个HouseBlend1HouseBlend2HouseBlend3…?


故事背景:
    不多说了简直无理取闹,眼睛都看花了,问题很大!头炸了这么大!简直就是一个 “类爆炸” 的运维噩梦!


开始设计:
    老旧的设计已为你将坑完美试探出:不同种类的饮料价格是不同的 -> 选取的配料价格不同、单位量不同。一个最随意的构思应运而生:


故事背景:
    看似解决,但任然存在问题。有过两次设计经验的你发现:“调料价格改变会迫使需要修改现有代码、新调料的增加需要修改父类中的cost()实现、不适合的调料会继承给对应的饮料”。


设计分析:
    完美的触犯了:需将不变分离!配料就是极其有可能变化的代码,而父类作为一个不应该变化的部分(因为具有非常多的子类),它会影响到所有的子类(父类修改出bug,影响所有子类),也无法在运行时动态改变一个类的行为。


故事背景:
    碰巧周会悄然来临,说不定在其中可以找到解决方案,你需要做的就是讲述你如今对于继承的理解…


反思追寻:

  • 策略模式: 开发一款鸭塘模拟游戏《SimUDuck》。
  • 观察者模式: 开发基于Internet气象观测台建立显示平台。

设计原则:
    类应该对扩展开放,但对修改关闭。


故事背景:
    “大佬” 同事来拯救你了:“小伙子不错嘛!成长的很快,但以防你 ‘中毒’ 过深容我强调一下。开放-关闭原则其实通常情况下是办不到的,因为这需要时间和精力,过于的最求就是在浪费,它的实现往往也需要引入新的抽象层次,从而大大增加代码的复杂度。日常中你往往只需专注于最有可能改变的区域进行实现就足够了,而哪部分区域的变化是最重要的,就需要你具备熟能生巧的设计经验了,加油!”。


开始设计:
    你现在正式从设计原则的角度开始着手设计,毫无疑问你所最熟悉的设计原则:

设计原则:
    识别应用中变化的方面,将它们和不变的方面分开。

设计原则:
    针对接口(超类型/基类型)编程,而不是针对实现编程。 - 要点是通过针对超类型/基类型编程来利用多态

设计原则:
    优先使用组合而不是继承。

    和两个理解不是太深的设计原则:

设计原则:
    尽量做到交互的对象之间的松耦合设计。 - 主题与观察者的联系在于各自的接口上,仅需知道对象的接口,其他事情毫不知情。

设计原则:
    类应该对扩展开放,但对修改关闭。 - 只需专注于最有可能改变的区域进行实现就足够了。

    从你最熟悉的三个设计原则入手,无非渴望能够将变化的部分进行独立封装(以接口(超类型/基类型)编程),随后用组合实现运行时弹性的设置。


故事背景:
    你开始展开思维:“饮料原料都是水,那我通过饮料 ‘制作’ 为开始(原料价格),使用调料 ‘装饰’ 为过程(原料 += 调料价格),最终饮料成型(售卖价格),是否可行?”。


根本问题:
    确实是一个很好的想法,但也仅仅是一个想法,对于一个设计模式,需要关注的太多了,于是你开始上网找 “名师” 。于是你便发现了一个设计模式:装饰者模式,并对你的想法进行了优化。

装饰者模式: 动态地将额外责任附加到对象上。对于拓展功能,装饰者提供子类化之外的弹性替代方案


   本图实在不易于理解,此处给出最简的代码概述:

伪代码:

测试:


根本问题:
   继承并不是仅仅只能带来行为的复用,还能达成类型的匹配

   在此做出假设: CondimentDecorator 并不继承于 Beverage,那么便会出现一层配料包装影响类型 。

测试:

这是装饰者模式所需的(装饰者有着和所装饰的对象相同的父类型),通过这样的方式可以实现:

  • 鉴于装饰对象所装饰对象具有相同父类型,需要原始对象的场景,可以直接传递一个被装饰的对象
  • 用一个或多个装饰者包囊一个对象。
  • 装饰者委托给所装饰对象之前或之后添加自己的行为。

故事背景:
    “大佬”同事:“干的不错!自行摸索下能够如此迅速的初步了解到装饰者模式,但容许我验证一下你的思维:CondimentDecorator类是否并没有存在的意义?重点不是配料们吗?直接继承Beverage类效果不是一样吗?”。
    你:“这确实是一个有趣的问题,碰巧我在资料查询中有所遇到,并进行过思考…”。


问题思路:
    星巴兹 (Starbuzz) 咖啡刚刚兴起,所以功能需求上极少,以此使得CondimentDecorator类看似“鸡肋”,但我认为其中存在两个关键设计原则。

设计原则:
    尽量做到交互的对象之间的松耦合设计。 - 主题与观察者的联系在于各自的接口上,仅需知道对象的接口,其他事情毫不知情。

设计原则:
    识别应用中变化的方面,将它们和不变的方面分开。

   删除CondimentDecorator这种做法似乎简化了结构,但实际上会减少装饰者模式的可扩展性和灵活性。

  • 现代码分析装饰链形成正是因为调料具备Beverage的引用(Beverage*)。如果直接继承Beverage,那么此共用逻辑就需要在每个具体装饰者中重复编写,或在Beverage中编写导致抽象组件具体装饰者之间的耦合增加,且让每个具体组件获得其无需属性。

   正如上所述,CondimentDecorator作为抽象装饰者,可以定义一些通用的逻辑或状态管理,如果直接继承Beverage,会引起代码激增(维护噩梦)

通用逻辑写入具体装饰者违反:识别应用中变化的方面,将它们和不变的方面分开。
通用逻辑写入抽象组件违反:尽量做到交互的对象之间的松耦合设计。


故事背景:
   “大佬”同事:“回答的真好!看来你开始理解松耦合的魅力了!”


故事概述:
   面对场景:对于日常开发中,渴望将对象进行不断的修饰,并拿到最后的修饰结果,如果将对象类可进行的修饰属性进行类内维护,将会造成不可想象的运维噩梦。
   装饰者模式:通过具体装饰继承于抽象装饰抽象装饰具体组件继承于抽象组件,使得装饰组件具备统一类型,让装饰可以通过父类引用的方式引用原组件被修饰的组件,实现修饰链。并以组合(父类引用)的方式实现组件装饰分离实现动态地装饰。


本文资料来源:《Head First设计模式 第二版》
本文画图工具: diagrams
本文编写形式: markdown

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

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

相关文章

springboot仪器校准系统-计算机毕业设计源码51504

摘 要 随着科技的不断发展。测量设备的准确性和可靠性对于各行各业都至关重要。仪器校准系统作为确保测量设备性能的重要手段&#xff0c;已成为工业生产、科学研究、质量控制等领域不可或缺的一部分。本文对仪器校准系统进行了概述&#xff0c;探讨了校准方法、流程、特点、应…

Apache防盗链、网页压缩、网页缓存

目录 网页压缩 类型 示例 动态添加模块操作步骤 重装Apache操作步骤 网页缓存 示例 操作步骤 隐藏版本信息 操作步骤 Apache防盗链 定义 原理 配置防盗链实验环境 实验环境 本地图片盗链示例 操作步骤 防盗链示例 操作步骤 网页压缩 网站的访问速度是由多个…

following a different leader because i am not the healthiest node

源代码 解决方案&#xff1a; 手动 patronictl failover 修改切换模式从高可靠模式改成高可用模式 patronictl edit-config-synchronous_mode: true synchronous_mode: false

透明加密软件哪个好?这5款好用的加密软件尽在你眼前!

数据安全和隐私保护已成为企业和个人不可忽视的重要问题。 透明加密技术以其无需用户额外操作即可实现文件的加密和解密&#xff0c;大大提高了数据处理的便捷性和安全性。 下面小编将为您介绍五款优质的透明加密软件&#xff0c;帮助您选择最适合自己的加密工具。 1. Pg32 …

超秒集物商城打造“私域流量新策略”用消费增值破解流量困局

消费增值模式是什么?在如今这个公域流量的竞争愈发激烈的时代,流量已成为企业竞争的关键,消费增值可以帮助企业在私域流量的海洋中乘风破浪? 一、消费增值模式的引入 消费增值模式不仅仅是一种商业模式,更是一种营销策略。它鼓励消费者在享受商品或服务的同时,通过消费行为获…

KEIL5 MDK的(官网)下载安装(Win11)

一、KEIL5 MDK下载 1、Keil官网下载&#xff1a;Keil Product Downloadshttps://www.keil.com/download/product/ 支持包和破解软件和V5编译器下载链接 链接&#xff1a;https://pan.baidu.com/s/1ery0Q3FAR8_bLLlPQHSFNg?pwd9pxf 提取码&#xff1a;9pxf 选择最新版本下载&…

打造高效能“园区企业服务平台”,让企业更好更快发展!

​近年来&#xff0c;随着我国经济的快速发展&#xff0c;各地产业园区建设如火如荼&#xff0c;成为区域经济的支柱&#xff0c;如果说园区是区域经济的支柱&#xff0c;企业则是园区的血液&#xff0c;给园区带来生命力&#xff0c;为园区发展提供着动力&#xff0c;各地政府…

electron + express 实现 vue 项目客户端部署

写在前面 作为一个前端程序员&#xff0c;如何实现从前端到客户端的跨越&#xff0c;可能是一个很难实现的事。但客户需求千奇百怪&#xff0c;偶尔遇到一个非要客户端的&#xff0c;如何应对&#xff1f; 那Electron可能真是你福音。具体它有哪些功能&#xff0c;可自行官网…

向日葵IT运维节丨解决三个关键问题,搞好企业IT运维

724运维节&#xff0c;是所有运维人的节日&#xff0c;贝锐向日葵也在这一天致敬所有需要7x24小时待命的运维人&#xff0c;将这一天定为“向日葵IT运维节”&#xff0c;为广大运维人带来大量专属福利&#xff01; 724这组数字&#xff0c;折射出运维人的日常&#xff0c;即7x2…

c++多态的定义和原理

目录 1、多态的定义和实现 1.多态的构成条件 2.虚函数 3.虚函数的重写(覆盖) 4.虚函数重写的两个例外 5.c11 override和final 6.重载&#xff0c;覆盖(重写)和隐藏(重定义) 2、抽象类 概念 接口继承和实现继承 3、多态的原理 1.虚函数表 2.多态的原理 4、多继承中的虚…

MessageBox与HubSpot:企业沟通与客户管理的双重利器

今天咱们来聊聊两个超实用的工具——MessageBox和HubSpot。它们就像是你的超级助手&#xff0c;让你和客户沟通起来更顺畅&#xff0c;管理起来也更轻松。 先说说MessageBox吧 想象一下&#xff0c;你正在忙着工作&#xff0c;突然客户发来个消息&#xff0c;你嗖的一下就收到…

常见网页问题解决

用edge浏览器打印功能时&#xff0c;出现瞬间或加载几秒后突然闪退情况&#xff0c;本来以为是浏览器出了问题&#xff0c;去重置设置也没有&#xff0c;后来又下载了Chrome浏览器&#xff0c;没想到还是一样&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;想着…

windows安装Docker Desktop及国内镜像

简介 Docker 是一个开源的应用容器引擎&#xff0c;它让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的 Linux 机器上&#xff0c;也可以实现虚拟化。通过Docker工具&#xff0c;简化了应用的部署、配置和管理过程&#xff0c;提高…

2024年五款企业加密软件(企业加密软件排行最新)

关键是数字化时代&#xff0c;企业数据安全至关重要。一般来说信息技术快速发展&#xff0c;企业数据泄露风险上升。你知道的加密软件保护企业核心数据和商业机密&#xff0c;不可或缺。对我而言介绍几款企业加密软件&#xff0c;帮助选择适合需求的解决方案。 固信加密软件ht…

性价比高充电宝有哪些?充电宝十大最佳品牌大盘点!

在如今这个高度数字化的时代&#xff0c;我们的生活离不开各种电子设备&#xff0c;而充电宝作为保障电子设备续航的重要工具&#xff0c;其地位日益凸显。然而&#xff0c;面对市场上琳琅满目的充电宝品牌和产品&#xff0c;要挑选到一款性价比高的充电宝并非易事。在这篇盘点…

C++20中的指定初始化器(designated initializers)

指定初始化器(designated initializers, 指定初始值设定项)语法如下&#xff1a;C风格指定初始化器语法&#xff0c;初始化数据成员的一种便捷方式 T object { .des1 arg1, .des2 { arg2 } ... }; T object { .des1 arg1, .des2 { arg2 } ... }; 说明&#xff1a; 1.每个指…

2024做TEMU跨境电商,全托管/半托管模式怎么选?

如果说2023年&#xff0c;“全托管”是跨境圈的热词&#xff0c;那2024年一定少不了“半托管”。 自2024年1月&#xff0c;速卖通首次推出半托管模式后&#xff0c;引发了众跨境卖家的热议&#xff1b;而TEMU随后在3月也推出半托管模式&#xff0c;便迅速使得半托管这一模式开始…

盲人出行好帮手:蝙蝠避障让走路变简单

在一片无光的世界里&#xff0c;每一步都承载着探索与勇气。我是众多盲人中的一员&#xff0c;每天的出行不仅是从&#xff21;点到&#xff22;点的物理移动&#xff0c;更是一场心灵的征程。我的世界&#xff0c;虽然被剥夺了视觉的馈赠&#xff0c;却因科技的力量而变得宽广…

Visual Studio 2019 (VS2019) 中使用 CMake 配置 OpenCV 库(快捷版)

2024.07.11 测试有效 最近需要用一下 opencv 处理图像&#xff0c;简单配置了一下Cmake下的 opencv 库。 没有编译 opencv &#xff0c;也不知道他们为什么要自己编译 opencv 。 一、下载并安装 OpenCV 1.前往 OpenCV 官方网站 下载适用于您的系统的 OpenCV 安装包。 2.点击直接…

Java高级重点知识点-23-网络编程

文章目录 网络编程入门软件结构网络通信协议协议分类网络编程三要素 TCP通信程序通信步骤Socket类ServerSocket类简单的TCP网络程序 文件上传【拓展】 网络编程入门 软件结构 C/S结构 &#xff1a;全称为Client/Server结构&#xff0c;是指客户端和服务器结构。B/S结构 &…