在以前的文章 系列中,我们简要地讨论了组织和运作框架台风的基本原则 -为iOS依赖注入容器。 但是,如何将工具布置一点理解-最重要的是要正确地使用它。 在第一部分中,我们看的创建依赖关系,现在处理更高级别的配置设置的各种例子-模块分为TyphoonAssembly自己和测试。
周期“在iOS中右依赖驱动的应用程序”
- 熟悉台风
- 该器件台风
- 模块化台风
- 台风技巧与诀窍
- 台风替代品
- (可选)Rambler.iOS#3。 依赖注入的iOS。 幻灯片
- (可选)Rambler.iOS#3。 依赖注入的iOS。 视频
为什么模块化
利用一个相当简单的应用程序的例子-在气象服务客户端(顺便说一下, 的演示应用程序之一 )。 它由以下屏幕:
- 城市列表其中有气象资料
- 有关所选城市的天气信息,
- 添加一个新的地理点,
- 应用程序设置。
再就是第一种方法,嫌definition‘y这些屏幕。
计数器技术:4
我们先从UI一会儿,转移到业务逻辑层的结构。 所有逻辑相关的功能,我们组到单独的每个其他实体的独立,称为服务。 他们执行以下任务:
- 经营城市的名单(获得城市的集合,添加/删除/修改其中的任何)
- 获取气象资料(有关天气所选城市获取信息)
- 工程与地理定位(获取当前用户的地理位置,他的运动的历史)
- 处理推送通知(注册设备订购设置)
- 获取数据有关应用程序(合格证,许可证,版本)。
计数器技术:5 + 4 = 9
由自己,这些服务都相当无用的,因为他们只描述应用程序的业务逻辑的某些规则。 让我们来看看他们需要什么,这取决于。
我们需要几个客户(实体负责相互作用与外部数据源)。 夸大和现状时,工作将不得不天气几个供应商。
- 与你的服务器交互,
- 工作与API服务天气1
- 使用API?? 2全天候服务,
- ...
- 与API服务天气N个工作,
- 使用的数据库。
反技术9 + N + 2 = 11 + N
除了客户,每个网络服务需要映射器(负责转换从服务器接收到一个模型对象的原始数据),以及验证器(负责检查数据)。
计数器技术:11 + N + 2 *(N + 1)= 13 + 3n的
不要忘了一些伟大的帮手:
- 日志记录,
- 与networkActivityIndi??cator工作,
- 监控连接的状态
计数器技术:13 + 3N + 3 = 16 + 3N
对实体的数量并没有结束,因为我们回去层UI。 取决于体系结构,依赖于每个屏幕的数目可以达到几十。 当然,我们做一个简单的应用程序,所以我们只选择了最必要的设施:
- 动画状态屏幕
- 数据源(表或视图中的任何不重要),
- 一个封装与滚动相关的逻辑对象,
- 路由器实现屏幕之间的导航,
- 与当前屏幕相关联的错误处理程序。
计数器技术:16 + 3N + 4 * 5 = 36 + 3N
在此式中,n -的天气服务,这是必要的正确的应用程序的数据数量。 我们想用Gismeteo,Yandeks.Pogodu和Yahoo.Weather。
计数器技术:36 + 3 * 3 = 45
四五方法来配置各种视,看似非常简单的应用。 如果我们停留在一个TyphoonAssembly,那么我们将有一些非常严重的问题:
- 该类TyphoonAssembly的巨大规模 -这将是非常困难的分析和维护清洁。
- 模糊的责任 -创建对象完全不同的,无关的抽象对方发生层在同一个地方。
- 的结构缺乏 -如果必要的话,不能提供不同的实现并逻辑连接definition‘ov。
为了避免这种问题,TyphoonAssembly分成模块,它们是相互连接的水平和垂直方向。 正如我所说的,在最后一部分 ,事实上,几个组件的引擎盖下激活已经创建了一个共同的TyphoonComponentFactory,包含所有definition‘ov和池创建的对象的登记册。 这个架构框架使我们能够安全地分解TyphoonAssembly,这是通常用于访问一个工厂的内部的代理。
来概括。 模块化TyphoonAssembly级需要:
- 根据分组相互连接,从而构建一个清晰的架构
- 支持的每个组件清洁接口,并宣布只方法都需要其他组件,
- 提供,如果需要的话,不同的实现中的任何所选择的组分(如客户的水平)
- 为了让一个陌生人,使代表对整个项目仅在TyphoonAssembly模块的结构建筑。
分成模块
不只是组独立的子类TyphoonAssembly逻辑相关的项目 -在大多数情况下,他们必须知道对方什么。 回到上面的例子中的天气应用程序,看看有什么需要根据从选定城市的天气信息在屏幕上:
接口RCTWeatherViewController:的UIViewController
在此基础上,我们需要构建三个不同组件之间的相互作用的模型- 创建分别控制器,服务和动画“啊哈!” -你的想法。 - “这个家伙是谁开始一个单元注入到另一个,一般写厂厂!”不应该赶快行动吧! 一个下一个伟大的机会,台风是模块的交互不需要任何进一步的注入。 这足以接口TyphoonAssembly指定需要为它工作的其他模块 -你可以放心地使用他们的公共方法:
接口RCTWeatherUserStoryAssembly:TyphoonAssembly
因此该方法会寻找TyphoonDefinition‘a:
- (*的UIViewController)weatherViewController
离题。 这是可能的,而不是直接指导组件及其方法,类似于以下使用的语法:
[定义injectProperty:选择(cityService)] ;
在这种情况下,台风取属性类型(类或协议),并寻找所有组件项目的合适定义。 不过,我不建议使用这种方法
- 是该项目的其他参与者更加清晰,并为您的未来,将直接指示依赖的起源。 此外,这将避免抽象的不同层之间的隐含装配关系。
正如我所提到的,模块可以连接或者水平(例如,组件,用于不同用户的故事)(以上RCTWeatherUserStoryAssembly和RCTServiceAssembly中的例子),并垂直。 为了建立一个称职的架构TyphoonAssembly,需要严格遵守以下规则:
- 在相同的抽象级模块一无所知对方,
- 下层的模块不知道关于顶层模块什么。
模块的最基本的例子TyphoonAssembly打入层:
每个里面层都可以由任意数目的组件。 例如,根据不同的呈现水平的有意义的跨多个用户故事拆分。
考虑打破TyphoonAssembly模块为例较为复杂的情况下,像往常一样,Rambler.Pochty。
结构大会Rambler.Pochte
一般来讲,??所有的模块分为三个标准层 - 表示,业务逻辑和核心。
我们去了所有的组件:
- RCMApplicationAssembly。 负责创建应用程序级的对象- AppDelegate中,PushNotificationCenter,ApplicationConfigurator等。 这取决于其它两个模块- helperAssembly和serviceComponents。
- RCMUserStoryAssembly。 在Rambler.Pochte每个故事情节都有自己的议会,由otnasledovannaya RCMUserStoryAssemblyBase。在这些模块包含definition‘y为ViewController‘ov,路由器,动画师,视图模型和其他依赖关系是唯一的一个给定用户的故事。 取决于helperAssembly,parentAssembly和serviceComponents。
- RCMSettingsUserStoryAssemblyBase / RCMSettingsUserStoryAssemblyDebug。 根据构建计划(发布/调试),它提供了不同的实现依赖设置屏幕(更多的谈论后)。 这种方法可以很容易地添加的应用程序设置特殊功能的测试谁是缺席的App
Store中的组件。 - RCMParentAssembly。 它包含了基本的definition‘y控制器,路由器和错误处理程序。 我不知道如何生产没有真正的实例(所有标记为抽象的)。 没有一个人是独立的。
- RCMHelperAssembly。 它提供了各种辅助层演示,需要UserStoryAssembly多个组件定义。 没有一个人是独立的。
- RCMServiceComponentsAssemblyBase。 它包含了所有的definition‘y服务的应用程序。 这取决于两个模块的内核- clientAssembly和coreComponentsAssembly。
- RCMServiceComponentsAssemblyDouble。 与此相反的底座组件,返回feykovye执行工作的所有服务,不需要与因特网交互。 没有一个人是独立的。
- RCMClientAssembly。 负责创建各种客户。 没有一个人是独立的。
- RCMCoreComponentsAssembly。 负责创建所需的服务的操作辅助部件。 没有一个人是独立的。
事实上,没有人打扰,进一步打破RCMServiceComponents RCMCoreComponents和几个独立的模块互相 -但它是值得做的事情增加他们的代码库。
当然,所有这些模块必须在同一时间被激活- 最好是通过加入合适的键在Info.plist中要做到这一点,但是可以手动实现一个特殊的方法的AppDelegate(细节 在周期的第二部分 )。
换人实现大会
考虑两种典型情况:
- 我们要开始工作的应用程序服务器上,但球队还没有来得及铺开的API。
- 一个足够大的项目开发商的发展提出了一些 - 他们中的一些计划来处理用户界面,以及其他 - 业务逻辑,并在彼此隔离。
这两种情况都结合相同的 - 需要开始在上层应用程序的工作(尤其是在UI),在没有业务逻辑。 在大会Rambler.Pochte解决这个问题的图可以看出,在商业逻辑层的水平。
书面协议指定哪些方法应该实现当前模块,及其两个实施 - 的基地,将尽快填补现有API和服务层,并制造假,包含运行,例如服务的最基本的实现,与内存数据库。
让我们来看看如何通过预处理文件的Info.plist的机制实现:
- 创建两个文件- BaseHeader.h和DoubleHeader.h:
BaseHeader:
#定义 SERVICE_COMPONENTS_ASSEMBLY RCMServiceComponentsAssemblyBase
连赛:
#定义 SERVICE_COMPONENTS_ASSEMBLY RCMServiceComponentsAssemblyDouble
- 在该文件的Info.plist,下TyphoonInitialAssemblies而非特定类RCMServiceComponentsAssemblyBase仅指示一个给定的指令 -SERVICE_COMPONENTS_ASSEMBLY。
- 构建设置项目,寻找关键部分包装的Info.plist预处理前缀的文件,并为每个使用的这些计划的集结设置适当的头文件。 例如,发布 -BaseHeader.h,调试 - DoubleHeader.h。
现在,取决于叠合电路是否被选择来运行应用程序,它将被连接到相应的装配,并用于任一战斗服,或它们feykovye实现。
在某些情况下,这是没有必要更换所有对象的创建假实现和需要更换只有一个依赖。 在这种情况下,将使用类别TyphoonDefinition
+选项 ,其中的细节,我将在下一篇文章讨论。
测试模块TyphoonAssembly
像任何其他应用程序组件,所有的子类TyphoonAssembly进行测试。 仅与组装测试全覆盖,它们可以在集成测试中使用。
第一步是确定应该怎样进行测试:
- 方法激活TyphoonAssembly创建所需的类,
- 创建的对象包含了所有必要的依赖,
- 所有取决于创建的对象上实现所需的协议/班。
为了减少样板代码我已经准备了量的基础XCTestCase ,TyphoonAssembly简化了测试:
接口RCMAssemblyTestsBase:XCTestCase
下面是测试方法大会之一:
- (无效)testThatAssemblyCreatesApplicationBadgeHandler
在大会的情况下,应测试不仅公共方法,但私人 - 因为我们要检查所有的依赖是否在应用正确的。 准备创建扩展_Testable为每个选定的模块。
我必须承认,即使在这样的方式来覆盖大会面团的所有方法 - 足够费时和乏味业务,所以其放在发展的最后阶段是没有必要的。 只是开发增加新的测试用例又一definition‘a的TyphoonAssembly外观的习惯。
闭幕
在这篇文章中,我们了解到为什么你需要打破一个大的大会分成几个小的模块,以及如何做是正确的。 该方案是打破所有的模块到层- 表示,业务逻辑和核心,在这种或那种形式可以在几乎任何项目中使用。 此外,在适当的构造模块结构变得可以替换任何这些feykovye实现,可在基本版本工作期间被用作插头。
TyphoonAssembly它是项目,在其上搁置在整个连接组件彼此的最重要的组件之一 -因此它必须被彻底的测试。 对于本身这个冗长的过程付费多次在项目的过程。
看完这部分的周期后,您已做好充分准备,整合台风框架项目,无论完成百分比。 在接下来的文章中,我们将着眼于各种技巧与诀窍使用台风:自动装配,TyphoonConfig,TyphoonPatcher,尤其是与多个UIStoryboard和更多的工作。
周期“在iOS中右依赖驱动的应用程序”
- 熟悉台风
- 该器件台风
- 模块化台风
- 台风技巧与诀窍
- 台风替代品
- (可选)Rambler.iOS#3。 依赖注入的iOS。 幻灯片
- (可选)Rambler.iOS#3。 依赖注入的iOS。 视频