Advertisement
Guest User

Untitled

a guest
Oct 21st, 2019
104
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.19 KB | None | 0 0
  1. // Deps1.playground
  2.  
  3. import UIKit
  4.  
  5. // Design issues / decisions:
  6. //
  7. // - should "providing" protocols use funcs or vars?
  8. // - i.e. `var serviceA` vs `func serviceA()`
  9. //
  10. // - for deps which themselves have deps ("internal nodes of the deps tree"),
  11. // should they take a deps object or should we ban them from using the deps pattern?
  12. // - i.e. if C depends on A and B, should we `class ServiceC { init(deps: Deps) }`
  13. // or should we `class ServiceC { init(a: ServiceA, b: ServiceB) }`?
  14. //
  15. // - if internal nodes take a deps object, the deps object will run into a bootstrapping problem
  16. // (`ServiceC.init()` needs a `Deps` and `Deps.init()` needs a `ServiceC`)
  17. // - we can get around this by using force-unwrapped vars (and a static builder method)
  18. // - or avoid the issue by banning internal nodes from using the deps pattern.
  19. //
  20. // - if internal nodes are banned from the deps pattern, we lose the ability to replace
  21. // a dep at run-time and have every part of the system automatically start using the new
  22. // dep (if ServiceC uses ServiceA (given via init), replacing Deps.serviceA
  23. // at runtime with a fake does not affect ServiceC, which will still use the original A).
  24.  
  25.  
  26.  
  27. // This playground explores:
  28. // - "providing" protocols use vars
  29. // - "internal" nodes use deps pattern
  30. // - use force-unwrap to work-around the bootstrapping problem
  31.  
  32. // Ultimately, it looks like this approach will not work because `var foo: Foo!`
  33. // does not satisfy a `var foo: Foo { get }` protocol.
  34.  
  35.  
  36.  
  37. // service data types
  38.  
  39. public typealias A = Int
  40. public typealias B = Int
  41. public typealias C = (A,B)
  42.  
  43.  
  44.  
  45. // service protocols
  46.  
  47. public protocol AServicing {
  48. func getAs() -> [A]
  49. }
  50.  
  51. public protocol BServicing {
  52. func getBs() -> [B]
  53. }
  54.  
  55. public protocol CServicing {
  56. func getCs() -> [C]
  57. }
  58.  
  59.  
  60.  
  61. // service implementations
  62.  
  63. public class AService: AServicing {
  64. public func getAs() -> [A] {
  65. return [1,2,3]
  66. }
  67. }
  68.  
  69. public class BService: BServicing {
  70. public func getBs() -> [B] {
  71. return [11,12,13]
  72. }
  73. }
  74.  
  75. public class CService: CServicing {
  76.  
  77. public init(deps: AServiceProviding & BServiceProviding) {
  78. _deps = deps
  79. }
  80.  
  81. public func getCs() -> [C] {
  82. return Array(zip(_deps.aService.getAs(), _deps.bService.getBs()))
  83. }
  84.  
  85. private let _deps: AServiceProviding & BServiceProviding
  86. }
  87.  
  88.  
  89.  
  90. // deps protocols
  91.  
  92. public protocol AServiceProviding {
  93. var aService: AServicing { get }
  94. }
  95.  
  96. public protocol BServiceProviding {
  97. var bService: BServicing { get }
  98. }
  99.  
  100. public protocol CServiceProviding {
  101. var cService: CServicing { get }
  102. }
  103.  
  104.  
  105.  
  106. // deps implementation
  107.  
  108. public class Deps: AServiceProviding, BServiceProviding, CServiceProviding {
  109. public var aService: AServicing
  110. public var bService: BServicing
  111. // this fails to compile because the force-unwrapped version apparently doesn't satisfy the protocol requirement:
  112. public var cService: CServicing!
  113.  
  114. public init(aService: AServicing, bService: BServicing) {
  115. self.aService = aService
  116. self.bService = bService
  117. }
  118.  
  119. public static func makeDeps(
  120. aService: AServicing,
  121. bService: BServicing,
  122. cService: CServicing? = nil
  123. ) -> Deps {
  124.  
  125. let deps = Deps(aService: aService, bService: bService)
  126. deps.cService = cService ?? CService(deps: deps)
  127. return deps
  128. }
  129. }
  130.  
  131.  
  132.  
  133. // Some objects which use the deps:
  134.  
  135. public class ControllerAB {
  136. public let deps: AServiceProviding & BServiceProviding
  137. public init(deps: AServiceProviding & BServiceProviding) {
  138. self.deps = deps
  139. }
  140.  
  141. public func total() -> Int {
  142. return (deps.aService.getAs() + deps.bService.getBs())
  143. .reduce(0, { $0 + $1 })
  144. }
  145. }
  146.  
  147. public class ControllerC {
  148. public let deps: CServiceProviding
  149. public init(deps: CServiceProviding) {
  150. self.deps = deps
  151. }
  152.  
  153. public func total() -> Int {
  154. return deps.cService.getCs()
  155. .reduce(0, { $0 + $1.0 + $1.1 })
  156. }
  157. }
  158.  
  159.  
  160.  
  161. // use real services:
  162.  
  163. let a = AService()
  164. a.getAs() // [1,2,3]
  165.  
  166. let b = BService()
  167. b.getBs() // [11,12,13]
  168.  
  169. let deps1 = Deps.makeDeps(aService: a, bService: b)
  170.  
  171. let c = CService(deps: deps1)
  172. c.getCs() // [(1,11),(2,12),(3,13)]
  173. deps1.cService.getCs() // [(1,11),(2,12),(3,13)]
  174.  
  175. let controllerab1 = ControllerAB(deps: deps1)
  176. controllerab1.total() // 42
  177.  
  178. let controllerc1 = ControllerC(deps: deps1)
  179. controllerc1.total() // 42
  180.  
  181.  
  182.  
  183. // fake A and B implementations:
  184.  
  185. public class FakeAService: AServicing {
  186. public func getAs() -> [A] {
  187. return [-1,-2,-3]
  188. }
  189. }
  190.  
  191. public class FakeBService: BServicing {
  192. public func getBs() -> [B] {
  193. return [-11,-12,-13]
  194. }
  195. }
  196.  
  197.  
  198.  
  199. // use fake A with real C:
  200.  
  201. let fa = FakeAService()
  202. fa.getAs() // [-1,-2,-3]
  203.  
  204. let deps2 = Deps.makeDeps(aService: fa, bService: b)
  205. let c2 = CService(deps: deps2)
  206. c2.getCs() // [(-1,11),(-2,12),(-3,13)]
  207. deps2.cService.getCs() // [(-1,11),(-2,12),(-3,13)]
  208.  
  209. let controllerab2 = ControllerAB(deps: deps2)
  210. controllerab2.total() // 30
  211.  
  212. let controllerc2 = ControllerC(deps: deps2)
  213. controllerc2.total() // 30
  214.  
  215.  
  216.  
  217. // fake B with real C:
  218.  
  219. let fb = FakeBService()
  220. fb.getBs() // [-11,-12,-13]
  221.  
  222. let deps3 = Deps.makeDeps(aService: a, bService: fb)
  223. let c3 = CService(deps: deps3)
  224. c3.getCs() // [(1,-11),(2,-12),(3,-13)]
  225. deps3.cService.getCs() // [(1,-11),(2,-12),(3,-13)]
  226.  
  227. let controller3 = ControllerAB(deps: deps3)
  228. controller3.total() // -30
  229.  
  230. let controllerc3 = ControllerC(deps: deps3)
  231. controllerc3.total() // -30
  232.  
  233.  
  234.  
  235. // fake A and fake B with real C:
  236.  
  237. let deps4 = Deps.makeDeps(aService: fa, bService: fb)
  238. let c4 = CService(deps: deps3)
  239. c4.getCs() // [(-1,-11),(-2,-12),(-3,-13)]
  240. deps4.cService.getCs() // [(-1,-11),(-2,-12),(-3,-13)]
  241.  
  242. let controllerab4 = ControllerAB(deps: deps4)
  243. controllerab4.total() // -42
  244.  
  245. let controllerc4 = ControllerC(deps: deps4)
  246. controllerc4.total() // -42
  247.  
  248.  
  249.  
  250. // or use a fake C directly:
  251.  
  252. public class FakeCService: CServicing {
  253. public func getCs() -> [C] {
  254. return [(0,0)]
  255. }
  256. }
  257.  
  258. let fc = FakeCService()
  259. fc.getCs() // [(0,0)]
  260.  
  261. let deps5 = Deps.makeDeps(aService: a, bService: b)
  262. deps5.cService.getCs() // [(1,11),(2,12),(3,13)]
  263. deps5.cService = fc
  264. deps5.cService.getCs() // [(0,0)]
  265.  
  266. let controllerab5 = ControllerAB(deps: deps5)
  267. controllerab5.total() // 42
  268.  
  269. let controllerc5 = ControllerC(deps: deps5)
  270. controllerc5.total() // 0
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement