Reputation: 115
I am trying to write a generic mediator base class (Mediator) that registers peer classes to specific protocols (on peer class extensions), that are defined on instantiation.
Mediator and Peer subclasses are not supposed to know about each other. Their relationship is defined when all is wired up. This is to make each component modular.
If I use only ONE type parameter such as:
class Mediator<T, U> {
private var peers = [T]()
func registerPeer(peer: T) {
self.peers.append(peer)
}
}
Then one Peer registers correctly.
I want both T or U able to be appended to the peers[].
I am looking for a solution that only modifies Mediator's peers[] and registerPeer() to allow a mix or T or U.
// Mediator
class Mediator<T, U> {
// I want this to be an Array that can be T OR U
private var peers = Array<T|U>()
// I want peer: to be either T OR U
func registerPeer(peer: <T|U>) {
self.peers.append(peer)
}
}
class RootModuleMediator<T, U> : Mediator<T, U> {}
protocol RootModuleMediatorsIOInterface { func someFunction() }
extension RootModuleMediator : RootModuleMediatorsIOInterface { func someFunction() { print("RootModuleMediator someFunction() printed")}}
protocol RootModuleMediatorsViewInterface { func aFunction() }
extension RootModuleMediator : RootModuleMediatorsViewInterface { func aFunction() { print("RootModuleMediator aFunction() printed")}}
// Peer
class Peer<T> {
private var mediator : T?
func registerMediator(mediator: T) { self.mediator = mediator }
}
// View Peer
class RootModuleView<T> : Peer<T> {}
protocol RootModuleViewsMediatorInterface { func someFunction() }
extension RootModuleView : RootModuleViewsMediatorInterface { func someFunction() { print("RootModuleView someFunction() printed") }}
// IO Peer
class RootModuleIO<T> : Peer<T> {}
protocol RootModuleIOsMediatorInterface { func someFunction() }
extension RootModuleIO : RootModuleIOsMediatorInterface { func someFunction() { print("RootModuleIO someFunction() printed") }}
// Wiring components together
let rootModuleIO = RootModuleIO<RootModuleMediatorsIOInterface>()
let rootModuleView = RootModuleView<RootModuleMediatorsViewInterface>()
let rootModuleMediator = RootModuleMediator<RootModuleIOsMediatorInterface, RootModuleViewsMediatorInterface>()
rootModuleIO.registerMediator(rootModuleMediator)
rootModuleView.registerMediator(rootModuleMediator)
rootModuleMediator.registerPeer(rootModuleIO)
rootModuleMediator.registerPeer(rootModuleView)
// I want the following function to print "RootModuleIO someFunction() printed"
rootModuleMediator.peers[0].someFunction()
Upvotes: 2
Views: 2078
Reputation: 115
In the end, I could not get T or U type parameters to work with the array or function. Having instead opted for a solution that is more suited to my use case of loosely coupling components and making them communicate over defined interfaces.
// Mediator base
class Mediator<IOTypeParam, ViewTypeParam> {
private var IO : IOTypeParam?
private var view : ViewTypeParam?
func registerIOPeer(peer: IOTypeParam) { self.IO = peer }
func registerViewPeer(peer: ViewTypeParam) { self.view = peer }
}
// Mediator subclass
class RootModuleMediator<IOTypeParam, ViewTypeParam> : Mediator<IOTypeParam, ViewTypeParam> {}
protocol RootModuleMediatorsIOInterface { func someFunction() }
extension RootModuleMediator : RootModuleMediatorsIOInterface { func someFunction() { print("RootModuleMediator someFunction() printed")}}
protocol RootModuleMediatorsViewInterface { func aFunction() }
extension RootModuleMediator : RootModuleMediatorsViewInterface { func aFunction() { print("RootModuleMediator aFunction() printed")}}
// Peer base
class Peer<MediatorTypeParam> {
private var mediator : MediatorTypeParam?
func registerMediator(mediator: MediatorTypeParam) { self.mediator = mediator }
}
// View Peer
class RootModuleView<MediatorTypeParam> : Peer<MediatorTypeParam> {}
protocol RootModuleViewsMediatorInterface { func someFunction() }
extension RootModuleView : RootModuleViewsMediatorInterface { func someFunction() { print("RootModuleView someFunction() printed") }}
// IO Peer
class RootModuleIO<MediatorTypeParam> : Peer<MediatorTypeParam> {}
protocol RootModuleIOsMediatorInterface { func someFunction() }
extension RootModuleIO : RootModuleIOsMediatorInterface { func someFunction() { print("RootModuleIO someFunction() printed") }}
// Instances
let rootModuleIO = RootModuleIO<RootModuleMediatorsIOInterface>()
let rootModuleView = RootModuleView<RootModuleMediatorsViewInterface>()
let rootModuleMediator = RootModuleMediator<RootModuleIOsMediatorInterface, RootModuleViewsMediatorInterface>()
// Interface registration
rootModuleIO.registerMediator(rootModuleMediator)
rootModuleView.registerMediator(rootModuleMediator)
rootModuleMediator.registerIOPeer(rootModuleIO)
rootModuleMediator.registerViewPeer(rootModuleView)
// Communication constrained to defined interfaces
rootModuleMediator.IO!.someFunction()
rootModuleMediator.view!.someFunction()
rootModuleIO.mediator!.someFunction()
rootModuleView.mediator!.aFunction()
Upvotes: 1
Reputation: 3863
It is possible to have generic types that conform to multiple protocols. It is done like this:
class Mediator<T where T: RootModuleMediatorsIOInterface, T: RootModuleIOsMediatorInterface> {
private var peers = Array<T>()
func registerPeer(peer: T) {
self.peers.append(peer)
}
func exercisePeers() {
for peer in peers {
peer.someFunction()
peer.someOtherFunction()
}
}
}
class RootModuleMediator : RootModuleMediatorsIOInterface, RootModuleIOsMediatorInterface {}
// ############ EXAMPLE PROTOCOL CONSTRAINED EXTENSIONS IMPLEMENTATION ############
protocol RootModuleMediatorsIOInterface { func someFunction() }
extension RootModuleMediatorsIOInterface { func someFunction() { print("Something")}}
protocol RootModuleIOsMediatorInterface { func someOtherFunction() }
extension RootModuleIOsMediatorInterface { func someOtherFunction() { print("Something else") }}
let root = RootModuleMediator()
let mediator = Mediator<RootModuleMediator>()
mediator.registerPeer(root)
mediator.exercisePeers()
I added an exercise function so you can see that you can call the functions implemented by the protocol extensions. I also simplified your protocol and extension definitions. The output is as you would expect:
Something
Something else
Upvotes: 1
Reputation: 10136
I do not see the rest of implementation to verify it will all work as expected, but did you mean something like this:
class Mediator<T, U> {
private var peers = [(T, U)]()
func registerPeer(peer: (T, U)) {
self.peers.append(peer)
}
func registerPeer(left: T, _ right: U) {
registerPeer((left, right))
}
}
The missing step was to use tuples
as the array elements.
Upvotes: 2