Composition rather than inheritance for shared variables - ios

I was previously using a class that could be simplfied down to this:
class Whatever {
var someArray = [Int]()
func unchangingFunction {
print("test")
}
func functionForOverride() {}
}
I was asking of ways to improve this, and I got told to favour composition over inheritance, using something like the following:
protocol Implementation {
func functionForOverride()
}
final class Whatever {
var someArray = [Int]() // How can I access this?
let implementation: Implementation
init(implementation: Implementation) {
self.implementation = implementation
}
func unchangingFunction() {
print("test")
}
func functionForOverride() {
implementation.functionForOverride()
}
}
However, with this, I can't find a way to do anything with the someArray array:
struct Something: Implementation {
func functionForOverride() {
print(someArray) // This cannot work
}
}
With the original code I am able to access and alter someArray however I want, but with this new way, I can't think of an easy solution.

I think we should use a "real" example in order to make things clearer.
Inheritance (and why it's wrong)
We have the following classes
class Robot {
var battery = 0
func charge() {
print("⚡️")
battery += 1
}
}
class Human {
func eat() {
print("🍽")
}
}
class RobotCleaner: Robot {
func clean() {
print("💧")
}
}
class HumanCleaner: Human {
func clean() {
print("💧")
}
}
Code duplication!!!
As you can see the clean() method is duplicated in RobotCleaner and HumanCleaner. Can you find a way (using inheritance) to remove code duplication?
Ok think about that, I'll wait on the next paragraph... :)
...
Oh, here you are! There's no way to fix that with inheritance right? Well, let's see what we can do with composition.
Composition (the classic way)
Let's define the following 3 protocols and related components
protocol Robot {
mutating func charge()
}
struct RobotComponent: Robot {
var battery = 0
mutating func charge() {
print("⚡️")
battery += 1
}
}
protocol Human {
func eat()
}
struct HumanComponent: Human {
func eat() {
print("🍽")
}
}
protocol Cleaner {
func clean()
}
struct CleanerComponent: Cleaner {
func clean() {
print("💧")
}
}
Now we can build any combination of the previous 3 elements
struct RobotCleaner: Robot, Cleaner {
var robotComponent = RobotComponent()
let cleanerComponent = CleanerComponent()
mutating func charge() {
robotComponent.charge()
}
func clean() {
cleanerComponent.clean()
}
}
struct HumanCleaner: Human, Cleaner {
let humanComponent = HumanComponent()
let cleanerComponent = CleanerComponent()
func eat() {
humanComponent.eat()
}
func clean() {
cleanerComponent.clean()
}
}
Protocol Oriented Programming: Composition the Swifty way
Swift offers a very neat way of doing composition.
First of all let's define the following 3 protocols (and related extensions).
protocol Robot {
var battery: Int { get set }
}
extension Robot {
mutating func charge() {
print("⚡️")
battery += 1
}
}
protocol Human { }
extension Human {
func eat() {
print("🍽")
}
}
protocol Cleaner { }
extension Cleaner {
func clean() {
print("💧")
}
}
Now we can create a Type which has any combination of the previous 3 entities. Let's see how.
struct HumanCleaner: Human, Cleaner { }
struct RobotCleaner: Robot, Cleaner {
var battery: Int = 0
}

If 'Implementation' requires 'someArray' to do what it is intended to do, then you should have 'Implementation' require any object conforming to it to also declare 'someArray'
Like this:
protocol Implementation {
var someArray: [Int]
}
And if you know what you want to do with 'someFunction', then you could give a default implementation of it with a protocol extension like so:
extension Implementation {
func someFunction() {
//you can do some stuff with someArray here
}
}
Then when you conform to 'Implementation' you need to declare 'someArray' but not 'someFunction', unless you want to override the default function.
E.g.
class MyClass: Implementation {
var someArray: [Int]!
init() {}
}
Note that MyClass now has access to 'someFunction', which can be freely overridden in your class, and that you can add as many functions as you want to 'Implementation's extension.

Related

Swift - How can I test with generic?

I wanna unittest with generics.
But I can't think of a way.
My code is as below, and I want to test the part prepare().
class A_ViewModel {
var useCase: UseCaseProtocol = UseCase()
var item: A_CellModel = .init()
// I want to unittest prepare()
func prepare() {
// logic....
// and call calcuate
useCase.calculate(item: item)
}
}
protocol TestableProtocol {
var testProperty: Bool { get set }
}
class A_CellModel: TestableProtocol {
var testProperty: Bool = false
}
protocol UseCaseProtocol {
func calculate<T: TestableProtocol>(item: T)
}
class UseCase: UseCaseProtocol {
func calculate<T: TestableProtocol>(item: T) {
// logic......
}
}
However, since calcaulte(item:) in usecase uses generic, it is necessary to hand over the clear type (A_CellModel).
In that case, there is a dependence between A_ViewModel and A_CellModel, which makes it difficult to test the unit.
In order to test prepare(), should calcaulte(item:) give up generic?
Should I use existential type?

Share implementations with protocols

I have two presenters: FirstPresenter and SecondPresenter. FirstPresenter conform to protocol PresenterProtocol. SecondPresenter needs to use all functions from FirstPresenter but with two additional.
protocol PresenterProtocol: class {
func one()
func two()
func third()
}
class FirstPresenter: PresenterProtocol {
func one() {
// do something
}
func two() {
// do something
}
func third() {
// do something
}
}
And then I have SecondPresenter and I need to use exactly the same implementation from FirstPresenter (but I want to avoid inheritance, I want do it with protocols)
class SecondPresenter: PresenterProtocols {
var firstPresenter: PresenterProtocol = FirstPresenter()
func one() {
firstPresenter.one()
// do something
}
func two() {
firstPresenter.two()
// do something
}
func third() {
firstPresenter.third()
// do something
}
func additionalFunction() {
// do something more
}
}
I am not sure if calling firstpresenter function is a good way to solve this problem, because it's just rewriting. I wonder also to use default implementation. What's the best way to share functionalities?
Your code doesn't actually rely on the methods you define, so they don't need to be requirements. They're extensions. As written, your code would be:
// This is where *requirements* go. Not shared code.
protocol PresenterProtocol: class {}
// This is your shared code
extension PresenterProtocol {
func one() {
// do something
}
func two() {
// do something
}
func third() {
// do something
}
}
// And FirstPresenter needs nothing else
class FirstPresenter: PresenterProtocol {}
// SecondPresenter gets those, and also has other things
class SecondPresenter: PresenterProtocols {
func additionalFunction() {
// do something more
}
}
Now, I'm betting that one() actually has some requirements. It needs its implementers to provide something. Those are what go in your PresenterProtocol. For example:
extension PresenterProtocol {
func one() {
doFirstThing() // Something the implementer must do
doSecondThing() // Something the implementer must do
}
}
In that case, you'd add those as requirements:
protocol PresenterProtocol {
func doFirstThing()
func doSecondThing()
}
And if there were a default way to do it that some implementers might override, then you'd provide a default implementation. Or you can just have all implementers provide it directly. Or you might not have any requirements at all.
Having a parent class is the better implementation as far as I see. But, if you don't want to, swift protocols have a nifty trick: the protocols can be extended.
Let me demonstrate using your code,
protocol PresenterProtocol: class {
func one()
func two()
func third()
}
// Adding the extenstion/default implementation
extension PresenterProtocol {
func one() {
print("one was pressed")
}
func two() {
print("two was pressed")
}
func third() {
print("third was pressed")
}
}
This way, any class conforming to PresenterProtocol will use the so-called "default implementation" (which is another way to say protocol extensions) unless you override the method in the class.
So your usage will look something like the following where you don't need to implement the 3 methods all over again.
class SecondPresenter: PresenterProtocol {
// Calling default implementations
func someFunction() {
one()
two()
third()
}
}
.
.
.
class FirstPresenter: PresenterProtocol {
func someFunction() {
one()
two()
third()
}
}
If you want more help learning, I would highly suggest reading the HackingWithSwift Tutorial

SOLID principles in mvp architecture

I use model view presenter architecture in my app and I wonder what's better for respect solid principles and reusability.
So I have 4 classes: View Controller, Presenter, Model and Service. But I have a doubt in connection between presenter and service. I am not sure if I don't break single responsibility principle.
Presenter:
class WorkoutPresenter() {
// some code
let workoutSettingsService = WorkoutSettingsService()
func changeUnitFromKGtoLBInHistory() {
workoutSettingsService.changeUnitFromKGtoLBInHistory()
}
func changeUnitFromLBtoKGInHistory() {
workoutSettingsService.firstFunction()
}
func changeUnitFromKGtoLBInCalendar() {
workoutSettingsService.secondFunction()
}
}
class WorkoutSettingService {
func firstFunction() {
// some code
}
func secondFunction() {
// some code
}
func thirdFunction() {
// some code
}
}
Now workout service has 3 responsibilities (first, second and third function)
Or maybe better option would be create different class for each function and then call them in WorkoutService, something like:
class WorkoutSettingService {
let firstFunctionClass: FirstFunctionClass
let secondFunctionClass: SecondFunctionClass
let thirdFunction: ThirdFunctionClass
init(firstFunctionClassClass: FirstFunction, secondFunctionClass: SecondFunctionClass, thirdFunctionClass: ThirdFunctionClass) {
self.firstFunctionClass = firstFunction
self.secondFunctionClass = secondFunction
self.thirdFunctionClass = thirdFunction
}
func firstFunctionCall() {
firstFunctionClass.function()
}
func secondFunctionCall() {
secondFunctionClass.function()
}
func thirdFunctionCall() {
thirdFunctionClass.function()
}
}
And then call it in Presenter like before. Or maybe better than accessing to this new three class is create a protocols and set delegates from service to this new specific classes?
I hope you understand what my problem is. If you have other idea how to connect presenter with service in clean way, go ahead.
The cleaner approach in my opinion would be to introduce protocols to your service class and segregate the responsibilities.
To make the example simpler, I am going to assume that func changeUnitFromKGtoLBInHistory() and func changeUnitFromLBtoKGInHistory() have to invoke a service with respect to some history data and the func changeUnitFromKGtoLBInCalendar() has to invoke current calendar data.
First we introduce 2 protocols to do that
protocol InHistoryServiceProtocol {
func firstFunction()
func secondFunction()
}
protocol InCalendatServiceProtocol {
func thirdFunction()
}
Then we update the class WorkoutSettingService to conform to protocol as below:
class WorkoutSettingService: InHistoryServiceProtocol, InCalendatServiceProtocol {
func firstFunction() {
// some code
}
func secondFunction() {
// some code
}
func thirdFunction() {
// some code
}
}
Now we use protocol composition to gracefully handle the service class in the presenter
class WorkoutPresenter {
// some code
typealias WorkoutServiceProtocols = InHistoryServiceProtocol & InCalendatServiceProtocol
let workoutSettingsService: WorkoutServiceProtocols = WorkoutSettingService()
func changeUnitFromKGtoLBInHistory() {
workoutSettingsService.firstFunction()
}
func changeUnitFromLBtoKGInHistory() {
workoutSettingsService.secondFunction()
}
func changeUnitFromKGtoLBInCalendar() {
workoutSettingsService.thirdFunction()
}
}
This way you have the flexibility to add/remove responsibilities in the Work out service class respecting the SOLID principles. It also becomes easy to mock the data and inject into presenter for testing.

Redefine protocol functions using constraints without having to expose method

Ugly 1
protocol Persisting {
func persist()
}
extension Persisting {
func persist() { print("persisting") }
}
protocol Service {
func get()
func persistIfAble() // If I remove this, "Not able to persist" gets printed twice
}
extension Service {
func get() {
persistIfAble()
}
}
extension Service {
func persistIfAble() {
print("Not able to persist")
}
}
extension Service where Self: Persisting {
func persistIfAble() {
persist()
}
}
struct OnlyService: Service {}
struct Both: Service, Persisting {}
let both = Both()
both.get()
let onlyService = OnlyService()
onlyService.get()
print("Can now directly call `persistIfAble` which is not wanted")
onlyService.persistIfAble() // DONT WANT THIS TO BE POSSIBLE
This solution would be elegant if I could remove func persistIfAble() from protocol declaration. Because I do not want it to be exposed. However, what is really interesting is that if I remove it, then the behavior changes, then the implementation inside extension Service where Self: Persisting never gets called.
Ugly 2
protocol Persisting {
func persist()
}
extension Persisting {
func persist() { print("persisting") }
}
protocol Service {
func get()
}
extension Service {
func get() {
// Ugly solution, I do not want to cast, `Service` should not have to know about `Persisting`
if let persisting = self as? Persisting {
persisting.persist()
} else {
print("not able to persist")
}
}
}
extension Service where Self: Persisting {
func persistIfAble() {
persist()
}
}
struct OnlyService: Service {}
struct Both: Service, Persisting {}
let both = Both()
both.get()
let onlyService = OnlyService()
onlyService.get()
The code in both ugly solutions is of course an extremely simplified version of my actual scenario, where I really do not want to perform casts, because it makes the code so much more difficult to read. Even if I would change if let to guard let.
Ugly 3 (ugliest?)
protocol Persisting {
func persist()
}
extension Persisting {
func persist() { print("persisting") }
}
protocol Service {
func get()
func persistIfAble(allowed: Bool)
}
extension Service {
func get() {
persistIfAble(allowed: true)
}
}
extension Service {
func persistIfAble(allowed: Bool = false) {
guard allowed else { print("KILL APP"); return }
print("Not able to persist")
}
}
extension Service where Self: Persisting {
func persistIfAble(allowed: Bool = false) {
guard allowed else { print("BREAKING RULES"); return }
persist()
}
}
struct OnlyService: Service {}
struct Both: Service, Persisting {}
let both = Both()
both.get()
let onlyService = OnlyService()
onlyService.get()
print("Can now directly call `persistIfAble` which is not wanted")
// DONT WANT THIS TO BE POSSIBLE
onlyService.persistIfAble() // prints: "KILL APP"
What am I missing?
Where is the beautiful solution?
I wonder if maybe what you really want is to use composition of actual objects, not just interfaces (and some default implementations). Consider this: Both Persisting and Service as you've defined them really need to be implemented in concrete classes or structs, so that they can contain context about where they are accessing their data. So I'd imagine that you could skip the protocol extensions, leave the real "guts" up to concrete implementations of those protocols, and then something like your Both would be implemented like this:
struct Both: Persisting, Service {
let persisting: Persisting
let service: Service
// a default init lets you pass in concrete implementations of both of those things
func persist() {
persisting.persist()
}
func get() {
service.get()
persist()
}
This obviously doesn't give you the automatic sort of "mix-in" effect that it looks like you're trying to achieve, but OTOH it's pretty clear to understand.
How about removing one level of indirection (i.e. 'persistIfAble')?
protocol Persisting {
func persist()
}
extension Persisting {
func persist() {
print("persisting")
}
}
protocol Service {
func get()
}
extension Service where Self: Persisting {
func get() {
persist()
}
}
extension Service {
func get() {
print("Not able to persist")
}
}

Optional functions for override in Swift classes?

I'm trying to make a simple game using Swift. The game has different levels, and each level requires the game to behave in slightly different ways. I decided to use a different class for each level, all inherited from a base level class.
This is the base:
import SpriteKit
class LevelBase {
var scene: GameScene! // Seems very dodgy
var blocks = [SKSpriteNode]()
init(scene: GameScene) { // Should this be required init?
self.scene = scene
}
func filterBlock(_ block: SKSpriteNode) {
blocks = blocks.filter() { $0 !== block } // Looks really dodgy to me
}
func update(time: TimeInterval) {
// For override
}
func levelUp() {
// For override
}
func postGenerate() {
// For override
}
}
However, to me, this class seems to be very badly written. I can't find any examples anywhere of functions created in a class just to be overwritten, which makes me think I'm doing something wrong. Should I be using extensions or protocols for optional functions like that? I don't quite understand how they work, so I haven't used any so far.
The second issue is that this class needs to be initialized with the game scene variable, since some levels need it to add or remove sprites. This seems especially dodgy, considering the class is created in the game scene's file.
Surely there's a better way?
I have no experience with SpriteKit, but from a general perspective you should consider to "Favour composition over Inheritance".
You would have one Level class that is not intended for subclassing but can be instantiated with objects or values that have different implementation.
Additionally you should use protocols to define those and you can add default implementation as protocol extensions.
final class Level {
init(levelImplementation: LevelImplementationType) {
self.levelImplementation = levelImplementation
}
let levelImplementation: LevelImplementationType
func navigate() {
levelImplementation.navigate()
}
func update(timeInterval: TimeInterval) {
levelImplementation.update(timeInterval: timeInterval)
}
}
The Level would be instantiated with an object or struct conforming to LevelImplementationType
protocol LevelImplementationType {
func navigate()
func update(timeInterval: TimeInterval)
}
Default implementations can be done via an extension.
extension LevelImplementationType {
func navigate() {
}
func update(timeInterval: TimeInterval) {
}
}
The LevelImpelmenation needs to conform to LevelImplementationType, but don't have any further constraints. i.e. they can have very different initialisers.
struct LevelImplementation1: LevelImplementationType {
// useses default implementation of `navigate` and `update` from extension
}
struct LevelImplementation2: LevelImplementationType {
// useses default implementation of `update` from extension
func navigate() {
}
}
struct LevelFileImplementation: LevelImplementationType {
init(with path: String) {
// read variables from file at path
}
func navigate() {
// navigate as given in file
}
}
Level instances cane be created like
let level1 = Level(levelImplementation: LevelImplementation1())
let level2 = Level(levelImplementation: LevelImplementation2())
let level3 = Level(levelImplementation: LevelFileImplementation(with: "path/to/file"))

Resources