CymChad / CymChad/BaseRecyclerViewAdapterHelper

关于 BaseNode 与 BaseExpandNode 的设计

Open
#3,546 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Kotlin
Stars
24.6k
Forks
5.2k
PR merge metrics
No merged PRs in 30d

Description

abstract class BaseNode {
    abstract val childNode: MutableList<BaseNode>?
}

abstract class BaseExpandNode : BaseNode() {
    var isExpanded: Boolean = true
}

提一个小小建议,个人觉得这两个节点类没必要设计成抽象类,改为接口更好一些。特别是当场景需要实现其他一些接口以提供能力后,由于 BaseNodeAdapter 只接受 BaseNode ,因此在业务代码中充斥着强转,感觉不是太好。

假设我有一个 Model 接口,我希望每个节点都实现它,如果按照目前框架的设计,是这样的:

interface Model {
    val id: String?
    val name: String?
}

class Student : BaseNode(), Model {
    override val childNode: MutableList<BaseNode>? = null

    override val id: String? = null
    override val name: String? = null
}

class Clazz : BaseExpandNode(), Model {
    override val childNode: MutableList<BaseNode>? = null

    override val id: String? = null
    override val name: String? = null
}

fun test() {
    val baseNodeAdapter = baseNodeAdapter
    val models = mutableListOf<Model>()

    // Compile error, type mismatch.
    baseNodeAdapter.setList(models)
    
    val node = baseNodeAdapter.getItem(0)
    
    // Compile error, unresolved reference: name.
    val name = node.name

    // It work, but complex.
    val castName = (node as Model).name
}

可以看到在转型上面比较繁琐,但如果设计成接口,我认为是比较合理的,解决单继承的痛点,如下:

interface BaseNode {
    val childNode: MutableList<BaseNode>?
}

interface BaseExpandNode : BaseNode {
    var isExpanded: Boolean
}

interface Model : BaseNode {
    val id: String?

    val name: String?

    val children: MutableList<Model>?

    override val childNode: MutableList<BaseNode>?
        get() = children as? MutableList<BaseNode>?
}

class Student : Model {
    override val id: String? = null
    
    override val name: String? = null
    
    override val children: MutableList<Model>? = null
}

class Clazz : Model, BaseExpandNode {
    override var isExpanded: Boolean = true
    
    override val id: String? = null
    
    override val name: String? = null
    
    override val children: MutableList<Model>? = null
}

如果改成接口,那么 NaseNodeAdapter 也需要改为支持指定泛型,否则在 getItem() 等这些泛型方法的处境仍然没变。

abstract class BaseNodeAdapter<T : BaseNode>(nodeList: MutableList<T>? = null) : BaseProviderMultiAdapter<T>(null) {
    override fun setList(list: Collection<T>?) {
        super.setList(flatData(list ?: arrayListOf()))
    }
}

以上是我的一些想法,如有错误或不足请指出,感谢作者提供这么便捷的框架。RESPECT 👍

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reviewing BaseNode, BaseExpandNode, and BaseNodeAdapter, including its BaseProviderMultiAdapter inheritance. Evaluate the proposed interface and generic changes against the adapter APIs shown in the issue. Done would require a maintainer-approved design and corresponding implementation, with compatibility and usage effects resolved.

Written by the indexing model from the issue text.

Assessment

Tech stack
kotlin
Domain
mobile-dev
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.