3 votes

Comment sécuriser les mêmes hiérarchies d'héritage par exemple pour MVVM

J'ai une base ViewController et un base ViewModel. Le ViewModel de base est utilisé par le ViewController de base. De plus, j'ai 2 sous-classes de ViewControllers et 2 sous-classes de ViewModels qui doivent être utilisées ensemble.

Exemple:

class BaseViewModel {
    func somethingBasic() {}
}

class ConcreteViewModel1: BaseViewModel {
    func somethingConcrete1() {}
}

class ConcreteViewModel2: BaseViewModel {
    func somethingConcrete2() {}
}

class BaseViewController {
    let viewModel: BaseViewModel

    init(with viewModel: BaseViewModel) {
        self.viewModel = viewModel
    }
}

class ConcreteViewController1: BaseViewController {
    init(with viewModel: ConcreteViewModel1) {
        super.init(with: viewModel)
    }

    func useViewModel() {
        viewModel.somethingBasic()
        viewModel.somethingConcrete1() //this does not work
    }
}

class ConcreteViewController2: BaseViewController {
    init(with viewModel: ConcreteViewModel2) {
        super.init(with: viewModel)
    }

    func useViewModel() {
        viewModel.somethingBasic()
        viewModel.somethingConcrete2() //this does not work
    }
}

La question est : quelle est la solution préférée pour faire fonctionner viewmodel.somethingConcrete1() et viewmodel.somethingConcrete2()?

8voto

PGDev Points 6277

Essayez d'utiliser Génériques pour cela.

Créez init dans BaseViewController acceptant un paramètre générique T contraint au type BaseViewModel, c'est-à-dire

class BaseViewController {
    let viewModel: T

    init(with viewModel: T) {
        self.viewModel = viewModel
    }
}

Maintenant, héritez de ConcreteViewController1 et ConcreteViewController2 de BaseViewController en donnant le type spécifique pour le paramètre générique T, c'est-à-dire

class ConcreteViewController1: BaseViewController {
    func useViewModel() {
        viewModel.somethingBasic()
        viewModel.somethingConcrete1()
    }
}

class ConcreteViewController2: BaseViewController {
    func useViewModel() {
        viewModel.somethingBasic()
        viewModel.somethingConcrete2()
    }
}

2voto

stk Points 752

J'ai discuté de cela avec quelques autres collègues, et nous sommes arrivés à cette solution, basée sur Composition au lieu de l'héritage :

class BaseViewModel {
    func somethingBasic() {}
}

class ConcreteViewModel1 {
    private let baseViewModel = BaseViewModel()
    func somethingConcrete1() {}

    func somethingBasic() {
        baseViewModel.somethingBasic()
    }
}

class ConcreteViewModel2 {
    private let baseViewModel = BaseViewModel()
    func somethingConcrete2() {}

    func somethingBasic() {
        baseViewModel.somethingBasic()
    }
}

class BaseViewController {}

class ConcreteViewController1 {
    private let base = BaseViewController()
    private let viewModel: ConcreteViewModel1

    init(with viewModel: ConcreteViewModel1) {
        self.viewModel = viewModel
    }

    func useViewModel() {
        viewModel.somethingBasic()
        viewModel.somethingConcrete1()
    }
}

class ConcreteViewController2: BaseViewController {
    private let base = BaseViewController()
    private let viewModel: ConcreteViewModel2

    init(with viewModel: ConcreteViewModel2) {
        self.viewModel = viewModel
    }

    func useViewModel() {
        viewModel.somethingBasic()
        viewModel.somethingConcrete2()
    }
}

Avec cette solution, vous obtenez la sécurité des types, vous évitez les génériques et vous n'avez pas besoin de caster partout.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X