短信服务怎么使用API/SDK发送短信
短信服务是阿里云为用户提供的一种通信服务的能力,分为国内短信和国际/港澳台短信服务。本文介绍如何快速使用阿里云OpenAPI开发者门户或阿里云SDK完成常见操作,例如添加短信签名、添加短信模板、发送短信服务和查询短信发送详情等,将指定信息发送至国内或境外手机号码。背景信息调用API时,您可以根据API文档了解使用说明,并查询必选的请求参数。发送请求后报错时,您可以在相应API文档中获取错误码说明。调用方式OpenAPI开发者门户示例:如果您经常使用交互式操作界面,或者您是初次使用阿里云产品的开发者用户,可选用此方式。您可以在OpenAPI开发者门户中调试和获取SDK请求示例,详情请参见阿里云 OpenAPI 开发者门户是什么。Java SDK示例:适用于SDK编码场景。使用升级版Java SDK要求您已提前安装Java 8或以上版本,安装详情请参见安装与使用教程。其他编程语言SDK,请参见短信服务SDK。使用须知使用短信服务前,请了解以下注意事项:仅当短信签名的适用场景为通用时,国内短信和国际/港澳台短信可以共用此签名,无需分别添加。国内短信模板与国际/港澳台短信模板不通用,请根据实际业务情况分别添加、使用。填写签名、模板申请信息时,请正确选择签名适用场景、模板类型,详细描述已上线业务的使用场景,并提供可以验证这些业务的网站链接、已备案域名地址、应用市场下载链接、公众号或小程序全称等信息。对于登录场景,还需提供测试账号密码。信息完善的申请说明会提高签名、模板的审核效率。短信签名和短信模板均需审核通过后方可使用。准备工作注册账号与实名认证。说明实名认证的类型包括个人认证和企业认证。个人认证表示账号持有者是个人、以个人身份使用短信服务;企业认证表示账号持有者是企业或政府部门,以企业身份使用短信服务。个人认证和企业认证可使用的功能不完全相同。更多信息,请参见认证模式。发送推广短信、国际/港澳台短信必须为企业实名认证用户。如果您未注册阿里云账号,请先完成账号注册和实名认证。如果您已有实名认证的阿里云账号,请直接进行下一步操作,开通短信服务。开通短信服务。登录短信服务控制台,勾选开通协议,单击开通服务。获取AccessKey。阿里云访问密钥(AccessKey)是调用API访问云资源的安全口令,支持阿里云账号和RAM用户方式访问。调用API前,您需要先创建AccessKey。具体操作,请参见创建AccessKey。OpenAPI开发者门户示例调用API发送短信的全流程如下所示:API发送短信流程图通过AddSmsSign添加短信签名。通过AddSmsTemplate添加短信模板。分别通过QuerySmsSign、QuerySmsTemplate查看短信签名和短信模板的审核状态。通过SendSms发送短信,您也可以通过SendBatchSms批量发送短信。通过QuerySendDetails查询短信发送详情。短信发送后,通过配置MNS消息队列消费模式和HTTP批量推送模式,可以接收短信发送状态的结果和用户回复的短信内容,帮助您掌握短信的发送成功率,为其他业务提供支持。更多信息,请参见回执消息简介与配置流程。Java SDK示例以AddSmsTemplate为例,演示如何通过阿里云SDK调用短信服务API。示例代码中的下列参数需要您根据实际情况自行填写。AccessKeyId:您的AccessKey ID。AccessKeySecret:您的AccessKey Secret。TemplateType:短信模板类型。TemplateName:短信模板名称。TemplateContent:短信模板内容。Remark:短信模板申请说明。import com.alibaba.fastjson.JSONObject;import com.aliyun.dysmsapi20170525.models.*;import com.aliyun.teaopenapi.models.*;public class AddSmsTemplate {public static com.aliyun.dysmsapi20170525.Client createClient(String accessKeyId, String accessKeySecret) throws Exception {
Config config = new Config()
// 您的AccessKey ID
.setAccessKeyId(accessKeyId)
// 您的AccessKey Secret
.setAccessKeySecret(accessKeySecret);
// 访问的域名
config.endpoint = "dysmsapi.aliyuncs.com";
return new com.aliyun.dysmsapi20170525.Client(config);
}
public static void main(String[] args_) throws Exception {
java.util.List<String> args = java.util.Arrays.asList(args_);
com.aliyun.dysmsapi20170525.Client client = Sample.createClient("accessKeyId", "accessKeySecret");
AddSmsTemplateRequest addSmsTemplateRequest = new AddSmsTemplateRequest()
.setTemplateType(0)
.setTemplateName("content3")
.setTemplateContent("您正在申请手机注册,验证码为:${code},5分钟内有效!")
.setRemark("用于文件下载时的验证码");
// 复制代码运行请自行打印API的返回值
client.addSmsTemplate(addSmsTemplateRequest);
AddSmsTemplateResponse response=client.addSmsTemplate(addSmsTemplateRequest);
System.out.println(JSONObject.toJSONString(response));
}}
ZenUML与服务驱动设计
在《解构领域驱动设计》书中的领域建模阶段,我提出了以业务服务为核心进行设计与建模的方法——服务驱动设计。通过该方法可以在静态的领域设计模型基础之上,以业务服务规约为基础,通过分析需求,对业务服务进行任务分解,获得以子任务构成的任务树。这棵树以业务服务为根,组合任务为枝,原子任务为叶,既体现了业务服务的执行过程,又进行了适度的封装,建立了一定的封装层次。一旦获得了子任务树,即可对树中的每一个子任务进行职责分配,根据其特点分别分配给远程服务、本地服务、领域服务、聚合、端口。它们是构成限界上下文的主要对象角色,我将其称之为“角色构造型”,可以和我提出的菱形对称架构结合:分配的过程可以呈现为序列图,作为动态的领域设计模型,它与静态的领域设计模型共同组成领域设计模型。然则,绘制序列图总是不太方便,于是,我提出了编写序列图脚本的方法。以提交订单业务服务为例,分解获得的子任务树为:根据职责分配的规则,业务服务分配给远程服务与本地服务,组合任务分配给领域服务,原子任务分配给聚合或端口,就可以编写出如下的序列图脚本:
OrderController.placeOrder(placingOrderRequest) { // 业务服务对应远程服务
OrderAppService.placeOrder(placingOrderRequest) {//应用服务的方法体现服务价值
OrderService.placeOrder(order) { // 领域服务对应组合任务,避免领域逻辑泄露到应用服务
OrderService.validate(order) { // 领域服务对应组合任务
Order.validate(); // 聚合承担原子任务
InventoryCheckingClient.check(order); // 客户端端口指向库存上下文的边界服务
}
OrderRepository.save(order); // 资源库端口操作订单数据表
ShoppingCartService.removeItems(customerId,cartItems) { // 领域服务对应组合任务
ShoppingCartRepository.cartOf(customerId); // 资源库端口操作购物车数据表
ShoppingCart.removeItems(cartItems); // 聚合承担原子任务
ShoppingCartRepository.save(shoppingCart); // 资源库端口操作购物车数据表
}
}
OrderPlacedPublisher.publish(orderPlacedEvent); // 发布者端口发布订单已提交的应用事件
}
}序列图脚本的创意并非我的创举,而是ZenUML给予我的启发。我还在ThoughtWorks的时候,我的Sponsor肖鹏正在打磨这款工具。我们二人都认同UML的序列图对于领域建模与设计颇有助力。一方面,序列图这一可视化方式可以提供给设计者一些特征,用于甄别设计的坏味道;另一方面,绘制序列图时,是由外向内逐层递进的,可以更好地站在调用者的角度去思考设计,消息的定义也会产生一种驱动力。我在为GitChat编写领域驱动设计课程时,就想到了这一工具,它提供的脚本语法非常接近Java语法,于是,我就采用拿来主义,将其搬到我的文章里,在融入业务服务、菱形对称架构、角色构造型后,组成了服务驱动设计,其完整过程如下图所示:在《解构领域驱动设计》一书即将出版前,我准备修改针对菱形对称架构提供的一个案例,预备在代码库中增加提交订单的序列图脚本。忽然想起之前与肖鹏交流时,他曾提及ZenUML已经为IntelliJ IDEA开发了插件。果然在Settings -> Plugins中找到了ZenUML的插件:它的使用方式非常简单,在安装了该插件后,你可以在代码库的任意位置(建议在项目根目录下定义一个文件夹),新建一个扩展名为.zen的文件,然后在文件内根据语法编写序列图脚本,工具就可以自动生成序列图了:在上图右上方的View工具栏上,还可以切换视图类型,从左到右依次为:仅显示编辑器:此时只会显示时序图脚本显示编辑器和预览:如上图所示,同时显示时序图脚本和预览的时序图效果仅显示预览:此时只会显示序列图在浏览器中打开如果将ZenUML工具运用到服务驱动设计方法中,即可在领域设计建模阶段尝试通过IDE建模,分析需求后,尝试编写序列图脚本,然后对照生成的序列图对脚本进行调整。调整的成本很低,完全可以随时修订。一旦确定了最终的序列图,即可按照测试驱动开发的流程,优先为聚合承担的原子任务和组合任务编写测试用例,通过测试驱动出该业务服务的实现代码。ZenUML的功能当然不限于此,在驱动出最终的实现代码后,也可以将真实代码转换为序列图。例如在IntelliJ IDEA中,打开已经实现好的远程服务类OrderController,将光标移到要生成序列图的方法体内,右键弹出快捷菜单,即可看到如下的菜单项:选择该菜单项,就会自动生成序列图脚本与对应的序列图,生成的文件为buffer{n}.zen:如果你不喜欢它默认提供的呈现样式,也可以到Languages & Frameworks中找到ZenUML,添加CSS规则,以改变呈现样式:ZenUML除了Web APP之外,还提供了Confluence插件,以便于我们编写设计文档。不出意料之外,它也为主流的浏览器提供了扩展,例如,在Microsoft Edge浏览器中可找到ZenUML Sequence扩展,安装后,工具栏会出现它的图标,打开,即可输入序列图脚本生成序列图:真的是太方便了!ZenUML简直就是为服务驱动设计量身定做的。至于该怎么实践服务驱动设计,在《解构领域驱动设计》书中你可以找到答案。该如何使用ZenUML?那就太简单了,它的脚本语法基本和Java相同,使用也非常简单,无论是通过浏览器还是IDE,实际去使用一下,很快就能理解它的价值。如果你的开发流程和开发工具中需要序列图,也可以直接在系统中把ZenUML作为一个前端库进行集成。目前已经有多家企业在自己的构建流程中集成了ZenUML。某国内企业在构建过程中使用ZenUML在文档中嵌入序列图;某国外企业则开发了Python转ZenUML工具,从代码直接生成序列图。ZenUML的文本转序列图的功能以免费的形式发布在npm上面。ZenUML开发者提供(有限的)免费技术支持。
2022 云原生总结:容器智能化、微服务开源普惠、Serverless 爆发,“用好云”成关键词
如果用两个词来总结 2022 年云原生的发展态势,您会有哪些评价?——繁荣和普惠。“繁荣”代表当前云原生的技术和产品蓬勃发展;“普惠”代表云原生技术从互联网走向金融、零售、政企等行业,普惠千行百业构建丰富应用。(阿里云智能云原生应用平台产品负责人李国强)2022 年,云原生技术日趋成熟,伴随容器、Serverless、微服务等技术快速发展,已逐步构建出繁荣的技术体系。如今云原生凭借降本增效、提高持续交付能力、易于开发等优势,正在不断激活应用构建范式,引起企业系统架构、生产方式、商业模式等发生变革,毋庸置疑,云原生已成为企业数字化转型的最短路径。那么,2022 年云原生领域有哪些新进展?未来我们需要关注云原生哪些发展?对此,在第三届云原生实战峰会期间,阿里云智能云原生应用平台产品负责人李国强接受媒体采访,为我们解读云原生的最新发展与阿里云在云原生领域的最新实践。云原生热门技术发展趋势容器容器作为云原生的代表技术,正在不断重塑云的使用方式。据 Gartner 发布的《全球容器管理预测》中指出,在加速的数字化转型驱动下,更多企业采用基于云的容器管理服务,在 2025 年85% 的大型企业将更多地使用容器管理。今年容器技术依旧发展强劲,李国强观察到容器在云原生 FinOps、云原生大数据、混部、分布式云等拥有良好发展趋势。第一个发展趋势是越来越多的新型负载类型容器化。今年在游戏领域、AI 大数据领域的容器化愈发明显,企业将核心负载运行在容器上,以进行统一的资源调度,帮助企业更好地利用弹性。在混部上,阿里云今年开源了云原生混部项目 Koordinator,它在 K8s 上提供了对编排调度能力的增强,支持针对不同类型的工作负载,资源效率提升100%,实现差异化 SLO 保障,让低优先级的任务对延迟敏感型任务的影响< 5% 。第二个发展趋势是分布式云。企业可基于容器分布式云的方式,来构建线上线下联合的混合云方案,既兼顾了线下利旧兼容,也兼顾到上云效率的提升。2021年 9 月,阿里云容器服务全面升级为 ACK Anywhere,让企业在任何用云的地方都能获得一致的容器基础设施能力。阿里云通过分布式云容器平台 ACK One 和边缘容器服务 ACK@Edge,以覆盖更多企业用云的场景。通过 ACK One 帮助企业构建线上线下统一方案,便捷统一管理应用。能够支持数据中心弹性到公共云,公共云能力下沉到客户数据中心等丰富场景。知名自动驾驶科技公司元戎启行基于 ACK@Edge 将自动驾驶车辆通过边缘容器进行管理,快速覆盖到众多智能车载设备,有效降低管理成本,运维效率提升 60% 以上。阿里云容器服务产品家族已经成为企业的云原生操作系统。基于阿里云容器服务,阿里巴巴实现了100%业务云原生上云。另外,今年云原生 FinOps 发展良好。后疫情时代,如何通过云原生技术帮助企业更好地降本增效,成为摆在云厂商面前的新思考题。阿里云结合业财一体化实践和 FinOps 理念,推出 ACK FinOps 套件,通过数字化手段和智能化方法,帮助企业实现成本可视化、可优化、可控制。在服务网格领域,2022 年 4 月,谷歌提议将 Istio 捐赠给 CNCF,9月 Istio 正式成为 CNCF 孵化项目。更加开放的 Istio 社区治理模式,将会得到更多企业和开发者的支持,推动更多的创新和技术成熟。2022 年,Istio 宣布引入全新的无 sidecar 数据平面模式 Ambient Mesh,通过将数据平面功能从 sidecar 容器转移到网络基础设施来解决常见的操作挑战,可以说Istio 的发展未来可期。阿里云服务网格 ASM 产品,是业内首个全托管 Istio 兼容的服务网格产品,今年,ASM产品获得了首批通过可信云服务网格性能测评先进级认证、排名第一、全项满分。得益于阿里云的大规模容器应用实践,在 2022 年第一季度 Forrester 发布的全球公共云容器平台分析师报告中,ACK 成为比肩 Google 的全球领导者,这也是首次有中国科技公司进入容器服务领导者象限。在CSDN 发布的《2021-2022中国开发者调查报告》中显示,在容器云平台的使用上,有52% 的开发者在使用阿里云,占领先地位。微服务在数字化转型需求的大潮下,企业系统从传统的单体应用走向分布式、更为标准的微服务架构。然而随着分布式微服务发展,微服务框架复杂繁多,系统架构越来越复杂,如何做好微服务治理成为企业关注的问题。今年 4 月,阿里巴巴和 B 站、字节跳动等企业共同发起并开源 OpenSergo 项目。OpenSergo 从微服务的角度出发,涵盖流量治理、服务容错、服务元信息治理、安全治理等关键治理领域,提供一系列的治理能力与标准、生态适配与最佳实践,支持 Java、Go、Rust 等不同语言。李国强表示,上述模式是今年的全新尝试,即通过制定标准、联合更多力量共同推动社区发展,寻找上下游企业和社区的支持。旨在构建一个和语言无关、技术形态无关,贴近业务的统一服务治理规范和实现。另外在云原生网关领域上,由于网关类型众多,传统网关无法满足容器化应用的高弹性等需求,今年 10 月,阿里云开源新一代云原生网关 Higress,遵循 Ingress/Gateway API 标准,将流量网关、微服务网关、安全网关三合一,在一个网关上解决多个网关的问题,大大简化用户在网关体系上的复杂度。自发布一个多月以来,已有 700 个 Star,社区活跃度较高。可观测云原生时代,企业所面临的 IT 运维环境愈发复杂,对企业的运维能力提出高度挑战,一套全面的观测性系统极为关键。然而以往在可观测领域里,存在标准不一、数据存储分散等问题。伴随 OpenTelemetry、Prometheus、Grafana 等逐步成为事实标准,越来越多企业开始基于这些开源标准构建可观测体系。基于以上趋势,阿里云发布了云原生可观测套件 ACOS,形成指标存储分析、链路存储分析、异构构数据源集成的可观测数据层,同时通过标准的 PromQL 和 SQL,提供数据大盘展示,告警和数据探索能力。李国强表示,不同行业对可观测的诉求不同,例如在互联网行业,主要以公共云为主,在构建可观测时希望与开源体系相匹配,企业自主选择适合的产品来构建相关技术体系;在政企行业,对一站式服务可观测体系的诉求较多,而云原生可观测套件 ACOS 可以一站式提供数据采集、数据存储、数据展示、告警处理等功能。值得一提的是,在本次云原生实战峰会上,阿里云云原生可观测套件ACOS 发布了可观测集成中心 2.0升级,目前已支持 50+款云服务和技术组建指标观测的一键集成,ECS/ACK/EDAS 等部署应用零改造观测集成,观测接入效率提升超过 20%。Serverless当前,Serverless 加速重塑应用架构和研发模式,云上研发方式正在发生根本性变革。Serverless提供众多预制模块,大大降低软件开发门槛,提高软件生产效率,开发者在云上高效进行研发、运维、部署。为帮助企业和开发者更轻量灵活地用云,实现业务敏捷创新,今年阿里巴巴确立了以“云原生”作为集团整体技术架构的战略,阿里云更是对外宣布核心产品全面 Serverless 化,致力让企业和开发者用云就像用电一样简单。截止发稿,阿里云已有 20 多项核心服务实现了 Serverless 化,未来将全面推进整体产品体系的 Serverless 化。谈及今年 Serverless 的火热发展,李国强表示,Serverless 的理念、能力以及市场的覆盖率仍处于持续上升阶段,远远没有达到真正的顶峰。今年市场对它的认知逐渐趋于成熟,越来越多人开始应用 Serverless 架构,有非常多的应用适合演进到Serverless架构。今年是国内 Serverless发展的元年,相信未来几年,Serverless 将逐步迭代演进、实现大规模落地。全面云原生深度用云,降本增效的绝佳利器后疫情时代,企业在开展数字化转型时面对前所未有的挑战:一是在大环境下,今年企业对“降本增效”的诉求强烈。二是伴随疫情防控政策变化,专家预测明年经济可能会快速复苏。企业需要重新审视其 IT 系统是否足够健壮以面对未来的业务陡增;另外市场的快速变化将带来新的商机,企业自身的数字化能力是否足够敏捷以应对业务的快速变化?云原生正在激活应用的构建方式,帮助企业在竞争中脱颖而出。云原生以高弹性、流量治理、高可用的优势帮助用户构建健壮的、具有弹性的应用,以面对业务流量突增等变化。同时,云原生基于标准的构建发布流程,用户可以敏捷地进行产品发布来应对日新月异的市场需求。在降本增效上,以阿里巴巴为例,依靠强大的技术能力,通过全面云原生深度用云,同时阿里巴巴也享受云上研发带来的技术红利,来实现降本增效。在2022年双 11 中,阿里云结合业财一体化实践和 FinOps 理念,从统一调度混部到全面 FinOps 实践,以单位算力 TCO 来衡量,相比2021年双 11,单位算力成本 TCO 下降 8%。回顾阿里巴巴上云历程,从 2019 年的核心系统上云,到 2020 年的全面云原生化,再到 2021 年阿里 100% 业务全面上云,如今已进入云原生化的深度用云阶段,据官方数据披露,今年阿里集团在 PaaS 支持的业务形态中支出占用云总成本达 43%。以上也是企业上云用云的典型历程:在初级用云阶段,企业用云从最基础的 IaaS 层开始,将原来 IDC 搬到云 IaaS 层,在 PaaS 层仍存在大量自建技术,企业需要一支专业的运维团队来负责构建 PaaS 层产品能力,主导产品演进。随着用云程度的深入,用户意识到云 PaaS 层已提供足够强大的产品能力,用户只需将自己的精力放在业务本身即可,于是企业用云逐渐从 IaaS 层覆盖到 PaaS 层,如此一来,PaaS 层用云的占比变高了,同时技术人力投入降低。在深入用云的过程中,IT 投入总成本也在逐年降低,充分释放云原生红利,最终反哺到业务,让云原生助力企业最终实现降本增效。坚持云原生开源,构筑开放融合生态体系要想云原生技术、生态持续发展,光靠一家企业是不足够的,开源对云原生发展有着至关重要的促进作用,一直以来,阿里云不留余力地为云原生开源做贡献:2018年,阿里云提出“云原生三位一体”理念,将自研技术、开源项目、商业产品形成统一的技术体系,积极参与打造一个开放、标准、健康良性的云原生技术生态。截止目前,由阿里云主导发起、参与的云原生开源项目已有 30+,其中包括 13 个 CNCF 项目,2 个 Apache 顶级项目,目前积累 2000+贡献者,27 万Star,覆盖全球 100 万+开发者。在 2022 年 CNCF 开发者协作影响力排名中 ,阿里云位列全球第二,仅次于谷歌。数据来源:X-lab 开放实验室/木兰开源社区 OpenDigger 项目过去,阿里云发起并捐赠了 KubeVela、OpenYurt、Fluid、OpenKruise、sealer、ChaosBlade、ServerlessDevs、OCM 等多个项目均已进入 CNCF,覆盖应用交付管理、边缘计算、多云混合云、混部等领域。据中国互联网发布的《中国互联网发展报告(2022)》,在云计算领域,2021年云计算市场保持高速发展,整体市场规模达到 1781 亿元,增速超 33%。云计算市场庞大,企业需求多样,阿里云期待携手各方“以生态为先”的策略,构建开放、融合的云原生生态体系,助力千行百业数字化转型。阿里云通过构建转售生态、产品生态、服务生态三大体系构筑开放融合的伙伴生态。在转售生态上,通过和创云、青莲、乘云科技、华讯网络等伙伴合作,推动更多企业使用云原生产品技术,实现数字化创新;在产品生态上,一是通过丰富全面的云原生产品,服务好 SaaS和 ISV 厂商,形成联合解决方案。今年,阿里云与鼎捷软件、大海科技打造了工业领域的联合解决方案,以更好地服务制造业客户,提升企业智能制造的水平;二是通过和产品生态的合作,引入优秀的产品,与阿里云现有产品体系进行融合,提供更全面的云原生解决方案。目前,阿里云与谐云、行云创新、袋鼠云等生态伙伴已开展深度合作。在服务合作上,与浩鲸、软通动力等合作,基于云原生的技术和解决方案,贴身服务企业客户,以满足不同的服务诉求。开发者如何迎接云原生时代?据 CSDN 2021 年数据统计,在 3200 万 CSDN 注册用户中,阅读和研究云原生技术的开发者已经达到了 406 万。云原生已成为必然发展趋势,开发者们如何全面拥抱?李国强建议,对于运维人员来说,在技术上,学习和采用更多的容器、Serverless 云原生技术来帮助企业降低 IT 成本。在思维上,从技术思维逐渐向业务思维发展,今年FinOps理念深入到企业里,运维开发人员可结合FinOps理念,从原有关注业务的稳定性到关注业务的健康度,以更稳定高效地创造业务价值。对于应用开发人员来说,下一代应用开发人员是“长”在云上的开发人员,是云原生的应用开发者。目前有些开发人员尚未形成云原生开发的工作习惯,仍采用线下开发完代码后部署到云上运行的方式, 下一步应用开发人员需改变原有的思维模式,学习事件驱动架构(EDA)、组装式编程、Serverless架构等知识,及时关注云上应用开发模式和相关的应用框架、编程模式。点击此处,了解更多峰会资讯~
【数组指针与函数指针】
前言数组指针和函数指针都是C语言比较难的知识点,尤其是函数指针,并且函数指针在开发中有着巨大的作用。函数指针语法定义一个函数指针,并通过函数指针间接调用函数:int get_num(int a, int b)
{
return a + b;
}
int (*func)(int a, int b); //定义了一个函数指针func,它指向 返回值为int 参数为 int a, int b的函数
func = &get_num; //函数指针指向函数
func(1, 2); //通过函数指针调用函数通过定义一个函数指针类型来定义一个函数指针:typedef int (*func)(int a, int b); //定义了一个函数指针类型
func func1 = &get_num; //使用函数指针类型func定义函数指针变量func1定义一个函数类型,并使用函数类型来定义一个函数指针typedef int (func)(int a, int b); //定义了一个函数类型
func* func1 = &get_num;
func1(1, 1); //间接调用函数指针约定了函数的返回值和函数参数,功能开发者只要根据这个约定实现功能函数,就可以通过以函数指针为参数的统一接口进行调用,来使用这个函数的功能,实现了功能开发与功能使用的解耦合。这就是函数指针的巨大作用:函数指针做函数参数具体函数指针做函数参数的应用详解请看我的另一篇文章:回调函数另外函数指针的正向调用使用场景,比如通过把动态库加载到程序中,在动态库中查找到函数入口地址来调用函数。数组指针与指针数组数组指针是指向数组的指针;指针数组是指针的数组。数组指针举例#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void PrintArray_int(int* array, int len)
{
if ((NULL == array) || (len < 0))
{
printf("err:(NULL == array) || (len < 0)\n");
return;
}
for (int i = 0; i < len; i++)
{
//两种方法访问数组元素
//printf(" %d ", array[i]);
printf(" %d ", *(array + i));
}
printf("\n");
}
int main()
{
//定义一个数组变量
int num_array[10];
// num_array + 1 移动 sizeof(int) 个字节
int len = sizeof(num_array) / sizeof(num_array[0]);
//memset(num_array, 0, sizeof(num_array) / sizeof(num_array[0])); //典型错误,只把十个字节的内存值为0
memset(num_array, 0, sizeof(num_array)); //实际应该把40个字节置为0
PrintArray_int(num_array, sizeof(num_array) / sizeof(num_array[0]));
//定义一个数组类型
typedef int(array1_t)[];
typedef int(array2_t)[10];
array1_t a1 = {1, 2, 3};
array2_t a2;
for (int i = 0; i < 10; i++)
{
a2[i] = i;
}
PrintArray_int(a1, sizeof(a1) / sizeof(a1[0]));
PrintArray_int(a2, 10);
//定义一个数组指针
int(*p_array)[10];
// p_array + 1 移动 sizeof(int) * 10 个字节
p_array = &num_array;
for (int i = 0; i < 10; i++)
{
(*p_array)[i] = i + 1;
}
PrintArray_int(*p_array, 10);
//定义一个指向数组的指针类型(数组指针)
typedef int(*p_array_t)[10];
p_array_t p1 = &num_array;
for (int i = 0; i < 10; i++)
{
(*p1)[i] = i + 2; //先解引用,还原为一级指针(数组本身可以看为一级指针
//数组指针是指向数组的指针,也就是指向一级指针的指针,即二级指针)
}
PrintArray_int((*p1), 10);
//指针数组
const char* p2[2] = { "aaa", "bbb" };
//p2[0] 和 p2[1] 都是一个指针
printf("%s\n", p2[0]);
printf("%s\n", p2[1]);
system("pause");
return 0;
}
Apache RocketMQ 入选 SegmentFault 年度中国技术品牌影响力企业榜单!
回首这一年,数字经济的蓬勃发展,风云变幻的市场环境下众多企业与个人的卓绝奋斗。SegmentFault 思否作为中国领先的新一代开发者社区,依托数百万开发者用户数据分析,及各科技企业和个人在国内技术领域的行为、影响力指标,推出了 “中国技术先锋” 年度评选。其中,Apache RocketMQ 社区入选中国技术品牌影响力企业榜单!非常荣幸成为推动社会创新的 “先锋力量”,社区将在 2023 年再接再厉,积极输出优质技术内容、坚持产品创新、为开发者创造价值和便利,和全体社区成员一起持续促进 Apache RocketMQ 项目和社区的发展!作为主流的分布式消息中间件,RocketMQ于 2012 年开源,并在 2017 年正式成为 Apache 顶级项目,持续迸发出旺盛的生命力。伴随着云原生时代的到来以及实时计算的兴起, 生于云、长于云的 RocketMQ 5.0 应运而生,全新升级为云原生消息、事件、流融合处理平台,帮助用户更容易地构建下一代事件驱动和流处理应用。RocketMQ 5.0 专注于消息基础架构的云原生化演进,聚焦在消息领域的后处理场景,支持消息的流式处理和轻计算,帮助用户实现消息的就近计算和分析,并全面拥抱 Serverless 和 EDA。在技术迎来重要革新的同时,回顾 Apache RocketMQ 社区这些年的成长历程。目前,全球 Apache RocketMQ Contributors 700+,促进整个社区长期和健康发展。同时,为了帮助社区开发者更好地找到感兴趣的技术方向,快速参与到社区并推动相关特性优化的快速演进,RocketMQ 还成立内核、批处理、Connect、Streaming、多语言客户端、RocketMQ-Flink、Operator、Exporter 等不同兴趣小组。为更好聚集本地开发者,我们在北京、深圳、苏州等城市相继成立当地社区,定期举行线下活动,共同讨论 RocketMQ 相关的落地实践与新特性需求,大量创新从社区的各类活动中产生并且落地。除此之外,RocketMQ 还非常重视社区间的合作,先后与 Apache DolphinScheduler,Apache Hudi 等社区组织了多次联合 Meetup,在打造 RocketMQ 上下游生态的同时,也为不同社区开发者近距离讨论提供了平台。在社区成员以及众多的开发者共同推动下,全球超过数万家企业在使用 Apache RocketMQ,这其中不仅有字节跳动、快手、小米、滴滴、同城艺龙等互联网头部企业,还有众多银行、券商、保险,基金公司等金融公司。经过多年发展,RocketMQ 已成为微服务领域业务消息首选。本次获奖离不开全体社区成员的共同努力,是全体社区成员的共同荣誉!社区将再接再厉,不忘初心,持续促进 Apache RocketMQ 项目和社区的发展。加入 Apache RocketMQ 社区十年铸剑,Apache RocketMQ 的成长离不开全球 700+ 位开发者的积极参与贡献,相信在下个版本你就是 Apache RocketMQ 的贡献者,在社区不仅可以结识社区大牛,提升技术水平,也可以提升个人影响力,促进自身成长。社区 5.0 版本正在进行着如火如荼的开发,以及 30 +个 SIG(兴趣小组)等你加入,欢迎立志打造世界级分布式系统的同学通过以下方式加入社区:微信搜索:「rocketmq666」,添加开发者微信,即可加入微信群;钉钉搜索:「21982288」,即可加入钉群。微信扫码添加小火箭进群
基于多分辨率奇异值分解的图像融合技术附matlab代码
作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。🍎个人主页:Matlab科研工作室🍊个人信条:格物致知。更多Matlab仿真内容点击👇智能优化算法 神经网络预测 雷达通信 无线传感器 电力系统信号处理 图像处理 路径规划 元胞自动机 无人机 ⛄ 内容介绍 一种新颖的基于多分辨率奇异值分解的图像融合技术(MSVD)提出和评估。这个算法的性能比较与众所周知的图像融合使用小波技术。它是由MSVD观察到图像融合执行几乎类似的小波。它是计算非常简单,它可以适合实时应用程序。此外,MSVD不有一组固定的基向量FFT、DCT和小波等及其基向量取决于数据集。⛄ 部分代码function[x] = IMSVD(Y,U)% inverse MSVD (IMSVD)% Inputs-> Y: MSVD coefficients & U: unitary matrix (U in SVD)% output-> x: image (spaitial domain)[m,n] = size(Y.LL);mn = m*n;T = zeros(4,mn);T(1,:) = reshape(Y.LL,1,mn);T(2,:) = reshape(Y.LH,1,mn);T(3,:) = reshape(Y.HL,1,mn);T(4,:) = reshape(Y.HH,1,mn);A = U * T; x = zeros(m*2,n*2); for j = 1:n for i = 1:m x((i-1)*2+(1:2), (j-1)*2+(1:2)) = reshape(A(:,i+(j-1)*m),2,2); endend⛄ 运行结果⛄ 参考文献⛄ 完整代码❤️部分理论引用网络文献,若有侵权联系博主删除❤️ 关注我领取海量matlab电子书和数学建模资料
匹配滤波增益matlab仿真附报告
作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。🍎个人主页:Matlab科研工作室🍊个人信条:格物致知。更多Matlab仿真内容点击👇智能优化算法 神经网络预测 雷达通信 无线传感器 电力系统信号处理 图像处理 路径规划 元胞自动机 无人机 ⛄ 内容介绍根据雷达原理,匹配滤波系统输出信号比输入信号幅度增大倍。但是,在实际仿真过程中发现幅度增益与理论值不一致。这是因为该结论是在输入信号为模拟信号,并且将匹配滤波器的频谱归一化的前提下得出的。仿真中的信号是经过采样的数字信号,匹配滤波器的频谱也没有进行归一化。根据采样理论,一个连续信号经采样后,采样信号的频谱幅度变为原信号频谱的Fs倍。回波信号和匹配滤波器分别进行傅里叶变换,相乘后再经过逆傅里叶变换,幅度总共比采样前增加Fs倍。未经归一化的模拟匹配滤波器的幅度为。所以,脉压后幅度增加为。⛄ 部分代码%% *****************模拟回波带fd的原理**********************clear allclcclose allFs = 10e6; %脉冲周期倒数Bw = 30e6;%调频带宽30MHzpolar = 1;fd = 0;pulseNum = 16;Pw = 100e-6;PRT = 500e-6;prtPointNum = PRT * Fs;pwPointNum = Pw * Fs; % 噪声增益计算 Gs(i, 1) = dpcsignalAmp/signaAmp; Gn(i, 1) = dpcNoiseAmp/NoiseAmpBeforeDpc; SNR0(i, 1) = db(signaAmp/NoiseAmpBeforeDpc); SNR1(i, 1) = db(dpcsignalAmp/dpcNoiseAmp); Gsnr(i, 1) = SNR1(i, 1) - SNR0(i, 1); figure(10) x = 1 : prtPointNum; subplot(3, 1, 1) plot(x, abs(signal_td_matrix(:, 1)), '-b') grid xlabel('t/s'); ylabel('幅度'); title('LFM信号real part'); subplot(3, 1, 2) f = linspace(-Fs/2, Fs/2, Nfft) ./ 1e6; % 单位换算成MHz dpcSys = fftshift(conj(fft(replica_matrix, Nfft))); % 滤波器系统函数 plot(f, abs(dpcSys(:, 1)), '-b') xlabel('w/hz'); ylabel('幅度'); title('经过匹配滤波器后的频谱'); grid subplot(3, 1, 3) plot(x, echoPcMod(:, 1), '-b') grid title('脉压信号幅度')endGsnr_avr = mean(Gsnr);figure(1)plot(Gsnr),xlabel('运行次数')ylabel('Gsnr(dB)')title(['SNR增益均值:', num2str(Gsnr_avr)])grid on⛄ 运行结果⛄ 参考文献⛄ 完整代码❤️部分理论引用网络文献,若有侵权联系博主删除❤️ 关注我领取海量matlab电子书和数学建模资料
软件架构编年史:包和命名空间
一个系统的架构是它的高层级的视图,是系统的大局观,是粗线条的系统设计。架构的决策就是系统结构上的决策,这些决策影响着全部代码,决定了系统中其它部分的基础。除了其它用处以外,架构决定了系统的:组件组件之间的关系指导对组件以及及其之间关系进行设计和演进的原则换句话说,这些设计决策在系统演进的过程中更难改变,它们是支撑特性开发的基础。◐ 意大利面架构我参与的有些项目结构完全是随意的,又不能体现架构也不能反映领域。如果我的问题是“这个值对象应该放在哪里?”,答案就是“随便放在 src 目录里就好了”。如果我的问题是“完成这个逻辑的服务在哪里”,答案是“用 IDE 搜索吧”。这意味着完全没有思考该如何组织代码。这里的隐患很大,因为完全没有使用包来实现模块化,高级别的代码关系和流向完全不遵守任何逻辑结构,将导致高耦合低内聚的模块,实际上可能根本就没有模块划分,本来应该属于某个模块的代码散落在整个代码库中。这样的代码库就是所谓的意大利面代码,或者是意大利面架构!◐ 可维护的代码库拥有可维护的代码库意味着我们能以最小的代码修改获得最大的概念变化。换句话说,如果我们需要修改一个代码单元,其它代码单元的修改应该尽可能地少。这带来了明显的优势:因为影响的代码少,修改会更容易;因为影响的代码少,修改会更快;因为修改的代码少,出现问题的几率会降低;封装 、低耦合和高内聚是保持代码隔离的核心原则,使可维护的代码库成为可能。封装封装是隐藏一个类的内部表示和实现的过程。也就是说,实现被隐藏了,这样类的内部结构可以随意的改变,而不会影响使用这个类的其它类的实现。低耦合耦合涉及代码单元之间的关系。如果一个模块的修改会导致另一个模块的修改,我们就说这两个模块高度耦合。如果一个模块可以独立于其它任何模块,我们就说它是松耦合的。通过提供稳定的接口来有效地对其它模块隐藏实现,可以达成松耦合的目标。低耦合的优点可维护性 - 修改被限制在一个模块中可测试性 - 单元测试涉及的模块尽可能地少可读性 - 需要仔细分析的类尽可能地少高内聚内聚指的是对模块内的功能相关性有多强的度量。低内聚指的是模块拥有一些不同的不相关的职责。高内聚指的是模块所拥有的功能在许多方面很相似。高内聚的优点可读性 - (紧密) 相关的功能包含在一个模块中可维护性 - 只用在一个模块内调试代码可重用 - 类的功能十分聚焦,不会充斥许多无用的函数◐ 对结构的影响上述这些原则适用于类,然而,它们一样适用于类的组合。类的组合通常被叫做包,但我们可以分得更细一些,如果分组是出于纯粹功能方面的考虑(如ORM)我们会称之为模块,如果是出于领域方面的考虑(如AccountManagement)则称之为组件。这些定义与 Bass、Clements 和 Kazman 在他们的著作 Software Architecture in Practice 里的描述一致。我们能够并且应该让包做到高内聚和低耦合,因为这样我们才能做到:修改一个包而不会影响其它的包,减少出现的问题;修改一个包而不需要修改其它的包,加快交付的节奏;让团队专注于特定的包,带来更快、更健壮和设计更优的变化;团队开发活动之间的依赖和冲突更少,提升产能。更仔细地斟酌组件之间的关系,让我们更好地将应用作为一个整体建模 ,交付质量更高的系统。◐ 概念封装我觉得如果我们的项目结构能以某种方式既体现出架构也体现出领域的话,我们的代码库的可维护性可以得到极大地提升。实际上现在我敢笃定这也是唯一可行的方式(当我们面对大中型企业应用时)。代码库如果组织得当,特定代码单元只有一处位置可供它存放。我们可能并不知道到具体的位置,但一定只有一条逻辑路径可以让我们顺藤摸瓜找到它。包的定义将类划分成包可以让我们在更高的抽象级别来思考设计。其目标是将你的应用中的类按照某种条件进行分片,然后将这些分片分配到包中。这些包之间的关系表达出了应用高级别的组织方式。—— Robert C. Martin 1996, Granularity pp. 3将概念上相关的代码定义成包,我们需要达成的目标。这些包十分重要,因为它们定义了概念上相关且独立于其它包的代码单元,还有这些包之间的关系。这样做的目的是:理解代码单元之间的关系维护代码单元之间的逻辑关系实现高内聚低耦合的代码包在不影响/极少影响应用的情况下重构代码包在不影响/极少影响应用的情况下替换代码包的实现◐ 分包的原则我们要遵循 Robert C. Martin 在 1996 年和 1997 年提出的包划分原则以及其他的一些原则来达成目标,主要有 CCP (Common Closure Principle,共同封闭原则), the CRP (Common Reuse Principle,共同重用原则) 和 SDP (Stable Dependencies Principle,稳定依赖原则)。Robert C. Martin 提出的包划分原则:包内聚原则REP – 重用发布等价原则:重用的粒度等价于发布的粒度CCP – 共同封闭原则:一起被修改的类应该放在一个包里CRP – 共同重用原则:一起被重用的类应该放在一个包里包耦合原则ADP – 无环依赖原则:包的依赖图中不能出现循环SDP – 稳定依赖原则:依赖应该朝着稳定的方向前进SAP – 稳定抽象原则:抽象的级别越高,稳定性就越高要想合理地运用 SDP,我们应该定义出代码的概念单元(组件)和组件的分层,这样我们才能搞清楚那些组件应该了解(依赖)其它组件。然而,如果这些组件的边界不够清晰,我们就会把本该互不相干的代码代码单元混在一起,让它们耦合在一起变成意大利面式代码,最后将无法维护。要让这些边界能清楚地呈现出来,我们需要把概念上相关的类放在同一个包中,就像我们把概念上相关的方法放在同一个类中一样。在包这个级别,我们只能用一些名字在领域中有一定含义(例如,UserManagement、Orders、Payments 等)的文件夹来区分它们。在最底层的级别,即包内的叶子节点,我们才会在必要时按照功能作用区分类(例如,Entity、Factory、Repository 等)。下面这个问题可以帮助我们反思如何设计出低耦合的组件:“如果我想去掉一个业务概念,是不是删除掉它的组件根目录就能把这个业务概念的所有代码删除而且应用的剩余部分还不会被破坏?”如果答案是肯定的,那么我们就有了一个解耦得不错的组件。例如,在命令总线架构中,命令和处理器离开对方就无法工作,它们在概念上和功能上都绑定在一起,因此,如果我们需要去掉该逻辑就要将它们一起去掉。如果它们在同一个位置,我们只用删除一个文件夹就好(我们并非真的要删除代码,只是借助这种思维方式来帮我们得到解耦和内聚的代码)。所以,遵循 CCP 和 CRP 原则,命令应该和它的处理器放在同一个文件夹中。任何代码只能存在于一个逻辑上的位置,即使对项目中的新手和初级开发者来说,这个位置也是十分明了的。这能避免自相矛盾、令人费解、重复的代码和开发者的挫败感。如果因为无法在代码本该在的位置找到它,和/或难以理解哪些代码和手头上正在处理的代码有关,而导致我们需要去搜寻这些代码...那么我们的项目结构就很糟糕,甚至是更坏的情况,架构很糟糕。◐ 尖叫架构尖叫架构是 Robert C. Martin 的想法,它基本上表明了这样一个观点,架构应该清楚地告诉我们系统是做什么的:即它的主要领域。那么源代码文件夹里出现的第一级目录自然就应该和领域概念有关,即最顶层的限界上下文(例如,患者、医生、预约等)。它们应该和系统使用的工具(例如,Doctrine、MySQL、Symfony、Redis 等)无关,和系统的功能块(例如,资源库、制图、控制器等)无关,和传达机制无关(HTTP、控制台等)。你的架构应该呈现给人的应该是系统,而不是系统使用的框架。如果你构建的是一个医疗保健系统,那么新程序员看到源代码仓库后的第一映像应该是:“哦,这是一个医疗保健系统”。—— Robert C. Martin 2011, Screaming Architecture这实际上是一种更简单地理解他十五年前发表的包划分原则的方法,这些原则之前我已经阐述过了。这种分包的风格又叫做“按特性分包”。◐ 延伸阅读2008 – Johannes Brodwall – Package by feature2012 -Johannes Brodwall – How Changing Java Package Names Transformed my System Architecture2012 – sivaprasadreddy.k – Is package by feature approach good?2013 – Lahlali Issam – Lessons to Learn from the Hibernate Core Implementation2013 – Manu Pk – Package your classes by Feature and not by Layers2015 – Simon Brown – Package by component and architecturally-aligned testing2015 – César Ferreira – Package by features, not layers2017* – javapractices.com – Package by feature, not layer◐ 引用来源1996 – Robert C. Martin – Granularity1997 – Robert C. Martin – Stability2009 – 500internalservererror – What do low coupling and high cohesion mean? What does the principle of encapsulation mean?2011 – Robert C. Martin – Screaming Architecture
软件架构编年史:MVC及其变种
创建可维护的应用始终是构建应用的真正的长期挑战。不久以前,我还为一家公司工作过,其核心业务应用是拥有数千家公司客户的 SaaS 平台。这个至关重要的应用已经开发了三年,代码文件中混杂着 HTML、CSS、业务逻辑和 SQL。果然,在发布两年之后,公司决定完全重写这个应用。尽管这些情况时有发生,但如今我们许多人都知道这是不对的以及该如何避免。然而,在20世纪70年代,职责混杂还是常见的实践,人们还在寻找更好的解决办法。随着应用程序复杂度的增长,修改 UI 必然也会引起业务逻辑的修改,修改越发复杂,耗费的时间也越来越多,还可能带来更多的问题(因为修改的代码更多了)。MVC 因此应运而生,它提出前端和后端之间的“关注点分离”来解决上述问题。◐ 1979 – Model-View-Controller为了解决上述问题,Trygve Reenskaug 于1979 年提出了 MVC 模式来分离关注点,将 UI 和业务逻辑隔离。该模式当时被应用于1973 就已经出现的桌面图形界面的开发。MVC 模式将代码拆分成了三个概念单元:代表业务逻辑的 Model (模型);代表 UI 控件的 View (视图):按钮、文本框等等;在视图和模型之间居中协调的 Controller(控制器),这意味着:它决定显示哪些视图以及哪些数据;它将用户操作(例如点击按钮)转换成业务逻辑。模型可以是单个对象(相当无趣),也可以是对象组成的某种结构。——Trygve Reenskaug 1979, MVC最初的 MVC 模式还有其它一些需要了解的的重要概念:View 直接使用 Model 数据对象来展示数据;当 Model 发生变化时,会触发一个事件立即更新 View(记住,1979年还没有 HTTP);每一个 View 通常只关联一个 Controller;每个界面可以包含多对 View 和 Controller;每个Controller 可以对应多个 View。现在我所熟知的 HTTP 请求响应范式并没有使用最初的 MVC 风格。这是因为,按照原始的设想,数据从 View 流向 Controller,这和我熟悉的一样,但另一边,数据直接从 Model 流向 View,并没有经过 Controller。而且,在现在的请求响应范式中,当数据库中的数据发生变化时,并不会触发浏览器中展示 View 的更新(尽管可以用 Web Socket 实现)。要看到更新后的数据,用户需要发起一次新的请求,而更新的数据总是会通过 Controller 返回。◐ 1987/2000 – PAC/Hierarchical Model-View-ControllerPAC 又称 HMVC,在 UI 片段控件化的上下文中它能带来更好的模块化拆分。例如,我们会发现 View 的一部分被其它一些 View 以同样的格式使用,甚至直接就在同一个 View 重复使用。一个实际的例子就是网页展现 RSS 订阅内容的片段,它可以被其它页面重用。如果使用 HMVC,处理主请求的 Controller 会将子请求转发给其它 Controller 让这些控件进行渲染,然后在主 View 的渲染中合并它们。在 HTTP 请求/响应范式的上下文里,我自己也曾遇到过几次这种情况,但我发现了一个更简单的方法,即让 UI 向可以渲染控件的 Controller 发起 AJAX 调用。在保持模块化优势的同时并没有增加嵌套 Controller 调用带来的复杂性,另一个优势就是这些子请求可以使用像 Varnish 这样的缓存。◐ 1996 – Model-View-PresenterMVC 模式给当时的编程范式注入了一剂强心针。然而,随着应用程序复杂度的增加,需要更进一步地解耦。1996 年,IBM 的子公司 Taligent 公开了他们基于 MVC 的 模式 MVP。其思想是将 Model 对 UI 的关注更彻底地分离:View 是被动的,对 Model 无感知;专注于轻量 Controller(Presenter),它们不包含任何业务逻辑,只是简单地调用命令和/或查询模型,将原始数据传递给 View;数据的变化不会直接触发 View 的更新:它始终要通过 Presenter,由 Presenter 来更新 View。这样在更新视图之前 Controller(Presenter) 还可以执行一些和展现相关的额外逻辑。例如,同时更新另一些数据,它们和数据库中发生变化的数据有关;每个 View 对应一个 Presenter。这更接近我所见到的现在的请求/响应范式:数据流始终要经过 Controller/Presenter。不过,Presenter 仍然不会主动更新视图,它始终需要执行一次新的请求才能让变化可见。MVP 中的 Presenter 又被称为 Supervisor Controller。◐ 2005 – Model-View-ViewModel由于应用程序的复杂性还在增加,2005 年微软的 WPF 和 Silverlight 架构师 John Gossman 又提出了 MVVM 模式,目标是进一步将 UI 设计从代码中分离出来,并提供 View 到数据模型的数据绑定机制。[MVVM] 是 [MVC] 的变种,专为现代 UI 开发平台设计。现代 UI 开发中,View 是由设计师负责而不是由传统意义上的开发者负责。[…] 开发应用程序 UI 使用的工具、语言以及使用它们的人都和业务逻辑以及数据后端有着天壤之别。——John Gossman 2005, Introduction to Model/View/ViewModel patternController 被 ViewModel “取代”:[View] 对键盘快捷键进行编码,而且控件自行管理与输入设备的交互,这本该是 MVC 中的 Controller 的职责(现代 GUI 开发中 Controller 的变化说来话长...我认为它只是淡出了开发者的实现。它始终都存在着,而我们不需要像1979年那样去思考它)。——John Gossman 2005, Introduction to Model/View/ViewModel patternMVVM 背后的思想是:ViewModel 和 View 一一对应;将 View 中的逻辑转移到 ViewModel 来简化 View;View 使用的数据和 ViewModel 中的数据一一对应;将 ViewModel 中的数据绑定到 View 中的数据上,这样 ViewModel 中数据的变化会立即体现在 View 上。和最初的 MVC 模式的情况相仿,对传统的请求/响应范式来说这种方法是行不通的,因为 ViewModel 无法主动地更新 View(除非使用 Web Socket),而 MVVM 对这一点是有要求的。还有,根据我的经验,ViewModel 的属性和 View 使用的数据做到完全匹配并不是 Controller 的常见实践。◐ Model-View-Presenter-ViewModel当构建云原生的复杂企业应用时,我倾向于将应用的 UI 结构合理地设计成 M-V-P-VM,这里的 View Model 是 Martin Fowler 在 2004 年提出的 Presentation Model,。Model一组包含业务逻辑和用例的类。View一个模板,模板引擎用它来生成 HTML;ViewModel(又叫做 Presentation Model)从查询中接收(或者从 Model 实体中提取)原始数据,持有这些会模板会用到的数据。它还要封装复杂的展现逻辑,来简化模板。我发现运用 ViewModel 十分重要,因为我们绝不会想在模板中使用实体。这样我们才能将 View 和 Model 完全隔离开:Model 中的变化(比如实体结构的变化)会上升并影响 ViewModel,但不会影响模板;复杂的展现逻辑被封装到了 ViewModel 之中,因此不会被泄露(例如,在业务实体中创建一些只和展现逻辑有关的方法)到领域之中;模板的依赖变得很清晰,因为它们必须在 ViewModel 中设置。例如,暴露出依赖可以帮助我们决定应该优先从数据库中加载哪些内容来避免 N+1 问题。Presenter接收 HTTP 请求,触发命令或查询,使用查询返回的数据、ViewModel、模板和模板引擎生成 HTML 并将它返回给客户端。所有 View 的交互都要经过 Presenter。下面是我实现的一个非常简单的例子:
<?php
// src/UI/Admin/Some/Controller/Namespace/Detail/SomeEntityDetailController.php
namespace UI\Admin\Some\Controller\Namespace\Detail;
// use ...
final class SomeEntityDetailController
{
/**
* @var SomeRepositoryInterface
*/
private $someRepository;
/**
* @var RelatedRepositoryInterface
*/
private $relatedRepository;
/**
* @var TemplateEngineInterface
*/
private $templateEngine;
public function __construct(
SomeRepositoryInterface $someRepository,
RelatedRepositoryInterface $relatedRepository,
TemplateEngineInterface $templateEngine
) {
$this->someRepository = $someRepository;
$this->relatedRepository = $relatedRepository;
$this->templateEngine = $templateEngine;
}
/**
* @return mixed
*/
public function get(int $someEntityId)
{
$mainEntity = $this->someRepository->getById($someEntityId);
$relatedEntityList = $this->relatedRepository->getByParentId($someEntityId);
return $this->templateEngine->render(
'@Some/Controller/Namespace/Detail/details.html.twig',
new DetailsViewModel($mainEntity, $relatedEntityList)
);
}
}M-V-C-VM_-_ViewModel_example.php模板和 ViewModel 一一对应,意味着 View 只能被一个特定的 ViewModel 使用,反过来也一样。这会让我进一步思考,也许我们可以将模板和 ViewModel 封装成一个 View 对象,更有效地将 Controller 和模板以及 ViewModel 解耦,让它只依赖一个通用的 View 接口;但我还没有机会实验这个想法。◐ 总结在网上,我们还能找到其它 MVC 的变种。但是,这里列出是我觉得更有意义和/或与我的工作有关的一些模式。然而,我在本文中引用的这些模式是为桌面应用程序和/或富客户端的上下文创建的,因此它们不是总能和请求/响应范式百分之百的匹配。如果你开发的是云原生的企业应用并且使用了 MVC,实际上你多半使用的是更接近 MVP 的某种模式。但无论如何,我想表达的不是应该尊崇某种特定的 MVC 变种或是刻板地理解它们的名字,而是我们应该学习所有的模式,按照需要去使用和调整它们。还是那句老话,最终目标就是高内聚低耦合:关注点分离。◐ 引用来源1979 – Trygve Reenskaug – MVC XEROX PARC 1978-791979 – Trygve Reenskaug – MVC1987 – Joelle Coutaz – PAC, an Object Oriented Model for Dialog Design1996 – Mike Potel – MVP: Model-View-Presenter: The Taligent Programming Model for C++ and Java2000 – Jason Cai, Ranjit Kapila, Gaurav Pal – HMVC: The layered pattern for developing strong client tiers2003 -Trygve Reenskaug – The Model-View-Controller (MVC): Its Past and Present2004 -Martin Fowler – Presentation Model2005 – John Gossman – Introduction to Model/View/ViewModel pattern for building WPF apps2006 – Martin Fowler – Supervising Controller2006 – Martin Fowler – GUI Architectures2011 – Mārtiņš Tereško – Architecture more suitable for web apps than MVC?2017* – Tracy-Gregory J. Gilmore – Never the twain shall meet. The tale of MV*2017* – Tech notes – MVVM vs MVP vs MVC: The differences explained2017* – Wikipedia – Model–view–controller2017* – Wikipedia – Presentation–abstraction–control2017* – Wikipedia – Model-view-presenter2017* – Wikipedia – Hierarchical model–view–controller2017* – Wikipedia – Model–view–viewmodel2018* – Wikipedia – History of the graphical user interface
基于粒子群算法PSO、帝国殖民算法ICA 和萤火虫算法 FA 求解最小生成树附matlab代码
作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。 🍎个人主页:Matlab科研工作室🍊个人信条:格物致知。更多Matlab仿真内容点击👇智能优化算法 神经网络预测 雷达通信 无线传感器 电力系统信号处理 图像处理 路径规划 元胞自动机 无人机 ⛄ 内容介绍 何为树:连通且不含圈的图称为树。 图T=(V,E),|V|=n,|E|=m,下列关于树的说法等价:T是一个树。T无圈,且m=n-1。T连通,且m=n-1。T无圈,但每加一新边记得到唯一一个圈。T连通,但任舍去一边就不连通。T中任意两点,有唯一道路相连。 何为生成树:若图G=(V,E)的生成子图是一棵树,则称该树为图G的生成树,也称支撑树,简称为图G的数。图G中属于生成树的边称为数枝(Branch)。 何为最小生成树:连通图G=(V,E),每条边上有非负权L(e)。一棵树上所有树枝权的总和,称为这个生成树的权。具有最小权的生成树称为最小生成树,也就是说最小支撑树,简称最小树。 私以为,两种算法其实都是贪心,所以需要严格的证明。由于最近时间零散、数学久置未学、对算法领域没有系统了解。所以不进行深入探讨(也就是说证明),仅以一个简单实例做一个入门级的了解。 Prim算法: 给定连通赋权图G=(V,E,W),其中W为邻接矩阵,设两个集合P和Q,其中P用于存放G的最小生成树中的节点,集合Q存放G的最小G的最小生成树中的边。另集合P的初值为P={v1}(假设构造最小生成树时从v1出发),集合Q的初值为P={空集}。 (1)P = {v1},Q = {空集}; (2)while P ~= Q 找到最小边pv,其中p∈P,v∈V-P; P = P + {v}; Q = Q + {pv}; end Kruskal算法 (1)选e1∈E(G),使得w(e1) = min(选e1的权值最小)。 (2)e1,e2,...,ei已选好,则从E(G)-{e1,e2,...,ei}中选取ei+1,使得G[{e1,e2,...,ei,ei+1}]中无圈,且,w(ei+1) = min。 (3)直到选得en-1为止。 以下是问题:一个乡有9个自然村,其间道路及各道路长度如图所示,各边上数字代表距离。问如何架设电线最短。 ⛄ 部分代码clcclear allclose allChoices = {'Particle Swarm Optimization', 'Firefly Algorithm', 'Imperialist Competitive Algorithm'};ANSWER = questdlg('Select the algorithm:', ... 'Minimum Spanning Tree', ... Choices{1}, Choices{2}, Choices{3}, ... Choices{1});if strcmpi(ANSWER, Choices{1}) pso; return;endif strcmpi(ANSWER, Choices{2}) fa; return;endif strcmpi(ANSWER, Choices{3}) ica; return;end⛄ 运行结果⛄ 参考文献⛄ 完整代码❤️部分理论引用网络文献,若有侵权联系博主删除❤️ 关注我领取海量matlab电子书和数学建模资料