You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin跨模块接口设计:视图层实现、后端层调用的解耦方案

Kotlin 实现跨模块接口解耦方案

你的需求完全适合用接口来实现,接口作为行为契约,能完美实现Backend层与View层的关注点分离,让Backend只依赖抽象契约,不关心具体实现。下面是具体步骤和代码示例:

1. 定义标准化接口

先把接口优化得更符合Kotlin最佳实践:用List代替具体的ArrayList,让接口更灵活;参数注释保持清晰:

interface AreaProcessing {
    /**
     * 判断点是否在指定区域内
     * @param point 坐标点,格式为 <经度, 纬度>
     * @param areaPointsList 区域顶点列表,每个元素为 <经度, 纬度>
     * @return 点在区域内返回true,否则返回false
     */
    fun isPointInsideTheArea(
        point: Pair<Double, Double>,
        areaPointsList: List<Pair<Double, Double>>
    ): Boolean
}

这个接口应该放在公共模块(比如core或者contract模块),让Backend层和View层都能依赖它,避免循环依赖。

2. View层实现接口

不同的地图模块各自实现这个接口,利用自身地图引擎的API完成判断逻辑:

GoogleMap模块实现

// GoogleMapModule中的实现类
class GoogleMapAreaProcessor : AreaProcessing {
    override fun isPointInsideTheArea(
        point: Pair<Double, Double>,
        areaPointsList: List<Pair<Double, Double>>
    ): Boolean {
        // 调用Google Maps SDK的点-in-区域判断API
        val googlePoint = LatLng(point.second, point.first)
        val polygonOptions = PolygonOptions().apply {
            areaPointsList.forEach { add(LatLng(it.second, it.first)) }
        }
        return PolyUtil.containsLocation(googlePoint, polygonOptions.points, true)
    }
}

BingMap模块实现

// BingMapModule中的实现类
class BingMapAreaProcessor : AreaProcessing {
    override fun isPointInsideTheArea(
        point: Pair<Double, Double>,
        areaPointsList: List<Pair<Double, Double>>
    ): Boolean {
        // 调用Bing Maps SDK的点-in-区域判断API
        val bingPoint = Location(point.second, point.first)
        val polygon = Polygon()
        polygon.Locations = areaPointsList.map { Location(it.second, it.first) }
        return polygon.Contains(bingPoint)
    }
}

3. Backend层依赖接口调用

Backend层只需要依赖AreaProcessing接口,不需要知道具体是Google还是Bing的实现。通过依赖注入(比如Dagger/Hilt、Koin)或者工厂模式获取接口实例:

// Backend层的业务类,仅依赖接口
class AreaCheckService(private val areaProcessor: AreaProcessing) {
    fun verifyPointInArea(point: Pair<Double, Double>, area: List<Pair<Double, Double>>): Boolean {
        // 直接调用接口方法,无需关心具体实现
        return areaProcessor.isPointInsideTheArea(point, area)
    }
}

切换地图实现时,只需要替换注入的AreaProcessing实例,Backend层的代码完全不需要修改。

4. 处理无实现的情况

如果没有提供接口实现,可以通过两种方式处理:

  • 在接口中定义默认实现,抛出异常:
interface AreaProcessing {
    fun isPointInsideTheArea(point: Pair<Double, Double>, areaPointsList: List<Pair<Double, Double>>): Boolean

    // 默认实现,无具体实现时调用会抛出异常
    fun default(): Boolean = throw UnsupportedOperationException("未提供AreaProcessing的实现")
}
  • 在Backend获取实例时做校验,比如依赖注入时如果没有绑定实例,直接抛出初始化异常。

为什么选接口而不是抽象类?

  • 契约优先:接口是纯粹的行为契约,只定义要做什么,不关心怎么做,完全符合你关注点分离的需求。
  • 多实现支持:一个类可以实现多个接口,但只能继承一个抽象类,后续如果需要扩展其他契约,接口更灵活。
  • 无默认状态:抽象类可以包含属性和默认实现,而你的场景中不同地图引擎的实现逻辑完全独立,不需要共享代码,用接口更简洁。

内容的提问来源于stack exchange,提问作者user14576370

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 14:45:56