HarmonyOS开发者限时福利来啦!最高10w+现金激励等你拿~ 了解详情
写点什么

多形态 MVC 式 Web 架构的分类

  • 2016-10-26
  • 本文字数:8019 字

    阅读完需:约 26 分钟

关键要点

  • MVC 已成为每一代软件开发人员所最早接触到的软件开发原则之一。
  • MVC 应被视为一种通用的架构原则和方法。
  • MVC 三元组件的语义随架构环境的不同而变化。
  • 可将基于 HTTP 的 Web MVC(WMVC)分成三个不同的类别:sWMVC、dWMVC 和 pWMVC。
  • 随着近期技术的进步,异步且实时观察变化的“事件循环”可用于 WMVC 应用的实现。

引言

MVC(模型- 视图- 控制器,Model-View-Controller)最初用于设计和实现狭义的桌面图形用户界面(GUI)应用开发。经典的MVC 与面向对象的程序开发方法一样,已成为每一代软件开发人员所最早接触到的软件开发原则之一。虽然MVC 对当今的工业界有着如此重要的影响,但是在日益互联计算的时代,很明显MVC 的内涵已迷失了其精准性。这在过去20 年间对于WUI(Web 图形界面,Web Graphical Interface)开发领域尤其是如此。基于以上原因,本文意在对MVC 的起源做概要地阐述之后,进而深入地探讨基于Web 的MVC 的演进和变化。

在WUI 的应用场景下,原始MVC 及MVC 三元组中成员对象的历史意义和内涵在不断地演变和转变形态。出于消除任何概念上的混淆的考虑,在本文的探讨中将使用“WMVC”一词表示基于Web 的MVC 式架构模式。大多数技术平台的WMVC 特性正处于不断地改进之中,这包括Microsoft 的 ASP.NET MVC 、PHP 的 Symfony 、Python 的 Django 、Ruby 的 Merb 、Java 的 JSR 371 等。驱动这些平台改进的原则,很大程度上在于 JavaScript 已可由客户端浏览器运行。此外,不少新的网络协议充实了服务器 - 客户间的通信。

自 JavaScript 被 XMLHttpRequest 赋予新生以来,它就成为 WUI 开发中情有独钟的技术。在过去的数年内,就有超过二十种 基于 WMVC 的 JavaScript 应用萌芽发展,其中包括 Dojo Angular Ember Backbone React 等。即使不是全部的也是绝大部分的框架都是侧重于客户端组件的交互,对于 WMVC 视图和控制器的组成对象而言尤其是如此。自然而言,WUI 开发方法上的革新再一次引发了针对 MVC 亦或 WMVC 的大量讨论。这些讨论时常是十分激烈的,通常侧重于某个特定的方面,或基于某个特定的环境。进而使得 MVC(WMVC)衍生出一些主要差异在于控制器对象的变体,其中包括 MVA MVP MVVM Flux Redux SAM 等。这些 MVC 变体时常被统称为“MV*”,其中的“*”表示了各变体间的差异主要在于视图和控制器间的交互方式。通常并不将表示现实世界视图对象的模型组件整体地列入考虑中,或仅是在 Web 应用方案中将模型作为 MVC 三元组关系里的被动参与者。

自 MVC 概念于四十多年前被提出以来,MVC 模型很有可能已经历了最重要的改变。在本文的探讨中,我们对 MVC 模型做了一个宽泛的定义,这个定义中涵盖了驻留内存的模型对象(例如记录集对象),还有用于支撑对象的 SoR (主数据记录系统,System of Record)中的源数据、源文档、源文件和原始信号,以及所有把它们同步和聚集到一起的过程。模型数据仓库的存储形式已从小型软盘发展到 RDBMS MMDBMS (多模数据库管理系统,multi-model database management system)。早期模型数据仓库是与驻留内存的模型对象共处一处的,这些模型对象是独立存在于各个用户桌面之上的。现在模型数据仓库使用宽带连接、分布式或基于云的系统,其部署可远离域对象。存储在这种外部环境中的数据,可以被企业生态系统的多个系统修改,也可以被消费者应用的数以千计的用户修改。这种使用场景上的根本差异,已经在根本上地改变了模型对象的行为,进而改变了模型对象与 MVC 三元组中的另两个成员间的通信和交互。

原型 MVC

oMVC (原型 MVC,Original MVC)是由挪威计算机科学家 Trygve Reenskaug 于 1978 年提出,当时他工作于著名的 Xerox PARC 研究中心 Smalltalk 团队中。在 oMVC 的概念初步成型后,最初被实现为 Smalltalk-80 类库的一部分,用于桌面 GUI 的建立。

在那个时代,桌面应用远非当前这样是日常家居中的常见物品,每个应用需要独立运行于一台机器上,而每台机器的存储是有限的并且是各自独立的。正如在图 1 中所示,对 oMVC 模型对象的任何操作都完全由用户行为通过控制器所触发,MVC 三元组在受控的环境中进行通信、同步并保持状态。控制器的主要作用是维持用户和系统之间的联系(参见图 1)。控制器实现对相关 GUI 组件的部署,并在屏幕上将这些 GUI 组件展现给用户。在 Win95 出现之前的年代中,这是一个具有挑战性的任务,因为当时 MS-DOS 依然是占据主要地位的操作系统。在 oMVC 模型中,一旦用户产生了某种动作,例如菜单选取、在输入框中输入、按钮点击等,控制器就会转化这些动作为对应的改变消息,向模型传递这些消息,并对消息进行处理。

图 1展示了独立桌面环境中的 oMVC。图中显示了作为模型的组成部分的本地软盘数据存储。oMVC 中控制器和视图具有成对出现的关系,但是模型的改变并不在两者间直接产生通信。控制器和视图知道模型的状态,但是反之并非如此。

一旦模型从控制器获取了变更通知,它并不直接通过调用去更新所涉及的视图。在模型 - 视图的关系中,变更通知的获取是通过每个独立的参与者之间的相互注册实现。一旦一方发生了变更,就会生成一个事件,对方就会采取相应的动作作为响应。在图 1 中,视图是附属于模型的,对模型进行观察。一旦控制器触发了模型变更事件,视图必须去确保自身显示也按需更新,以相应地反映出模型的状态。更新模型的通知信号也可由视图自身生成。这种视图与模型之间的观察(或订阅)和通知关系,有助于模型和视图间的解耦,使得多个视图可隶属于同一模型,进而可提供不同的表示。

在图1 中值得注意的是,控制器并非直接地改变视图。在Smalltalk 社区及其它后续的桌面GUI 应用库中,通常将视图和控制器看成一对耦合的对象。视图使用具有特定控制器类型的实例实现预期的响应。为创建所期望的行为,控制器还可以在不同情景中策略性地、动态地切换类型。这样的视图- 控制器对可以嵌套于复合层次结构中(如图2A 所示)。在该层次结构中的父辈之间、子女之间及父子之间,视图- 控制器组件都可以进行交互和通信。很多情况下,层次结构中的每个独立视图- 控制器的子女组件仅处理部分的模型对象。此外,从oMVC 组合的角度看,模型也可以使用层次结构的形式进行组织,这样 MVC 三元组作为一个整体构成层次结构中的父子关系,如图2B 所示。

(点击放大图像)

图2 左图是oMVC 的复合表示,右图是 PAC (显示 - 抽象 - 控制,Presentation-Abstraction-Control)的表示。

总而言之,oMVC 设计范例是由一系列的 GoF 设计模式所组成,尤其是其中包括了观察者模式策略模式复合模式。在早期的桌面应用库中,oMVC 域架构和模式的设计意图得以保持,即模型组件由应用域对象和数据存储所组成,其中存储多是本地的或是受限的。在oMVC 三元组类的行为中,应用域行为的维护和广播起着核心的作用。oMVC 的一个关键假设是模型的稳定性,该假设在上世纪七十和八十年代的桌面应用情景中显然是正确的。但是在WMVC 领域,模型时常发生改变通常是一种常态。直至近些年,向用户实时广播变更(类似于oMVC 所实现的)所需的技术基础才得以实现。

WMVC 的分类

具有讽刺意味的是,虽然直到上世纪九十年代,尤其是在 Win95 出现之后的年代,桌面计算机开始进入普通百姓家并得到普及,但是传统的桌面应用却因为因特网互联的 Web 应用开始统治了业界而逐渐退居幕后。不同于安装并于运行于终端用户计算机上的桌面应用,Web 应用是宿主于远离用户的服务器上,创建了客户 - 服务器的关系。在本文的其后内容中,我们将浏览器(browser)和客户(client)这两个概念互换使用。根据浏览器和服务器相对于 WMVC 三元组对象的部署位置和执行方式的不同,可将 WMVC 明确地分组为:

  1. 服务器端 WMVC (Server-side WMVC,sWMVC):所有 WMVC 的组件位于服务器上,并在服务器上执行。
  2. 双重 WMVC(Dual WMVC,dWMVC):WMVC 组件分布于浏览器和服务器之间。通信可由客户或者服务器端发起。
  3. 点对点 WMVC(Peer-to-Peer WMVC,pWMVC):这种架构中没有集中式服务器。所有 WMVC 组件位于客户端,在客户端执行。pWMVC 可具有自己的沙箱 SoR。
服务器端 WMV(sWMVC)

在 sWMVC 模型中,用户使用浏览器作为瘦客户,通过无状态的请求 - 响应 HTTP 协议访问应用(如图 3 所示)。客户向服务器发送 HTTP 请求或输入内容,接收并显示整个更新的 Web 页面(或是其它的文档)。一旦页面被加载以后,各页面组件间就很少有交互了,页面成为静止的。

在这种瘦客户 - 服务器范式的 sWMVC 架构中,应用 SoR 版本库外部化为一种集中式环境。它与应用服务器内存中的域对象是相互分离的。服务器和数据版本库都是远离用户浏览器部署的(如图 3 所示)。SoR 存储常常是由一个或多个关系数据库这样的数据源所组成。鉴于数据已经外部化了,带外进程或不同的用户都可对数据进行更新。数据的变更只会从控制器流向模型(参见图 3);当 SoR 中数据被不同的用户或系统改变时,并不向应用服务器发送入站数据变更通知。不同于 oMVC,模型及其所关联的视图间不再有任何的直接联系和必要的同步。由于视图不再反映模型的状态,这就需要用户手动地发起新的 HTTP 请求去同步和刷新视图。因此 sWMC 中的“s”,也可指代这种 WMVC 范例的静态(static)或是陈旧(stale)的本质特性。

图 3 sWMVC 范例的一种表示。图中显示了由服务器驻留内存的域对象模型(M)外部化而得到的 SoR。不同于 oMVC,控制器不再与用户交互,而是用于协调模型与视图间的通信。模型数据的变更是单向流动到外部数据存储中的。

WMVC 的模型可简述为一种分层架构(如图 4 所示)。架构的最顶层模型表示了在视图及其相关的控制器这个关系对之间的契约关系。为满足该契约,在处理栈中可包含数个可变的业务逻辑和数据访问组件。该契约用于所有与视图相关信息的连接,其中的信息可能直接来自本地 SoR,或是数据云,或是其它真实世界中的数据源,例如探测器和数据提供系统。

图 4 WMVC 模型的示意图。图中显示 WMVC 的组成包括了多个架构层次,以及来自本地或远程可访问环境中的可变数据源。

相对于在 oWMVC 中的意义和内容(如图 3 所示)而言,三元组对象间的关系和通信发生了根本上的转变。与控制器在用户和 oMVC 系统(图 1)间所起的作用不同,sWMVC 的控制器承担了在更高层级上协调视图和模型的角色(参加图 3)。视图和模型间的通信通过控制器发生。用户与视图进行交互,将模型与模型视图关联的行为逻辑包含在控制器中,由控制器负责管理输入、更新模型并产生适当的输出。

Web 应用的架构环境与桌面应用的有所不同,对于将MVC 引入早期Web 应用架构的设计中,虽然这在本质上忽视了MVC 的原生结构。但是这种引入反而接收了MVC 模型的基本理念,即将这三个相互作用的、多变责任的对象类进行相互分离是十分重要的。该做法将oMVC 范例提升为UI 设计中在更加通用层次上的架构原则,增加了对任意类型UI 应用的灵活性和可维护性。

sWMVC 中通常包含有多种设计模型,其中也包括在 oMVC 中所使用的设计原则。例如,各个用例的控制器原则和行为可能都是不同的,包括中介者模式调度者模式、使用状态模式模板方法模式策略模式代理等。但是在oMVC 中,观察者模式在触发三个对象类型间的通信中起着关键的作用,尤其是当该模式与视图做相关的更新时。在sWMVC 实现中,观察者的作用被缩减了。这样导致了sWMVC 的静态和陈腐的特征。直至近些年,技术的进展才使得交互式和富Web 用户体验成为可能。

双重WMVC(dWMVC)

在Web 时代的早期,由于浏览器的普遍使用,为使现有的桌面交互应用支持Web 做出了不懈的努力。这些工作的一个成果体现为 Microsoft 的 Outlook Web 项目所研发的一种基于 Web 的新组件,该组件允许客户端脚本发布异步 HTTP 请求到服务器。该工作引导了 XMLHttpRequest (XHR) 协议的建立和标准化。该协议是至上世纪末为止最具有革命性的工作。XMLHttpRequest 随后成为 Ajax 技术的基本原则。

当前,基于这种技术的架构使得 dMWVC 的视图 - 控制器对可以动态分布,并可安装到用户桌面、移动设备或其它设备的浏览器上。浏览器组件与服务器上模型间的异步通信,用于同步给定的或者所有的视图元素的 dWMVC 三元对象组状态,进而提供给用户对现实世界或模型对象的最新认知。这种技术的引入使得 XHR 切实地丰富了客户应用,为浏览器用户带来了交互式的用户体验。

XHR 技术还引发了单页应用 (SPA) 开发技术的发展。类似于oMVC 应用,SPA 是驻留在单一页面上的Web 网站,提供了无缝的浏览体验。对于用户而言,SPA 看上去在从一个页面到另一个页面时并没有任何页面重载,对不同页面渲染所需的资源是在所需时由幕后的服务器动态且异步加载的。SPA 和这种dWMVC 应用的交互行为的组合使此类范式划分为了富互联网应用 (RIA) 的最新条目。

就XHR 协议自身而言,从客户端的视图- 控制器对象到服务器端模型间的通信依然仅是单向的通信,需要由视图发起某种类型的轮询机制去探测模型上的更改。轮询是一种资源密集型操作,因而成为影响性能的一个关注点。类似于图1 所示的oMVC,在理想情况下模型中的任何更改应会被实时发布到、或是广播到所有相关的视图- 控制器组件中。图5 显示了dWMVC 架构的视图和模型间的双向异步同步(通过控制器)。该机制提供了完全动态的状态同步,这种同步基于dWMVC 组件间的订阅- 发布机制。一些近期的技术发展,其中包括服务器发送事件 (Server-Sent Events,SSE)、 WebSocket 和入站数据库通知技术等,使得该同步操作成为可能。

图 5 dWMVC 的示意图。图中显示了三元组对象在客户和服务器间的分布。由 SoR 发起的入站更改通知导致了模型和视图间的实时双向更新。

SSE 机制作为 HTML5 的组成部分,允许服务器端组件异步启动,并将数据从服务器端组件实时推送到浏览器。客户端组件可以使用 SSE 发起请求,向服务器申请建立一个非传统的 HTTP 连接。一旦客户端组件接收到所发起的请求,它继续对随后的服务器响应进行监听。与此同时,服务器保持同一客户 - 服务器初始连接是活跃的。一旦新的数据可用,服务器无需客户的额外请求,就立刻通过该初始连接将这些数据推送给客户。这样,SEE 给出了一种从服务器到客户浏览器的解决方案,该解决方法使用了异步的发布 - 订阅事件通知。

WebSocket 是一种提供浏览器和服务器间全双工连接的通信协议。当客户发送初始请求到服务器时,WebSocket 通知服务器该 HTTP 连接可能会升级为全双工的 TCP/IP WebSocket 连接,通知使用了一种特殊的 HTTP 报头。一旦 WebSocket 连接被建立,就可在需要时用于在浏览器和服务器间相互发送数据。

使用 SSE 和 WebSocket 通信协议,服务器可以异步地将模型驻留内存的更改发布到浏览器。但是正如前面所讨论过的,模型架构的分层可能会跨越服务器的边界,并可能包括应用服务器之外的外部 SoR(参见图 4)。由于 SoR 中的数据记录可被其他应用或用户修改,因此每当这样的带外更改发生时,SoR 应具有变化数据捕获 (change data capture,CDC)机制去探测并捕获更改,实时地发起并推送入站数据更改到应用服务器,实现端到端的双向发布- 订阅通信模型(如图5 和图6 所示)。在图6 中,dWMVC 轮毂的中心表示了共享的SoR 和CDC 数据源。数据的实时同步由数据源和相关驻留内存域模型对象之间的双向交互所维持。在图6 中,每个轮辐间的微型dWMV 表示了一个独立的业务应用(集成的企业生态系统中),或是一个独立的应用用户。

图6 dWMVC 轮图。图中显示了由SoR 发起的入站更改通知,并显示所引发的模型和所有视图间的实时双向更新情况(以微型WMVC 展示)。

基于Web 的架构栈中加入了XHR-Ajax、SSE 和WebSocket 等技术,还有数据库厂商提供了数据库入站通信能力,所有这些一起使得传统oMVC 中视图和模型间的双向交互通信在dWMVC 中得到了复兴。越来越多的数据库厂商,包括 PostgreSQL Oracle 等传统关系数据库厂商和 RethinkDB Cassandra NoSQL 数据库厂商,已经实现或者规划去提供 CDC 机制,以改进应用服务器的入站推送通知。

点对点 WMVC(pWMVC)

对于上面所论及的两种 WMVC,它们的架构语义都是基于客户- 服务器范例的,即用户浏览器向服务器发送HTTP 请求,取回服务器端的内容,服务器则回应以包含请求信息的一个或更多的响应。这类方法中,服务器负责存储,并发送所有内容及对所有请求的响应。但是这样的集中式方法可能会导致性能上的瓶颈。因为为了支持所有可能的请求负载,需要对服务器基础设施的资源进行适当地扩展和复制。当前由于高频度实时内容发布需求在数量上日益增长,这类方法会产生问题,尤其是在(意料之外的)高通量负载的期间。最优的系统无疑是那种能以去中心化的方式支持高质量终端用户体验的系统,这样的系统可以使用户用最短的路由和时间获取到数据。借助于点对点 (Peer-to-peer,P2P)数据交换及通信,终端用户可以从其它的用户那里交互、检索和接收内容。无疑,这样的架构绕开或降低了集中式服务器的负载和潜在瓶颈问题。

传统的点对点系统需要用户显式地安装专用的桌面应用或插件。在 WebRTC (Web 实时通信,Web Real-Time Communication)协议被标准化并被浏览器支持之前,浏览器本身并不具备使对等系统的工作直接相互通信的能力。现在 WebRTC 标准已被大多数的浏览器所支持。它是一种 API 定义,提供了无服务器的浏览器到浏览器(浏览器 P2P)直接数据交换和通信范例。WebRTC 对 Web 应用引入了点到点的解决方案,它允许 Web 浏览器打开到其它浏览器的直接通信通道,无需对每个 Web 请求 - 响应的集中式服务场景进行处理(参见图 7 和图 8)。

图 7 pWMVC 如图所示,图中显示了位于客户端(浏览器)内、或由客户端所控制的所有三元组组件。

在 pWMVC 模型中,所有的三元组组件位于并执行于客户端及相关终端用户的沙箱中(如图 7 所示)。沙箱中包括用户本地或基于云的 SoR 存储,这样的存储可以被 pWMVC 应用访问。在图 8 中,轮辐间的每个微型 pWMVC 都代表了一种独立用户浏览器环境。与图 6 相比,为便于持续进行的 Web 通信,pWMVC 轮图中并未涉及集中式服务器和 SoR 架构。互联浏览器间的微型 pWMVC 组件状态可使用 WebRTC 通信协议保持同步。

图 8 pWMVC 轮图。图中显示了由独立用户浏览器所发起的直接无服务器 P2P 变更通知,以及该通知如何导致其它的对等端视图进行实时更新。图中“M”指代内存中模型对象和用户 SoR。

总结

MVC 本身应该被视为是一种无需考虑任何语义的设计原则或方法论。MVC 的简要内涵在于,任何类型的 UI 应用都可被分解为三套相互作用的对象类。在 MVC 所应用的场景中,应该审查该三元对象类型组的行为。为更好地理解 MVC 概念,在对架构和特定域程序库进行实际设计和实现应用时,应使用适当的命名注释。

WMVC 可看成一种独特的原理图,用于在无状态 HTTP 域的场景中基于 MVC 方法论的开发。WMVC 可区分 sWMVC、dWMVC 和 pWMVC 这三种不同的类别。这些类别在机制上不同于 oMVC,即原型 MVC。考虑到标准化的网络协议、由特定数据库技术所提供的专用入站通信等这样的最新技术发展,基于观察更改的 MVC 式“事件循环”可以满足基于 Web 应用的需求。这使得 WMVC 当前可为浏览器用户实现具有完全交互的实时丰富 WUI 体验。

关于作者

自上世纪九十年代以来,Brent Chen先生就一直致力于系统架构和应用开发。他所提出的解决方案涵盖了众多的专业领域,其中包括:工资管理、人力资源管理、职工福利管理、监管合规、卫生保健和政府事务等。Brent Chen 先生曾供职于一些主要的解决方案和服务提供商,诸如:Computer Sciences Corp、Northrop Grumman、ADP、LLC 等。他的一个研究兴趣就是去探究当前正在发展的 Web 架构和技术中的新机遇和新兴前沿领域。

查看英文原文: Polymorphism of MVC-esque Web Architecture: Classification


感谢冬雨对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2016-10-26 18:304558
用户头像

发布了 227 篇内容, 共 74.2 次阅读, 收获喜欢 28 次。

关注

评论

发布
暂无评论
发现更多内容

c#12 实验特性Interceptor如何使用的一个简单但完整的示例

八苦-瞿昙

dotnet

尝试让查询更简单

八苦-瞿昙

dotnet

如何理解分布式事务

我爱娃哈哈😍

分布式 分布式事务 微服务

通义灵码上线一周年:超 600 万下载量,国内用户规模第一,新功能有奖测评

阿里巴巴云原生

阿里云 云原生 通义灵码

1018AI资讯|Optimus机器人进化,ChatGPT Windows版推出 | Siri新功能揭秘 | 复旦AI模型开创动画新纪元

言寡意多

SourceGenerator 生成db to class代码优化结果记录 二

八苦-瞿昙

dotnet

Java栈溢出|内存泄漏|内存溢出

EquatorCoco

Java

趣味科普:人的大脑相当于什么水平的CPU和GPU

伤感汤姆布利柏

创新突破!天翼云荣膺CCF HPC China 2024高性能计算创新大奖

天翼云开发者社区

云计算 高性能计算

一个基于 SourceGenerator 生成 从 dbReader转换为 class 数据的性能测试实验

八苦-瞿昙

C# dotnet csharp

SourceGenerator 生成db to class代码优化结果记录

八苦-瞿昙

dotnet

通义灵码上线一周年:超 600 万下载量,国内用户规模第一,新功能有奖测评

阿里云云效

阿里云 云原生 通义灵码

ArkWeb高级安全模式 - 提升应用安全性

秃头小帅oi

什么是 Spring Cloud?它解决了哪些问题?

我爱娃哈哈😍

微服务 SpringCloud

从零开始学机器学习——构建一个推荐web应用

快乐非自愿限量之名

人工智能 机器学习 Web

探索一下 Enum 优化

八苦-瞿昙

dotnet

弘扬传统文化,百度百科AI非遗馆亮相中国非物质文化遗产博览会

Geek_2d6073

一次彻底讲清如何处理mysql 的死锁问题

快乐非自愿限量之名

MySQL 数据库

Higress 重磅更新:AI 能力全面开源,云原生能力再升级

阿里巴巴云原生

阿里云 云原生 Higress

2024算力中国·年度重大成果!天翼云成功入选!

天翼云开发者社区

人工智能 云计算

测试人生 | 双非院校,2年工作经验年薪近20万

测吧(北京)科技有限公司

测试

淘宝商品详情数据接口抓取商品视频参数

tbapi

淘宝商品详情接口 淘宝商品视频接口

【HarmonyOS】SaveButton 保存图片

zhongcx

让查询可以使用 json path

八苦-瞿昙

dotnet

鸿蒙开发案例:推箱子

zhongcx

五种编程语言运行速度对比

高端章鱼哥

云手机与传统手机的不同之处

Ogcloud

云手机 海外云手机 云手机海外版 云手机群控 手机群控

认可+1!望繁信科技荣获2022年度新锐技术品牌奖

望繁信科技

数字化转型 流程挖掘 流程资产 流程智能 数字北极星

朋友吐槽我为什么这么傻不在源生成器中用string.GetHashCode, 而要用一个不够优化的hash方法

八苦-瞿昙

dotnet

为什么选择租用香港服务器?

Ogcloud

服务器 服务器租用 云服务器租用

第三届OpenHarmony技术大会展区亮点纷呈,全方位洞见智慧互联未来

科技热闻

多形态MVC式Web架构的分类_JavaScript_Brent Chen_InfoQ精选文章