月黑风高,好兄弟发给我一个重构需求,咨询我的意见。
开发的产品是需要运行到不同的定制Android板子,不同板子有对应的不同SDK提供的API,目前的业务端,业务流程基本是确定的,比如有业务流程为打开板子的某项开关(需求就是打开开关),对应在板子中可能存在A、B、C三个板子或者更多,其中板子都提供了打开开关S的方法,但是方法名称各不相同,目前在代码中的使用方式都是,创建一个服务于业务的工具类,在工具类中判断板子类型创建不同的SDK,并使用不同SDK的API完成这个需求。
对于商业SDK的开发及多SDK使用,我有丰富的设计经验,面对这个问题,立马能说出这个描述中存在的问题有多少,所以意见是重构!必须重构。
我从来都是以理服人,必须要着说明为什么重构,怎么重构,结果是什么.
分析上述问题,其中的重点有以下几处:
通过这三点可以看出,这个需求其实很简单,很清晰,但是对于上述的描述的实现方式,肯定是不行的。
为了好解决问题,我们要引入几个实体板子名称(在开发中,领域模型非常重要,事关需求的成功与否、事关团队的配合度高低), 假设目前面对的板子有例如树莓派(Raspberry Pi)、小米开发板、华为开发板。然后还原一下代码
假设工具类名称为ControlBroadUtil, 还原代码如下
这大概就是描述还原的代码,这问题就很清晰了。
面对这类型的问题,其实老手第一眼就想到重构的方式了,我的建议是在给出重构意见时必须考虑后续的问题。
其中:
ControlBoardFactory (抽象工厂):它声明了一组用于创建一族产品的方法,每个方法对应一种产品,在这里就是每一种板子的SDK。
/**
*
* @author: kpa
* @date: 2024/2/7
* @description: 它声明了一组用于创建一族产品的方法,每个方法对应一种产品,在这里就是每一种板子的SDK。
*/
abstract class ControlBoardFactory<out T : ControlBoardService> {
abstract fun createControlBoard(): T
}
HuaweiFactory等(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每种产品都位于某个产品等级结构中。
/**
*
* @author: kpa
* @date: 2024/2/7
* @description:huawei 板子的创建工厂
*/
class HuaweiControlBoardFactory : ControlBoardFactory<HuaweiBoardServiceImpl>() {
override fun createControlBoard(): HuaweiBoardServiceImpl {
return HuaweiBoardServiceImpl()
}
}
ControlBoardService(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。
/**
*
* @author: kpa
* @date: 2024/2/7
* @description: 抽象产品,对应业务,为需求接口
*/
interface ControlBoardService {
fun switch(switchValue: Int)
}
HuaweiControlBordImpl等(具体产品):它定义具体工厂生产的具体产品对象,实现在抽象产品接口中声明的业务方法。
/**
*
* @author: kpa
* @date: 2024/2/7
* @description:
*/
class HuaweiBoardServiceImpl : ControlBoardService {
override fun switch(switchValue: Int) {
TODO("Not yet implemented")
}
}
对于类中提的提供方接口将使用适配器模式完成与已知SDK API适配,此处设计的目的是:
所以决定对抽象产品(ControlBoardService)部分使用适配器模式进行设计,要求是:
组合方式:
class HuaweiBoardServiceImpl : ControlBoardService {
private val huaweiBoardSDK: HuaweiBoardSDK by lazy { HuaweiBoardSDK() }
override fun switch(switchValue: Int) {
huaweiBoardSDK.huaweiOpenSwitch(switchValue)
}
}
如果使用上述的代码,在一套体系中还是会出现调用混乱的问题,呐,处理方式就是使用外观模式,右边部分为外观模式下的物理、逻辑结构。
外观模式相对简单。
类图就不画了代码如下:
/**
*
* @author: kpa
* @date: 2024/2/7
* @description: 外观模式下的工具类
*/
object ControlBroadUtil {
private val huaweiBoardFactory: HuaweiControlBoardFactory by lazy { HuaweiControlBoardFactory() }
// 其他工厂
//...
// 需求接口,面相该接口编程
private var controlBoardService: ControlBoardService? = null
/**
* 供应商环境
*/
private var supplierEnvironment = ""
private fun init() {
// 统一配置读取
supplierEnvironment = System.getProperty("")
controlBoardService = huaweiBoardFactory.createControlBoard()
}
/**
* 直接使用接口编程
*/
public fun getControlBoardService(): ControlBoardService {
return controlBoardService ?: HuaweiControlBoardFactory().createControlBoard()
}
}
经过以上的分析和重构思路,可以得出以下重构结果分析:
通过对现有代码的分析和重构,我们解决了原有代码存在的问题,提高了系统的可维护性、可扩展性和可读性。使用抽象工厂模式和适配器模式,使得系统更加灵活,业务概念更加统一,业务代码与底层SDK的实现解耦。这样的设计不仅适应了当前的业务需求,还为未来的扩展和变化提供了良好的支持。
在实际开发中,重构是一个不断演进的过程,需要根据实际情况灵活运用设计模式和原则,不断优化和改进代码结构。同时,良好的文档和规范也是团队协作的重要保障,能够使团队成员更加容易理解和使用不同板子的SDK。