模式12:Module Facade

 由  xuchen 发布

声明

创建一个表面作为进入其他细粒度模块内部实现的粗粒度接口。

描述

我们创建细粒度的、轻量级的模块来增加模块复用性。不幸的是,由于使用者必须明白很多不同模块的API以及联合起来使用它们来完成某项任务,这些细粒度模块很难使用。此外,轻量级模块必须被配置到环境上下文中。因此,细粒度、轻量级模块更难使用。 模块表面通过协调一组细粒度模块的工作提供了更高层次的API。模块表面强调可用性,而下面的细粒度模块强调的是复用性。下图解释了模块表面。

实现

经常,配置细粒度模块很麻烦,尤其是需要很多细粒度模块联合使用但是将这些细粒度模块整合进入一个粗粒度实体又很困难的时候。在这种情况下,模块表面可以用来暴露包含的一组细粒度模块的功能的子集.模块表面让一组细粒度模块表现为一个粗粒度模块。 当为一组细粒度、轻量级模块封装配置的时候,模块表面很有用。一般,我们创建复用性很高的细粒度、轻量级模块。另一方面,我们需要为开发者使用一组模块提供简单的方法。通过模块表面,在两者之间找到平衡。通过在模块表面中封装配置信息,开发者不需要关心如何配置一个模块。 对于一组轻量级、细粒度模块,可能需要很多模块表面。在很多方面,这和我们试图分离应用的用户接口和定义与逻辑很类似。最佳情况下,我们可以为一组存在的业务逻辑创建一个新的用户接口。这也是模块表面的目的。不同的是,模块表面经常需要封装环境上下文用来保证一组模块可以在上下文中易于复用。但是,新的上下文可能需要新的模块表面,这是允许的,尤其是当一组模块在那个上下文中被复用很多次时。 模块表面也可能基于特定的上下文增加一组带有额外行为的模块。例如,只在特定情况下执行的业务逻辑可以被封装进模块表面用来保证它服务的模块维持高度的复用性。模块表面可以增加或者减少其内部模块的API数量,也可能基于上下文通过额外的行为装饰这些模块。模块表面可以作为帮助打破一组模块之间依赖的中介,这和我们在非循环关系中讨论的“升级”很像。 我们很可能和其他的模式一起使用模块表面。例如,模块表面内部的类可能有一个发布的接口。我们可以创建新的表面抽象来便于创建其他表面。

结果:

尽管模块表面在增加一组内部模块的功能方面很有用,但是模块表面很可能对这些内部模块有依赖。也就是说,模块表面通常和其他模块紧密耦合在一起。除了高度耦合,模块表面也封装了环境行为和配置信息。这虽然降低了模块表面在不同上下文中的复用性,但是,模块表面是用来在特定上下文中配置一组模块的。 通常,模块表面使内部模块易于使用,但是模块本身布局偶很高的复用性。表面维护了这一组模块的复用性。 因为模块表面有很多依赖,所以当部署粗粒度模块表面的时候,它所以来的所有细粒度模块都需要部署。模块表面在维持内部模块复用性的同时,增加了他们的可用性,但是随之而来的依赖增加也增加了部署的复杂性。同时,单独测试模块表面也很困难。 尽管有上面的缺点,模块表面仍然是使用一组内部细粒度、轻量级模块的好方法。

内部实现类必须实例化和捆绑在一起。Spring用来完成实例化和捆绑。使得模块在很多上下文中都可以复用。配置信息允许我们在选择捆绑哪一个实现的时候具有更大的灵活性。我们把配置信息嵌入模块时,由于它包含了环境信息,这降低了它的复用性。如果模块不包含配置信息,使用起来就会很困难。通过模块表面提供的默认捆绑,我们在两者之间找到了折中点确保了可用性和复用性。。

结论:

一方面,开发者试图创建具有高度复用性的轻量级、细粒度模块。另一方面,开发者需要保证这些模块在很多上下文中易于使用。模块表面允许开发者创建粗粒度、重量级的模块配置二和协调一组轻量级、细粒度模块的活动,允许开发者在可用性和复用性上找到平衡点。

查看评论