架构设计深度解析:策略模式 + 抽象工厂在UI适配中的高级应用

张开发
2026/4/8 16:53:12 15 分钟阅读

分享文章

架构设计深度解析:策略模式 + 抽象工厂在UI适配中的高级应用
架构设计深度解析策略模式 抽象工厂在UI适配中的高级应用代码// 在 BasePageConfig中 定义了很多抽象方法abstractclassBasePageConfig{companionobject{constvalCOLUM_COUNT_ONE1constvalCOLUM_COUNT_TWO2constvalCOLUM_COUNT_THREE3constvalCOLUM_COUNT_FOUR4constvalCOLUM_COUNT_FIVE5constvalCOLUM_COUNT_SIX6constvalCOLUM_COUNT_EIGHT8constvalCOLUM_COUNT_TEN10constvalCOLUM_COUNT_TWENTY20funget()if(ViewDelegate.isLandW2560()){LandPageConfig}else{PortPageConfig}}abstractfunrecommendGetGridLayoutManager(context:Context,recyclerView:RecyclerView,bannerWidgetStyle:Int?):GridLayoutManagerabstractfunrecommendSongFolderListMax():IntabstractfunrecommendSongInfoListMax():IntabstractfunmusicHouseGetGridLayoutManager(context:Context,recyclerView:RecyclerView):GridLayoutManager}// 在具体的实现类 LandPageConfigPortPageConfig中来实现会对每个页面设置具体是多少span/列,写的完整严谨很美妙LandPageConfig.kt:objectLandPageConfig:BasePageConfig(){overridefuncreateDecorationConfig():IDecorationConfig{returnLandDecorationConfig}overridefunrecommendGetGridLayoutManager(context:Context,recyclerView:RecyclerView,bannerWidgetStyle:Int?):GridLayoutManager{returnGridLayoutManager(context,COLUM_COUNT_TEN).apply{spanSizeLookupobject:GridLayoutManager.SpanSizeLookup(){overridefungetSpanSize(position:Int):Int{valadapterrecyclerView.adapteras?RecommendAdapterreturnwhen(adapter?.getItemViewType(position)){RecommendData.TYPE_SONG_FOLDER_SUPPLIER_STATION-COLUM_COUNT_TWO RecommendData.TYPE_SONG_ITEM-COLUM_COUNT_FIVE RecommendData.TYPE_BANNER-{if(bannerWidgetStyle1){COLUM_COUNT_TEN}else{COLUM_COUNT_FIVE}}else-{COLUM_COUNT_TEN}}}}}}overridefunrecommendSongFolderListMax()COLUM_COUNT_TENoverridefunrecommendSongInfoListMax()COLUM_COUNT_EIGHToverridefunmusicHouseGetGridLayoutManager(context:Context,recyclerView:RecyclerView):GridLayoutManager{returnGridLayoutManager(context,COLUM_COUNT_TEN).apply{spanSizeLookupobject:GridLayoutManager.SpanSizeLookup(){overridefungetSpanSize(position:Int):Int{valadapterrecyclerView.adapteras?MusicHouseAdapterreturnwhen(adapter?.data?.get(position)?.itemType){MusicHouseItem.TYPE_TITLE_MORE-COLUM_COUNT_TEN MusicHouseItem.TYPE_NEWEST_SONG_ITEM-COLUM_COUNT_FIVEelse-COLUM_COUNT_TWO}}}}}总结 base中把每个页面对应一个函数名称在实现类 LandPageConfigPortPageConfig中写需要多少span,也就是占多少列它属于典型的**“策略模式 抽象工厂”**在 UI 适配中的高级应用。我也觉得这段代码写得很好好在以下三点1. 将“业务逻辑”与“布局参数”彻底解耦在一般的代码里我们经常会在 Fragment 里面写大量的if (isLandscape) 5 else 2。而这段代码把**“一共有几列”、“某个 Item 占几格”**这些琐碎的数值全部抽离到了LandPageConfig和PortPageConfig中。好处 你的 Activity 或 Fragment 变得极其干净它只需要调用Config.get().recommendGetGridLayoutManager()完全不需要关心当前是横屏还是竖屏。2. 利用 SpanSizeLookup 实现极高的灵活性看LandPageConfig里的这段逻辑overridefungetSpanSize(position:Int):Int{returnwhen(adapter?.getItemViewType(position)){TYPE_SONG_ITEM-COLUM_COUNT_FIVE// 歌曲占 5 格一行俩else-COLUM_COUNT_TEN// 其他占满 10 格一行一个}}这里的“美感”在于它把 RecyclerView 的复杂布局转换成了简单的数学题。通过COLUM_COUNT_TEN总共10列作为分母不同的 Item 可以自由分配想一行显示 2 个那就占 5 格。想一行显示 5 个那就占 2 格。想占满全屏那就占 10 格。这种以最小公倍数作为总列数的思想让 UI 调整变得像拼图一样简单。3. 强迫症级别的“严谨性”单例化ObjectLandPageConfig用了object关键字这意味着这些配置在内存中只有一份不会重复创建对象非常省内存。类型安全在 Base 类里定义abstract fun强制子类必须实现。这样如果你以后要加一个“折叠屏配置”编译器会立刻提醒你“嘿你还没给折叠屏设置歌曲列表的最大值呢”——这避免了低级错误。核心感悟配置化思想你发现的这种“美”其实是**“配置化”**的思想。Base 层定义了规则有哪些页面需要配置。实现层填入数值具体这个环境下的列数是多少。调用层只负责执行。这种结构不仅写起来爽后期维护更爽如果老板说“横屏下推荐位想从 2 列改成 3 列”只需要去LandPageConfig改一个数字其他几千行代码动都不用动。

更多文章