容器模式

90 阅读4分钟

分析了一部分xflow的源码(command和hook),发现这里面有一个非常有意思的东西,我在这里叫它插槽,而源码中命名为contribution。本篇从定义、目的、实例和应用四方面对插槽进行分析。

你没看过或者也不想看xflow源码也没关系,这里重点讲模式。

插槽

你可能使用过vue中的插槽,没看过也没事,react中的children也是类似的东西,react也没用过的可以看下

image.png

小时候都玩过小霸王游戏机,游戏机中的插槽能让我们插很多游戏的卡。

插槽的优点

通过观察vue、react、游戏机中的插槽,我们发现插槽很好用,我小时候就有一盒子游戏卡,各种类型的,而且还能借别人的,只要能插到游戏机的插槽中就能玩(不能玩就用酒精擦一下)。

所以不难发现插槽的特点就是可以“无限扩展”,但是要符合插槽的接口。

如果我们的项目中某个类有大量类似的“零件”,或者我们希望能让别人给类添加”零件“而类保持不变,

哪就可以通过插槽的模式,把这些“零件”拆分开,然后再插到插槽里,类只负责存储“零件”,由“零件”本身决定是否加入这个类。

代码的维护性、扩展性都更优雅了。

xflow中的插槽

xflow是一个复杂的框架,涉及到命令、hook、状态等,而命令又分为节点命令、连线命令、图形命令等等,下面看下它是如何管理如此庞大的对象的。

xflow有一个FrontendApplication类,这个类的实例通过hooks暴露给开发者各种图形API,所以这个类就需要很多“零件”,包括图形命令、钩子函数、快捷键、菜单、工具栏、状态等,要想这些“零件”能插到插槽中需要一个插槽机制。

xflow框架用的是mana-syringe管理自己的类实例,这篇文章有详细介绍,下面简单提一下mana-syringe使用的三个步骤,然后看下如何通过这三个步骤完成插槽机制。

声明:每个类都可以声明集合标示(IFrontendApplicationContribution)和类标示(IGraphCommandService),singleton标示这个类是单例的。

@singleton({ contrib: [IFrontendApplicationContribution, IGraphCommandService], })

绑定:mana-syringe需要类把自己绑定到mana-syringe的容器上,这样才能被管理。register是mana-syringe上的管理对象,GraphCommandRegistry就是上面声明标示的类。

register(GraphCommandRegistry)

注入:一般注入是使用@inject,传入类标示就可以获取类实例,这里的@contrib是对@inject的封装,是把所有声明为IFrontendApplicationContribution标示的类收集起来。

@contrib(IFrontendApplicationContribution) protected readonly contributions!: Contribution.Provider<IFrontendApplicationContribution>

其实看完这三个步骤就知道xflow中的插槽机制了,类自己声明集合标示,IFrontendApplicationContribution直接通过集合标示把所有声明集合标示的类的实例收集到自己的contributions对象中了。

而且各个contributions中的类还可以定义自己的contributions,这样就能把每个类中的“零件”进一步划分。

对contributions还可以一些统一处理,拿游戏卡举例,当卡插到插槽中后,游戏机会读取卡中数据,然后初始化游戏机,渲染游戏画面等过程。同样,xflow对contributions的中的对象也都做了初始化处理。而mana-syringe其实是对InversifyJSk框架的封装。

个人对xflow用插槽的看法,好处有:

  1. 容器、零件职责清晰,代码层次感很强。
  2. 引入了mana-syringe,很好的做了解耦。
  3. 更容易扩展了,只需在容器中添加注册扩展的逻辑即可。

项目中如何应用

这块我自己实战也很少,大家现在都用react、vue这类框架,都像拼积木一样,好处坏处都有,好处是简单、高效,坏处是开发人本身用到的、学到的都比较浅。

由于这块我经验少,所以看看谁有jQuery或者其它比较“原始”的项目发个仓库链接,可以一块研究下如何用插槽更优雅的组织代码。