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

news2024/9/22 19:43:15

别名《我替你看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.coloradmin.cn/o/1921484.html

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

相关文章

【简历】重庆某一本大学:JAVA简历指导,中厂通过率较低

注&#xff1a;为保证用户信息安全&#xff0c;姓名和学校等信息已经进行同层次变更&#xff0c;内容部分细节也进行了部分隐藏 简历说明 这是一份重庆某一本大学Java同学的简历。那么因为学校是一个一本的学校&#xff0c;就先要确定就业层次在中厂或者大厂&#xff0c;但是…

Zed 编辑器发布了原生 Linux 版本

由 Rust 编写、GPU 加速的 Zed 文本编辑器终于提供了正式的 Linux 原生版本&#xff01;在过去的几个月里&#xff0c;Zed 的 Linux 支持取得了长足的进步&#xff0c;现在已经进入了更正式的阶段。 今天&#xff0c;这款由前 Atom 开发人员创建的现代开源代码编辑器现在在 Li…

算法的几种常见形式

算法&#xff08;Algorithm&#xff09; 算法&#xff08;Algorithm&#xff09;是指解决问题或完成任务的一系列明确的步骤或规则。在计算机科学中&#xff0c;算法是程序的核心部分&#xff0c;它定义了如何执行特定的任务或解决特定的问题。算法可以用多种方式来表示和实现…

如何在小红书上面有效地种草?

文末领取小红书电商开店运营教程&#xff01; 小红书是一个以内容分享为主的社交平台&#xff0c;大家喜欢在这里分享自己的生活体验和心得&#xff0c;其中就包括各种产品的使用感受。 那么我们要想在小红书上有效地种草&#xff0c;首先就需要了解并掌握小红书的种草文化。 …

JavaScript(8)——函数

函数 function,是被设计执行特定任务的代码块。 函数可以把具有相同或相似逻辑的代码包裹起来&#xff0c;通过函数调用执行这些代码&#xff0c;这么做的优势有利于精简代码方便复用。类似于alert(),prompt()和console.log()&#xff0c;这些都是js函数&#xff0c;不过已经…

C++学习书籍推荐

第一本&#xff1a;C Primer CPrimer&#xff1a;主要讲解语法&#xff0c;经典的语法书籍&#xff0c;前后中期都可以看&#xff0c;前期如果⾃学看可能会有点晦涩 难懂&#xff0c;能看懂多少看懂多少&#xff0c;就当预习&#xff0c;中后期作为语法字典&#xff0c;⾮常好⽤…

Android11 SplashScreen 的显示和退出流程

应用的启动到显示到屏幕是需要一定的时间的&#xff0c;为了提升用户的体验&#xff0c;google加入了启动窗口&#xff0c;也就是SplashScreen SplashScreen显示流程 在应用的启动过程中&#xff0c;会调用到ActivityStarter的startActivityInner方法&#xff0c;具体可参考&a…

STM32HAL库+ESP8266+cJSON+微信小程序_连接华为云物联网平台

STM32HAL库ESP8266cJSON微信小程序_连接华为云物联网平台 实验使用资源&#xff1a;正点原子F407 USART1&#xff1a;PA9P、A10&#xff08;串口打印调试&#xff09; USART3&#xff1a;PB10、PB11&#xff08;WiFi模块&#xff09; DHT11&#xff1a;PG9&#xff08;采集数据…

【JavaEE精炼宝库】文件操作(2)——文件内容读写 | IO流

文章目录 一、输入流1.1 InputStream 概述&#xff1a;1.2 read 方法详解&#xff1a;1.3 close 方法&#xff1a;1.4 利用 Scanner 进行读操作&#xff1a;1.5 Reader&#xff1a; 二、输出流2.1 OutputStream 概述&#xff1a;2.2 write 方法详解&#xff1a;2.3 利用 PrintW…

【Sql Server】sql server 2019设置远程访问,外网服务器需要设置好安全组入方向规则

大家好&#xff0c;我是全栈小5&#xff0c;欢迎来到《小5讲堂》。 这是《Sql Server》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 前言1、无法链接…

47、lvs之DR

1、DR模式&#xff1a; 1.1、lvs三种模式&#xff1a; nat 地址转换 DR 直接路由模式 tun 隧道模式 1.2、DR模式的特点&#xff1a; 调度器在整个lvs集群当中是最重要的&#xff0c;在nat模式下&#xff0c;即负载接收请求&#xff0c;同时根据负载均衡的算法转发流量&…

2024 China Joy 前瞻 | 腾讯网易发新作,网易数智携游戏前沿科技、创新产品以及独家礼盒,精彩不断!

今年上半年&#xff0c;CES、MWC和AWE三大国际科技展轮番轰炸&#xff0c;吸引全球科技爱好者的高度关注&#xff0c;无论是新潮的科技产品&#xff0c;还是对人工智能的探索&#xff0c;每一项展出的技术和产品都引起了市场的热议。而到了下半年&#xff0c;一年一度的China J…

springboot商城综合项目自动化系统-计算机毕业设计源码051018

摘 要 目前电商系统商城项目管理极其频繁,迫切地需要自动化测试来代替人工繁琐而又重复的劳动。自动化测试相关的研究已经很多,但多数只是针对某一方面,比如单一接口或者单一页面或者性能等,而缺乏将接口、页面、持续集成系统和缺陷管理系统整合的自动化测试平台。本研究采用混…

ROS——六轴机械臂建模

创建工作空间及目录&#xff08;my_arm&#xff09; 创建launch、urdf文件夹 urdf launch Arm_Model.xacro <?xml version"1.0"?> <robot name"marm" xmlns:xacro"http://www.ros.org/wiki/xacro"><!-- Defining the c…

【Python3】自动化测试_Playwright的安装教程

安装playwright库&#xff1a; pip install playwright 安装内置浏览器&#xff1a; # Install All playwright install# Install chromium playwright install chromium# Install firefox playwright install firefox# Install WebKit playwright install webkit 安装系统…

32.同步FIFO-IP核的调用

&#xff08;1&#xff09;FIFO&#xff08;First In First Out&#xff0c;即先进先出&#xff09;&#xff0c;是一种数据缓冲器&#xff0c;用来实现数据先入先出的读写方式。 &#xff08;2&#xff09;FIFO存储器主要是作为缓存&#xff0c;应用在同步时钟系统和异步时钟系…

深入解析发生 OOM 的三大场景

深入解析 OOM 的三大场景 什么是 OOM&#xff1f;一、堆内存溢出 ( Heap OOM )原因分析解决方案 二、栈内存溢出&#xff08;Stack OOM&#xff09;原因分析解决方案 三、方法区内存溢出&#xff08;Metaspace OOM&#xff09;原因分析解决方案 在Java应用程序开发中&#xff0…

CORDIC Translate

随便记录一下下&#xff1a; Cordic IP核使用说明以及避坑记录-CSDN博客 本次只用到了Translate&#xff0c;记录一下自己遇到的坑坑 实际配置&#xff1a; timescale 1ns / 1nsmodule cordic_tb();reg clk;wire m_axis_dout_tvalid;reg s_axis_cartesian_tvalid 0;wire [31…

三分钟了解什么是消费返利

消费返利作为一种创新的营销手段&#xff0c;不仅增强了消费者的购物体验&#xff0c;还为电商平台及商家带来了更多的用户粘性和复购率。什么是消费返利&#xff0c;其背后的运作机制又是如何的呢&#xff1f; 返利的定义: 返利即是一种消费激励措施&#xff0c;当消费者在指…

网络安全防御 -- 防火墙安全策略用户认证综合实验

实验拓扑&#xff1a; 实验目的&#xff1a; 1、DMZ区内的服务器&#xff0c;办公区仅能在办公时间内(9:00-18:00)可以访问&#xff0c;生产区的设备全天可以访问。 2、生产区不允许访问互联网&#xff0c;办公区和游客区允许访问互联网。 3、办公区设备10.0.2.10不允许访问DM…