突然讨厌做前端,讨厌代码_不要讨厌HATEOAS

突然讨厌做前端,讨厌代码

或我如何学会不再担心和爱HATEOAS

REST已成为实现Web服务的事实上的解决方案,至少已成为一种流行的解决方案。 这是可以理解的,因为REST在使用HTTP规范时提供了一定程度的自我文档。 它经久耐用,可扩展,并提供了其他一些理想的特性。

但是,许多所谓的RESTful服务都没有实现HATEOAS (作为应用程序状态引擎的超媒体),这会使Roy Fielding晚上 忙 起来 (如果您认为介绍不好,请阅读评论部分 )。 这是一个不幸的趋势,因为包括超媒体控件提供了很多优势,特别是在客户端与服务器解耦方面。

本文是一个分为两部分的系列文章的第一篇,将介绍控制REST的底层实现细节和设计方面的问题。 我们将讨论在RESTful服务中实现HATEOAS值得付出额外努力的原因,因为您的服务面临着不断变化的业务需求。

第二部分将于3月28日发布,它将是使用Spring-HATEOAS实现HATEOAS服务的实时代码示例。 在我即将于2016年3月2日星期三在堪萨斯城Spring用户小组的主题为“ 我如何学会停止照顾并开始爱上HATEOAS ”的演讲中,您还可以看到其中的一些概念。

REST,成功实现建筑约束的成功典范

作为一名开发人员,我不得不经常沮丧地学习如何在高位建筑师对我施加的约束下工作。 自从最近向架构师过渡以来,我现在可以定义自己的约束,并尽自己的力量继续痛苦的循环。 但是,在研究本文时,我了解了REST体系结构中经过深思熟虑的约束是如何使其成为Web服务世界的先驱。 苦难的循环至少在这次减少了。

Roy Fielding 在2000年的博士论文中定义了控制REST的六个主要建筑风格约束。 我将详细介绍其中的五个。 第六,按需编码(可选)将不涉及。 五个幸运的样式约束是:客户端-服务器,无状态,可缓存,统一接口和分层体系结构。

1.客户端-服务器

第一种样式约束是客户端-服务器分离。 具有讽刺意味的是,这是当开发人员选择不实施HATEOAS时受影响最大的约束。

关注点分离是好的系统设计的基本原则之一。 在REST和Web服务的上下文中,这种关注点分离在可伸缩性方面具有一些好处,因为RESTful服务的新实例也不需要处理客户端的拆包。

真正的好处,就像在任何时候都实现关注点分离约束一样,尽管允许独立发展。 客户端处理演示,服务器处理存储。 这种分离意味着对服务器的每次更改都不需要对客户端进行更改(并且不需要协调两者之间的发布),反之亦然。

在本文的后面,我们将更详细地介绍如何不实施HATEOAS来模糊客户端和服务器之间的界限。

2.无状态

如果您要问开发人员RESTful服务的关键特征是什么,您可能会首先收到的答复是它是无状态的。 这是一种流行的响应,因为无状态在REST最令人希望的两个特性中发挥着核心作用:持久性和可伸缩性。

在这种情况下,无状态意味着每个请求都包含服务器接受或拒绝请求所需的所有信息,并且服务器不需要检查会话状态即可确定请求的有效性。 这将导致持久性,因为客户端不再绑定到特定的服务实例。 如果客户端正在与实例“ A”进行对话并且故障,负载均衡器可以将客户端重定向到另一个可用实例,没有人是明智的。

另一个好处是可伸缩性,这是因为服务器资源不会因存储用户状态而消耗(如果服务足够流行,则可能会消耗大量资源)。 它还可以响应流量的激增,加快附加服务实例的旋转速度。 也就是说,要实现该功能需要高度的DevOps成熟度。

3.可缓存

第三个样式约束是请求可以是可缓存的。 在这种情况下,可缓存性是指客户端缓存请求的能力。 这与像Redis这样的服务器托管的缓存相反,尽管这是在以后的约束中启用的。 缓存客户端请求是每个主流浏览器中都已实现的功能,可通过使用http头激活该功能,如下图所示(缓存控制)。

图片来源:https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-CN

图片来源:https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching?hl=zh-CN

使客户端缓存请求的好处是不需要服务器重新提供对未更改且经常访问的资源的响应,从而减少了服务器负载。 同样,由于浏览器比从服务器更快地检索本地缓存的响应,因此可以改善客户端的感知性能。

4.统一的界面

RESTful服务的端点是资源。 状态的变化是通过操纵这些资源而发生的。 发送到这些资源的消息是自描述的,超媒体是应用程序状态的引擎(最后一个约束听起来很熟悉)。

在下面的Richardson成熟度模型部分,我们将逐步介绍在服务上实现这四个约束的外观。

5.分层架构

像食人魔和洋葱一样,REST体系结构也有层次。 RESTful服务中的分层体系结构是通过通过它发送的消息具有自描述性而实现的,并且每一层都无法从接口看到到下一层。

当我提交在Netflix上观看电影的请求时,无论我使用什么客户端,都将发送GET请求。 该请求可能会到达路由服务。 看到这是一个GET请求(即检索),然后该路由服务可以将该请求发送到服务器缓存。 该缓存可以检查其是否具有与请求的查询匹配的未过期资源。 在我的请求可以实现之前,这可能会持续进行几层甚至在Netflix体系结构中的某些区域。 所有这些路由和重定向都可能发生,因为REST消息是自描述的。 只要层可以理解HTTP,它就可以理解它收到的消息。

理查森成熟度模型

因此,我们已经涵盖了控制REST的六种主要架构样式约束中的五种。 现在,让我们仔细看看第四个样式约束,即统一界面,如先前所承诺的。 统一的接口定义了RESTful服务的许多“外观”,在该接口上定义了以下端点:GET:/ users / bob。 这也是定义HATEOAS的地方,这就是本文的重点。 为了使这些约束的影响可视化,并了解许多RESTful服务的不足之处,我将以有用的Richardson成熟度模型(RMM)为指南。

POX的沼泽

这是RMM上的级别0。 在这里,不能真诚地将服务描述为RESTful。 客户与之连接的端点不是资源,我们在请求中未使用正确的HTTP动词,并且服务器未使用超媒体控件进行响应。 我们都已经在这样的服务上进行了工作,确实有可能(尽管可能不太可能)这种服务易于使用和维护……但是无论它是否绝对不是RESTful的。

通过RMM时,我们将通过通过亚马逊等在线零售商订购电视来观察REST中统一接口约束的实现如何影响服务器与客户端之间的交互。

在这里,我们看到了级别0的交互:

POST: viewItem
{“id”: “1234”
}
Response:
HTTP 1.1 200
{“id” : 1234,“description” : “FooBar TV”,“image” : “fooBarTv.jpg”,“price” : 50.00
}
POST: orderItem
{“id” : 1,“items” : [“item” : {“id” : 1234}]
}
Response:
HTTP 1.1 200
{“id” : 1,“items” : [“item” : {“id” : 1234}]
}

资源资源

在RMM的这一级别上,我们正在实现统一接口的前两个约束。 我们正在通过URI(/ items / 1234,/ orders / 1)识别与我们交互的资源,而我们如何通过处理这些资源来与服务交互。

在向我们的服务发送请求时,为我们的每个资源分配一个专用的端点而不是单个端点,可以为客户与之交互的实体提供更多的标识。 它还提供了收集分析数据的机会,我们的客户如何与我们的服务交互。 热图可以更轻松地显示正在请求哪些资源以及该资源中的特定实体。

POST: /items/1234
{}
Response:
HTTP 1.1 200
{“id” : 1234,“description” : “FooBar TV”,“image” : “fooBarTv.jpg”,“price” : 50.00
}
POST: /orders/1
{“item” : {“id” : 1234}
}
Response: 
HTTP 1.1 200
{“id” : 1,“items” : [“item” : {“id” : 1234}]
}

因此,现在我们要使用资源终结点而不是所有请求都将通过的匿名终结点。 但是,我们与服务互动的性质尚不清楚。 当我们发布到/ items / 1234时,是在创建一个新项目还是要检索? 当我们发布到/ orders / 1时,是在更新现有实体还是创建一个新实体? 在发送请求时,客户端尚不清楚这些交互。

HTTP

到目前为止,我们一直主要使用HTTP作为客户端与RESTful服务进行交互的传输机制。 在此级别,我们将开始使用已定义的HTTP规范。 到目前为止,我们已经使用POST提交了所有请求,现在我们将开始使用更合适的HTTP动词(方法类型)。 这不是一条单向的街道,但是我们的服务器还会响应更合适的状态代码,而不是对每个成功的请求都响应200状态代码。

下表列出了RESTful服务通常实现的动词以及对这些动词的一些约束。 如果您不熟悉“幂等”一词(作者曾经),那么请知道,这意味着当执行次数大于零时,执行请求的副作用是相同的。

GET调用应始终返回相同的项目列表。 DELETE请求应该删除元素,但是后续的DELETE请求应该不会改变服务器的状态。 注意,这并不意味着响应总是必须相同。 在第二个示例中,第二个DELETE请求可能返回错误响应。 安全意味着该操作不会影响服务器的状态。 GET仅用于检索,它不会更改正在检索的资源的状态。 但是,PUT请求可能导致状态更改,因此不是安全动词。

安全 不安全
势力 GET,HEAD,TRACE,选项 删除,放入
不占优势 开机自检


当我们开始在交互中使用正确的HTTP动词和状态代码时,这就是交互的外观:

GET: /items/1234
Response:
HTTP 1.1 200
{“id” : 1234,“description” : “FooBar TV”,“image” : “fooBarTv.jpg”,“price” : 50.00
}
PUT: /orders/1
{“items” : [“item” : {“id” : 1234}]
}
Response: 
HTTP 1.1 226
{“items” : [“item” : {“id” : 1234}]
}

即使不深入了解HTTP规范,客户端与服务器之间的交互也变得更加清晰。 我们正在从服务器获取项目; 我们正在服务器上放置一些东西。 有一些字幕可以帮助您理解HTTP,了解PUT意味着修改会告诉开发人员一个订单已经存在,而我们正在修改它,而不是创建新订单(可能是POST请求)。

理解HTTP状态代码还将使开发人员对服务器如何响应来自客户端的请求有更多的了解。 虽然我们的服务器仍对初始GET请求返回适当的200响应,但服务器现在发送的PUT请求响应为226(已使用IM),这意味着仅返回已更改资源的增量。 如果您在“资源”部分下查看向订单添加商品的响应,则服务器将返回订单ID和商品列表。 在此响应中,仅返回添加到订单中的项目。 如果订单中已经有其他项目,则它们也将在“资源”响应中返回,但在此响应中将其省略。

或者,如果不存在ID为1234的项目,则HTTP已经定义了正确的响应,而不是返回空的响应正文或某种错误消息。 你能猜出来吗?

GET: /items/1234
Response:
HTTP 1.1 404

超媒体控件

以上为电视下订单的场景为实现超媒体控件带来好处提供了一个很好的用例。 在此情况下,我已经假设用户已经有一个ID为“ 1”的预先存在的订单,但是可能并非总是如此。

在不使用HATEOAS将状态应用程序传达给客户端的情况下,客户端必须足够聪明才能确定用户是否有未结订单,如果有,则确定该订单的ID。 这将导致工作重复,因为确定用户状态的业务逻辑现在同时存在于客户端和服务器上。 随着业务的变化,客户端和服务器之间将具有依赖关系来确定用户订单的状态,客户端和服务器代码都将发生更改,并且需要协调两者之间的发布。 HATEOAS通过通过返回的链接告知客户端状态(即客户端下一步可以做什么)来解决此问题。

GET: /items/1234
Response:
HTTP 1.1 200
{“id” : 1234,“description” : “FooBar TV”,“image” : “fooBarTv.jpg”,“price” : 50.00,“link” : {“rel” : “next”,“href” : “/orders”}}
}
POST: /orders
{“id” : 1,“items” : [{“id” : 1234}]
}Response:
HTTP 1.1 201:
{“id” : 1,“items” : [{“id” : 1234}
]
links : [{“rel” : “next”,“href” : “/orders/1/payment”}, {“rel” : “self”,“href” : “/orders/1”}]
}

可以省去确定用户是否有有效订单的相对简单性,因为它不够复杂,不足以证明在服务器端实施HATEOAS然后开发可以解释服务产生的超媒体控件的客户端所花的时间(都不其中是微不足道的)。 也就是说,该示例也非常简单,仅代表客户端和服务器之间的一种交互。

死亡,税收和变化,HATEOAS就是这样

开发人员知道,“唯一可以确定的就是死亡和税收”的成语是错误的,第三个可以肯定的是:变化。 任何开发的应用程序都将在其生命周期内发生变化; 添加了新的业务需求,修改了现有的业务需求,并一起删除了一些业务需求。

虽然我不希望HATEOAS成为银弹,但我确实相信HATEOAS是为数不多的技术之一,随着遇到现实问题,其收益会增加。 以下是三个用例的示例,这些用例结合在一起以及可以想象的其他用例,为您为什么要在RESTful服务中实现HATEOAS奠定了有力的案例。

用例1:管理员和普通用户通过同一客户端进行交互

普通用户和管理员都使用同一客户端与服务进行交互。 在这种使用情况下,普通用户将只能在/ items资源上执行GET,但是管理员也将具有PUT和DELETE特权。 如果我们在Richardson成熟度模型(HTTP)的第2级上停止,我们将需要让客户端了解用户所具有的特权类型,以便正确地向用户呈现接口。

使用HATEOAS,可能就像客户端呈现服务器发送的一些新控件一样简单。 这是请求中的不同之处。 另外,我们可能不希望管理员下达订单:

Request:
[Headers]
user: bob
roles: USER
GET: /items/1234
Response:
HTTP 1.1 200
{“id” : 1234,“description” : “FooBar TV”,“image” : “fooBarTv.jpg”,“price” : 50.00,“links” : [{“rel” : “next”,“href” : “/orders”}]	}
}
Request:
[ Headers ]
user: jim
roles: USER, ADMIN
GET: /items/1234
Response:
HTTP 1.1 200
{“id” : 1234,“description” : “FooBar TV”,“image” : “fooBarTv.jpg”,“price” : 50.00,“links” : [{“rel” : “modify”,“href” : “/items/1234”},{“rel” : “delete”,“href” : “/items/1234”}]	}
}

用例2:管理员不再可以删除

业务需求发生变化,管理员不再能够删除项目。 在上一个用例中,很可能会说不需要更改客户端(例如,管理员用户需要使用表单来修改项目的字段),但是删除DELETE动词绝对可以完成而无需更改客户。

随着HATEOAS服务不再返回DELETE链接,客户端将不再将其显示给管理员用户。

Request:
[Headers]
user: jim
roles: USER, ADMIN
GET: /items/1234
Response:
HTTP 1.1 200
{“id” : 1234,“description” : “FooBar TV”,“image” : “fooBarTv.jpg”,“price” : 50.00,“links” : [{“rel” : “modify”,“href” : “/items/1234”}]	}
}

用例3:用户可以出售自己的商品

企业现在要求用户具有销售自己的用户商品的能力。 这个用例比前两个更为实际,开始显示出客户端上业务逻辑的数量和复杂性Swift增加,并且还引入了客户端和服务器之间的可能耦合。

用户可以出售自己的物品,但他们也只能只修改自己准备出售的物品。 用户Bob不能修改用户Steve的项目,反之亦然。 解决此问题的常见方法可能是在项目实体内返回一个指定所有权的新字段,但是现在我们正在修改项目,只是为了使我们的客户端可以出于任何业务原因向用户正确呈现界面。

现在,我们正在引入客户端和服务器之间的耦合,并且它们之间的界限很快开始变得模糊。 有了HATEOAS服务,至少对于客户而言,这种复杂性就很多了,并且我们的项目实体保持不变。 以下是一些带有和不带有HATEOAS的示例请求,请注意,在HATEOAS示例中,响应的外观与用例1的响应相同。

没有HATEOAS:

Request:
[Headers]
user: jim
roles: USER
GET: /items/1234
Response:
HTTP 1.1 200
{“id” : 1234,“description” : “FooBar TV”,“image” : “fooBarTv.jpg”,“price” : 50.00,“owner” : “jim” 
}

使用HATEOAS:

Request:
[Headers]
user: jim
roles: USER
GET: /items/1234
Response:
HTTP 1.1 200
{“id” : 1234,“description” : “FooBar TV”,“image” : “fooBarTv.jpg”,“price” : 50.00,“links” : [{“rel” : “modify”,“href” : “/items/1234”},{“rel” : “delete”,“href” : “/items/1234”}]	}
}

摘要

尽管REST的第一个样式约束要求将客户端和服务器之间的关注点分离,但是在不实现HATEOAS的过程中,此样式约束受到了损害。 围绕如何计算用户状态的业务逻辑进行更改意味着需要在客户端和服务器上都进行更改。 客户端和服务器的独立可扩展性丢失(必须同步客户端和服务器的发布),并且重复进行业务逻辑。 世界需要更多的HATEOAS来解决这个问题。

参考书目

  • http://roy.gbiv.com/untangled/2008/rest-apis-must-be-超文本驱动
  • http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven#comment-745
  • https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
  • http://martinfowler.com/articles/richardsonMaturityModel.html
  • https://zh.wikipedia.org/wiki/No_Silver_Bullet
  • http://www.crummy.com/
  • http://www.crummy.com/writing/speaking/2008-QCon/act3.html

翻译自: https://www.javacodegeeks.com/2016/03/dont-hate-hateoas.html

突然讨厌做前端,讨厌代码

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

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

相关文章

【WebRTC---进阶篇】(三)各流媒体服务器的比较

多人音视频架构 Mesh方案 多对多大多进行P2P,在国内P2P直连穿越会出现很大问题。 MCU方案 客户端连接后,对应每个终端都有一个模块进项上传。再将音视频进行拆分解码。进行混屏,压缩编码分别推动给每个终端。 SFU方案 sfu不进行编解码,只是进行转发。只对订阅的终端进行…

汇编 cmp_汇编复习

第一章计算机组成五部分:(运算器、控制器)、存储器、输入/输出设备↑↑ CPU ↑↑ ↑内存↑三条总线:控制总线、地址总线、数据总线不同进制及BCD码的转换特殊ascll ‘0’~‘9’—— 30H ~ 39H‘A’~‘F’—— 41H ~ 46H回车 —— …

junit5和junit4_JUnit 5 –设置

junit5和junit42015年11月, JUnit Lambda团队展示了他们的原型 。 此后,该项目更名为JUnit 5,并于2016年2月发布了Alpha版本。我们将在一系列简短文章中进行探讨: 建立 基本 建筑 条件 注射 … 本节讨论JUnit 5的设置&…

markdown 生成目录_github上如何为markdown文件生成目录

写在前面熟悉markdown都知道可以使用[TOC]自动生成markdown文件的标题目录,比如在typora,vscode(需要插件)等本地编辑器中,或者在CSDN等网页编辑器中,但是github却不支持[TOC]标签,至于为什么不支持感兴趣的可以深入搜…

【WebRTC---进阶篇】(五)mediasoup的信令系统

mediasoup demo分析 app 客户端部分 broadcasters 推拉流部分 server 服务端部分 config.js 相当于一个配置文件,获取一些基本配置信息。获取的信息来交给server.js。 server.js 先从config.js获取信息,然后启动HTTPS webSocket服务等,…

axure html尺寸,axure怎么确定尺寸

回答:您好如做的是室内设计的话,那么来说可能会些参数提供给您的(例如长宽高)如果没有参数的话,只要把比例做好就可以了。只要比例做好了,东西看起来就自然像。至于教程的话,一般录制教程前都会有做好准备的&#xff0…

exe打包工具哪个最好_为你的 Python 程序写个启动工具箱

到目前为止,公众号已经介绍了不少图形界面的软件,比如猜数游戏、PDF阅读器、贪吃蛇游戏、天气查询软件、PDF 阅读器等。为了方便他人使用,我们常把图形界面打包成 exe 文件。但是如果我们只是为了自己使用方便的话,我们有必要把程…

【WebRTC---进阶篇】(六)SELECT网络模型

select函数原型 int WSAAPI select(_In_ int nfds,_Inout_opt_ fd_set FAR * readfds,_Inout_opt_ fd_set FAR * writefds,_Inout_opt_ fd_set FAR * exceptfds,_In_opt_ const struct timeval FAR * timeout); 函数功能:监视多个文件描述符的状态变化,在IO中负责IO的第一步…

计算机管理没有打印机列队,在Windows清除打印队列如果打印机被卡住,也没有打印输出...

我相信自己已经勾起回忆一拉似曾相识 ,右侧的主题? 我们每个人,在一段时间或其他,都在打印过程中面临的问题,特别是给打印命令,并打印输出不休后等待。 无论是在家里还是办公室里,那就是我们所有…

gatling 使用_使用Gatling + Gradle + Jenkins Pipeline为您的JAX-RS(和JavaEE)应用程序进行连续压力测试...

gatling 使用在这篇文章中,我将解释如何使用Gatling项目为您的JAX-RS Java EE端点编写压力测试,以及如何将它们与Gradle和Jenkins Pipeline集成,因此,除了进行简单的压力测试外,您还可以使用以下方法: 连续…

java comparator_【面试题】Java必考面试题全集(15)

Java基础面试题(15)1:Comparator 与Comparable 有什么不同?2:Object中有哪些方法?3:说下jdk8中的一些新特性4:在64 位 JVM 中,int 的长度是多数?5:java每改一点都需要重新…

px是什么意思计算机二级,px是什么意思?照片中的px是什么的缩写?

px是什么意思?px(Pixel,像素)是可以在数字显示设备上显示和表示的数字图像或图形的最小单位。像素是数字图形中的基本逻辑单元。将像素组合在一起以在计算机显示器上形成完整的图像,视频,文本或任何可见的东西。像素也称为图像元素。若把影像…

java 交替_Java 8:使用交替接口公开的类型安全地图生成器

java 交替动态展示您的课程 当我还是Java新手时,我记得当时以为应该有一种方法可以删除或隐藏我不想公开的类中的方法。 就像用private方法或类似方法覆盖public方法一样(哪种情况是不可能的,也不应该是不可能的)。 显然&#xff…

ieee期刊_论文绘图神器来了:一行代码绘制不同期刊格式图表,哈佛博士后开源...

贾浩楠 发自 凹非寺量子位 报道 | 公众号 QbitAI「一篇论文投多个期刊,每个期刊对图表格式要求不一,同一组数据要用多种工具分别绘图。」不光是你,哈佛大学天文研究所的博士后,也不堪忍受论文重复绘图之苦。他的解决办法是&#x…

微课与计算机技术的论文,微课在高校计算机教学的运用论文

微课在高校计算机教学的运用论文摘要:现代信息社会不断发展进步,高校计算机教学也面临着复杂的形势,为全面提高计算机教学质量,提升学生的专业素质及综合能力,应当微课加以科学化应用。本文基于微课的内涵及应用意义出…

spring 启动加载数据_12个很棒的Spring数据教程来启动您的数据项目

spring 启动加载数据Spring Data的任务是为数据访问提供一个熟悉且一致的,基于Spring的编程模型,同时仍保留基础数据存储的特​​殊特征。 它使使用数据访问技术,关系和非关系数据库,map-reduce框架以及基于云的数据服务变得容易…

concurrenthashmap_ConcurrentHashMap是如何保证线程安全的

文章已同步发表于微信公众号JasonGaoH,ConcurrentHashMap是如何保证线程安全的之前分析过HashMap的一些实现细节,关于HashMap你需要知道的一些细节, 今天我们从源码角度来看看ConcurrentHashMap是如何实现线程安全的,其实网上这类文章分析特别…

【OpenGL从入门到精通(三)】第一个点的理论

OpenGL状态机 一,OpenGL是一个状态机matrix中包括: model view (模型矩阵) worldpos(世界坐标,也称为顶点坐标)通过mv(模型矩阵)转到cameru摄像机下(根据右手坐标系,只有在Z的负方向才可以看得见) projection …

js find的用法_React常用库Immutable.js常用API

JavaScript 中的对象一般是可变的(Mutable),因为使用了引用赋值,新的对象简单的引用了原始对象,改变新的对象将影响到原始对象。如 foo{a: 1}; barfoo; bar.a2 你会发现此时 foo.a 也被改成了 2。虽然这样做可以节约内存,但当应用…

教学案例 计算机,计算机教学案例

海量优秀的免费计算机教学案例范文供您参考与下载,关于计算机教学案例的免费论文范文参考资料是由2016年最新的相关论文题目按照标准论文格式模板写作的,适合不知道怎么写计算机教学案例的大学毕业生,对相关的本科论文和硕士毕业论文及职称论文发表写作有参考价值&a…