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
相关产品推荐
相关产品推荐

