当前位置: 首页 > 知识库问答 >
问题:

构建iOS网络应用程序(REST客户端)的最佳体系结构方法[已关闭]

萧伟兆
2023-03-14

我是一个有经验的iOS开发人员,这个问题对我来说真的很有趣。我看到了很多关于这个话题的不同的资源和材料,但尽管如此,我仍然感到困惑。一个iOS联网应用程序的最佳架构是什么?我指的是基本的抽象框架和模式,它适合每一个网络应用程序,无论是只有少量html" target="_blank">服务器请求的小应用程序,还是复杂的REST客户端。苹果推荐使用MVC作为所有iOS应用程序的基本架构方法,但无论是MVC还是更现代的MVVM模式都没有说明网络逻辑代码应该放在哪里,以及如何组织它。

我是否需要开发类似于MVCS(SforService)的东西,并在此Service层中放置所有API请求和其他网络逻辑,从长远来看,这可能非常复杂?在做了一些研究之后,我找到了两种基本的方法。这里建议为Web服务API(如LoginRequest类或PostCommentRequest类等)的每个网络请求创建一个单独的类,这些类都继承自基本请求抽象类AbstractBaseRequest,此外还创建一些封装公共网络代码和其他首选项的全局网络管理器(如果we具有复杂的对象映射和持久性,则可能是AFNetworking定制或RestKit调优,甚至是具有标准API的自己的网络通信实现)。但这种方法对我来说似乎是一种开销。另一种方法是像第一种方法一样,使用一些单独的API调度器或manager类,但不为每个请求创建类,而是将每个请求封装为这个manager类的实例公共方法,如:FetchContactsLoginUser方法等。那么,什么是最佳和正确的方法呢?还有其他有趣的方法我还不知道吗?

我是否应该为所有这些网络内容创建另一层,如服务网络提供者层或在我的MVC体系结构之上的任何层,或者应该将这一层集成(注入)到现有的MVC层中,如模型

我知道有很好的方法,或者像Facebook客户端或LinkedIn客户端这样的移动怪物是如何应对网络逻辑的指数级增长的复杂性的?

我知道这个问题没有确切和正式的答案。本问题的目标是从经验丰富的iOS开发人员那里收集最有趣的方法。最好的建议方法将被标记为接受并授予声誉赏金,其他将被推翻。它主要是一个理论和研究问题。我想了解基本的、抽象的、正确的iOS网络应用的体系结构方法。我希望有经验的开发人员提供详细的解释。

共有1个答案

汪博达
2023-03-14

我想了解iOS中网络应用程序的基本、抽象和正确的体系结构方法

对于构建应用程序体系结构,没有“最好的”或“最正确的”方法。这是一项很有创意的工作。您应该始终选择最直接和可扩展的体系结构,这对于任何开始从事您的项目的开发人员或团队中的其他开发人员都是清楚的,但我同意,体系结构可以有“好”和“坏”之分。

你说:

它封装应用程序的业务逻辑,控制事务并在其操作的实现中协调响应。

在我们的MVC领域中,服务层类似于域模型和控制器之间的中介。这种方法有一个非常类似的变体,称为MVCS,其中存储实际上是我们的服务层。store提供模型实例并处理网络、缓存等。我想提到的是,您不应该在服务层中编写所有的网络和业务逻辑。这也可以被认为是一个糟糕的设计。要了解更多信息,请查看Anemic和Rich域模型。模型中可以处理一些服务方法和业务逻辑,因此它将是一个“丰富的”(带有行为)模型。

我总是广泛使用两个库:afNetworking2.0和reactivecoA。我认为它是任何与网络和Web服务交互或包含复杂UI逻辑的现代应用程序所必须具备的。

在服务层的所有这些操作之后,调用方(视图控制器)可以在reactivecoa基元的帮助下对响应执行一些复杂的异步操作:信号操作、链接、映射等,或者只订阅它并在视图中显示结果。我在所有这些服务类中注入了依赖项注入我的apiclient,它将把特定的服务调用转换为相应的getpostputdelete等请求,以到达RESTendpoint。在这种情况下,apiclient隐式传递给所有控制器,您可以使用参数化的apiclient服务类显式传递。如果您想为特定的服务类使用apiclient的不同自定义,那么这是有意义的,但是如果您出于某些原因不想要额外的副本,或者您确信您总是使用apiclient的一个特定实例(没有自定义),请将其作为一个单例,但是不要这样做,请不要将服务类作为单例。

然后,每个视图控制器再次使用DI注入它所需的服务类,调用适当的服务方法,并将它们的结果与UI逻辑组合在一起。对于依赖注入,我喜欢使用血魔或更强大的框架台风。我从不使用单例、Godapimanagerwhatever类或其他错误的东西。因为如果您将类称为whatevermanager,这表明您不知道它的用途,而且这是一个糟糕的设计选择。Singletons也是一种反模式,而且在大多数情况下(除极少数情况外)是一种错误的解决方案。只有满足以下所有三个标准时,才应考虑单身:

  1. 无法合理分配单个实例的所有权;
  2. 需要延迟初始化;
  3. 不提供全局访问。

在我们的例子中,单个实例的所有权不是问题,而且在将god manager划分为服务之后,我们也不需要全局访问,因为现在只有一个或几个专用控制器需要特定的服务(例如userprofilecontroller needsuserservices等等)。

我们应该始终尊重s原则,使用关注点分离,所以不要把所有的服务方法和网络调用都放在一个类中,因为这太疯狂了,尤其是在开发大型企业应用程序的时候。这就是为什么我们应该考虑依赖注入和服务方法。我认为这种方法是现代的和后面向对象的。在本例中,我们将应用程序分成两部分:控制逻辑(控制器和事件)和参数。

一种参数是普通的“数据”参数。这就是我们传递函数、操纵、修改、持久化等的内容。这些是实体、聚合、集合、案例类。另一类是“服务”参数。这些类封装业务逻辑,允许与外部系统通信,提供数据访问。

这里是我的架构的一个通用的工作流程示例。假设我们有一个friendsviewcontroller,它显示用户的朋友列表,并且我们有一个从朋友中删除的选项。我在FriendsServices类中创建了一个名为:

- (RACSignal *)removeFriend:(Friend * const)friend

其中friend是一个模型/域对象(或者,如果它们具有相似的属性,它可以只是一个user对象)。在此基础上,该方法将JSON参数friend_idnamesurnamefriend_request_id等的friend解析为nsdictionary。我总是将Mantle库用于这类样板以及用于我的模型层(前后解析、管理JSON中的嵌套对象层次结构等等)。解析之后,调用apiclientdelete方法来发出一个实际的REST请求,并将racsignal中的response返回给调用方(在本例中为friendsviewcontroller),以便为用户显示适当的消息。

如果我们的应用程序是一个非常大的应用程序,我们必须将我们的逻辑分离得更清楚。例如。将'repository'或模型逻辑与'service'一个混合在一起并不总是好的。当我描述我的方法时,我说过'removeFriend'方法应该在'service'层中,但是如果我们更加迂腐的话,我们可以注意到它更好地属于'repository'。让我们记住什么是存储库。Eric Evans在他的书[DDD]中给出了精确的描述:

存储库将某种类型的所有对象表示为一个概念集。除了具有更复杂的查询功能外,它的作用类似于一个集合。

因此,repository本质上是一个门面,它使用集合样式语义(Add、Update、Remove)来提供对数据/对象的访问。这就是为什么当您有诸如GetFriendsListGetUserGroupsRemoveFriend之类的东西时,您可以将其放在Repository中,因为这里类似集合的语义非常清楚。和代码,如:

- (RACSignal *)approveFriendRequest:(FriendRequest * const)request;

绝对是一个业务逻辑,因为它超出了基本的CRUD操作,并且连接了两个域对象(FriendRequest),这就是为什么它应该放在Service层中的原因。我还要注意:不要创建不必要的抽象。明智地使用所有这些方法。因为如果您将用抽象压倒您的应用程序,这将增加它偶然的复杂性,而复杂性在软件系统中引起的问题比其他任何东西都多

我给您描述了一个“旧的”Objective-C示例,但是这种方法可以非常容易地适应Swift语言,并有更多的改进,因为它有更多有用的特性和功能糖。我强烈推荐使用这个库:Moya。它允许您创建一个更优雅的apiclient层(您还记得我们的工作人员)。现在,我们的apiclient提供程序将是一个值类型(enum),其扩展符合协议并利用析构模式匹配。快速枚举+模式匹配允许我们像在经典函数式编程中一样创建代数数据类型。我们的微服务将使用这个改进的apiclient提供程序,就像通常的Objective-C方法一样。对于model layer,您可以使用ObjectMapper库,而不是mantle,或者我喜欢使用更优雅、功能更强大的Argo库。

所以,我描述了我的一般架构方法,我认为它可以适用于任何应用程序。当然,还可以有更多的改进。我建议您学习函数式编程,因为您可以从中获益良多,但也不要在这方面走得太远。通常,消除过多的、共享的、全局可变的状态、创建不可变的域模型或创建没有外部副作用的纯函数是一种良好的实践,新的swift语言鼓励这种做法。但请记住,用大量纯函数模式、类别理论方法重载代码是一个坏主意,因为其他开发人员会阅读并支持您的代码,他们可能会对您不可变模型中的棱镜profunctors和这类东西感到沮丧或害怕。对于reactivecoa也是一样的:不要太过racify您的代码,因为它可能会很快变得不可读,特别是对于新手。当它真的可以简化你的目标和逻辑时就使用它。

因此,阅读大量的内容,混合,实验,并尝试从不同的体系结构方法中找到最好的东西。这是我能给你的最好的建议。

 类似资料:
  • 我是一个iOS开发人员,有一定的经验,这个问题对我来说真的很有趣。我看到了关于这个话题的很多不同的资源和材料,但尽管如此,我还是感到困惑。iOS联网应用的最佳架构是什么?我指的是基本的抽象框架,模式,它将适合每一个网络应用程序,无论是一个只有几个服务器请求的小应用程序,还是一个复杂的REST客户机。苹果建议将 作为所有iOS应用程序的基本架构方法,但无论是 还是更现代的 模式都没有说明将网络逻辑代

  • 问题内容: 我正在制作一个Android应用程序。因为它是如此简单,所以我首先想到我可以简单地消除充当中间件的服务器上对Java应用程序的需求。我尝试使用MySQL的JDBC驱动程序直接连接到数据库,但是我的程序崩溃了,所以我不确定Android是否“支持” MySQL的JDBC驱动程序。 因此,我正在考虑如何实施该应用程序。基本上,应用程序从远程MySQL数据库写入一些数据,并从远程MySQL数

  • 我读了几篇文章,其中告诉我们关于微服务之间的通信,我选择了微服务之间基于事件的通信模式,但是现在我想知道客户端应该如何通信,如果它向API网关发送请求,应该等待响应(这可能需要时间,因为内部microsrvices之间的通信基于事件的性质),或者它应该说“处理”并进行轮询以检查请求是否完成? 客户的标准做法是什么

  • 问题内容: 以下是我典型的程序的整体结构。 funA funB并在用户单击按钮1、2、3时funC打开另一个Toplevel带有窗口小部件的窗口。 我想知道这是否是编写python tkinter程序的正确方法吗?当然,即使我这样写也可以,但这是最好的方法吗?听起来很愚蠢,但是当我看到其他人编写的代码时,他们的代码并没有弄乱一堆函数,而且大多数情况下都有类。 有没有作为良好实践应遵循的特定结构?开

  • 问题内容: 你将如何为Java应用程序实现插件系统? 是否有一个易于使用的(对于开发人员而言)系统可以实现以下目的: 用户将其插件放入应用程序的子目录中 插件可以提供配置屏幕 如果使用框架,那么许可证是否与商业开发兼容? 问题答案: 首先,你需要一个所有插件都需要实现的接口,例如 然后,插件作者应将其插件捆绑到JAR文件中。你的应用程序将打开JAR文件,然后可以使用JAR清单中的属性或JAR文件中

  • 我的应用程序与一些外部服务集成,并向该服务请求数据。我只是想知道在客户端建模响应的最佳实践是什么,尤其是在客户端业务逻辑只需要一些数据的情况下。我正在考虑以下实施: 将JSON转换为包含所有数据/属性的类对象,并在我的代码中使用此类对象 将JSON转换为仅包含进一步处理所需的数据/属性的类对象 以上两者的组合(创建包含所有属性的类对象,然后将其转换为仅包含进一步业务逻辑所需属性的对象)