Swift插件化设计方案-解耦业务

949 阅读3分钟

背景

我们在做具体业务,特别是复杂页面的时候。经常会遇到各种业务掺杂在一个ViewController的case。比如抖音播放页, 编辑页。此时的ViewController会可能会负责派发业务,缓存状态,导致很多业务都在一个地方交集,理解,维护性很差。

痛点

核心模块耦合过多逻辑。增加各种单一功能变量,代理回调。加重主控制模块压力,而且功能越增加越臃肿。常见于ViewController(我只想安安静静的做点DidLoad, Appear操作)。

常见解决方案

  1. 分化功能到子view。(缺点:VC需要处理delegate等业务,view交互)
  2. extensions (缺点:不能添加变量)
  3. 其他

我们希望可以这样

主控制模块只是负责派发业务,维护状态, 那VC就可以很简洁, 如图:

那就需要支持:

  1. 模块独立解耦
  2. 支持同步异步
  3. 自定义输入输出,自定义变量
  4. lazy, easy load.
  5. 异步回调,参数可定制
  6. 链式调用 继续...

设计

基于Swift语言特性,这里提出一种很简洁的设计方案。

features

  1. 分化业务
  2. 自定义输入输出
  3. 提供回调,自定义返回参
  4. 支持链式调用(by completion)
  5. Plugin内部自定义参数
  6. 生命周期可控
  7. 无需二次封装

基于此,我们这样设计

Plugin.swift 声明基础协议

public protocol Plugin: class {

   associatedtype Input 
   associatedtype Host
   associatedtype Output

   init()

   func active(in host: Host)

   func active(for input: Input, in host: Host)

   func active(for input: Input, in host: Host, completion: ((Output) -> ())?)

   func deactivate()
}


public extension Plugin {

    func active(in host: Host) {}

    func active(for input: Input, in host: Host) {}

    func active(for input: Input, in host: Host, completion: ((Output) -> ())? = nil) {}

    func deactivate() {}
}

PluginManager.swift 插件管理器

internal final class PluginWrapper {
    let wrapped: AnyObject
    
    init<P: Plugin>(plugin: P) {
        wrapped = plugin
    }    
}

public final class PluginManager {

    private var plugins = [TypeIdentifier: PluginWrapper]()

    public init() {
    
    }

    public func add<P: Plugin>(_ pluginProvider:@autoclosure () -> P) {
    	let identifier = TypeIdentifier(type: P.self)
        plugins[identifier] = PluginWrapper(plugin: pluginProvider())
    }

    public func remove<P: Plugin>(type: P.Type) {
    	let identifier = TypeIdentifier(type: type)
        plugins.removeValue(forKey: identifier)
    }

    public func plugin<P: Plugin>(for type: P.Type) -> P {
    	if let plugin = plugins[TypeIdentifier(type: type)]?.wrapped as? P {
            return plugin
        }
    	let plugin = P()
        add(plugin)
        return plugin
    }

}

private extension PluginManager {
    struct TypeIdentifier: Hashable {
    	private let identifier: ObjectIdentifier

        init<T>(type: T.Type) {
    	    identifier = ObjectIdentifier(type)
        }
    }
}

设计完毕,玩耍起来

public class ViewController: UIViewController {

    let pluginMgr = PluginManager()

    public override func viewDidLoad() {
    	super.viewDidLoad()
        pluginMgr.plugin(for: GuidePlugin.self).active(in: self)
    	pluginMgr.plugin(for: TapPlugin.self).active(in: self)
    }

    public override func viewDidAppear(_ animated: Bool) {
    	super.viewDidAppear(animated)
        pluginMgr.remove(type: GuidePlugin.self)//no need any more
    }

    func share() {//chain demo
    	pluginMgr.plugin(LoginPlugin.self).active(for: uid, in: self, completion: {[weak self] success in
            if success {
        	self?.pluginMgr.plugin(CommentPlugin.self).active(in: self)
            }
    	)
     }

}

是不是很简单!把基础业务都转交给了具体的插件去做处理。实现了vc的空壳化。而具体插件就可以处理细节性的业务,也可以定制自己的能力。举几个例子:

分享业务

public class SharePlugin: Plugin {

    private lazy var shareHandle = ShareHandle()
    private var closure: ((ShareResult) -> ())?

    public func active(for input: (SharePlatform, [String: Any]), in host: UIViewController, completion: ((ShareResult) -> ())?) {
	closure = completion
    	shareHandle.share(to platform: input.0, params: input.1)
    }
}
extension SharePlugin: ShareDelegate {
    func shareResult() {
	closure?(result)
    }
}

引导业务

public class GuidePlugin: Plugin {

     let guideView: GuideView?

     public func active(in host: UIViewController) {
           if !db.KeyExist(key: "guide") {
 	        guideView = GuideView()
                host.view.addSubview(guideView!)
            }
     }
}

总结

设计本身没有性能优缺点。主要为解耦业务,减轻主控制器压力。增删改轻便。 如果有具体设计问题欢迎加q私聊, 371823023. 本人就职抖音,也欢迎各位大佬内推。