【问题标题】:How to secure same inheritance hierarchies e.g. for MVVM如何确保相同的继承层次结构,例如用于 MVVM
【发布时间】:2019-12-10 19:39:06
【问题描述】:

我有一个基本的 ViewController 和一个基本的 ViewModel。基本 ViewModel 由基本 ViewController 使用。另外,我有 2 个 ViewControllers 子类和 2 个 ViewModels 子类需要一起使用。

例子:

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
    }
}

问题是:使viewmodel.somethingConcrete1()viewmodel.somethingConcrete2() 工作的首选解决方案是什么?

【问题讨论】:

  • 你应该使用协议或在基类中实现somethingConcrete2

标签: ios swift inheritance hierarchy


【解决方案1】:

为此尝试使用 Generics

BaseViewController 中创建init,接受一个通用参数 T 被限制为BaseViewModel 类型,即

class BaseViewController<T: BaseViewModel> {
    let viewModel: T

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

现在从BaseViewController 继承ConcreteViewController1ConcreteViewController2,为通用参数 T 提供特定类型,即

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

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

【讨论】:

  • 不错,但它在架构方面好吗?我的意思是 MVVM
  • 我就是这样做的,一开始看起来不错。但是在项目开始发展之后,它变得非常混乱。这是使用它时的类签名:pasteboard.co/IqOwJ0m.png
  • @stk 图片未找到
  • @Erumaru 纯文本:open class BaseDetailViewController&lt;ItemType, ItemViewModelType, ViewModelType: BaseDetailViewModel&lt;ItemType, ItemViewModelType&gt;, CellType: BaseDetailCell&lt;ItemType, ItemViewModelType&gt;, HeaderViewType: BaseDetailHeaderView, FooterBarType: DetailFooterBarView&gt;: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, SharingAlertProvider, Deselecting, DismissImageDetail {
  • 好吧,就像我提到的:你的解决方案很好,但我想找到一个替代方案。我找到了一些东西,我会在这里发布
【解决方案2】:

我与其他几位同事讨论过这个问题,我们基于 Composition 而不是继承提出了这个解决方案:

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()
    }
}

使用该解决方案,您可以获得类型安全,避免泛型,并且不需要在任何地方进行强制转换。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-12-22
    • 1970-01-01
    • 1970-01-01
    • 2020-10-24
    • 1970-01-01
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    相关资源
    最近更新 更多