10-NameSpaceHandlerSupport

2020-02-18  本文已影响0人  鹏程1995

背景简介

出现的原因

我们上面介绍了 NameSpaceHandler定义的接口,其中我们发现初始化接口还好,根据各自需要定制;但是后面的接口定义我们明显发现在同一个接口中实现了多个功能

我们定义的命名空间中有多个标签,就像这在默认命名空间中我们有四个标签就if-else的写了四次,如果定义了十个呢?这就很恐怖了。

接口定义时可能考虑的是向外提供简单、实用、统一的接口,但是对内部实现人员来时则增加了复杂度,也更容易出错

所以,根据我们之前一贯的风格,如果接口定义的粒度过大,我们在后面实现时就进行委托操作,及:保证每个具体的函数/类只负责属于自己的功能

考虑到具体的函数都是要根据各自命名空间的解析规则自行实现的,NameSpaceHandlerSupport采用了"注册——读取”的方式来完成功能,并对parse/decorete接口的中的核心逻辑顺序进行实现拆出更细粒度、更专注于该命名空间中唯一的节点操作的接口

职责

适配器模式或者说是模版方法模式的一个中间角色。

注意点

弄清楚角色就好,没什么坑。

源码

实例属性

/**
 * key 节点对应的本地名字
 * value 解析此节点所需的 Parser
 */
private final Map<String, BeanDefinitionParser> parsers = new HashMap<>();

/**
 * 同上
 */
private final Map<String, BeanDefinitionDecorator> decorators = new HashMap<>();

/**
 * 同上
 */
private final Map<String, BeanDefinitionDecorator> attributeDecorators = new HashMap<>();

专门将解析和装饰拆成了两个实现接口,接口入参和NameSpaceHandler的一样。

注册解析接口

void init();

自行实现 init()接口,往实例属性的Map里放定义的各个元素对应的解析方法。

根据注册的接口提供功能

/**
 * Parses the supplied {@link Element} by delegating to the {@link BeanDefinitionParser} that is
 * registered for that {@link Element}.
 */
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
    BeanDefinitionParser parser = findParserForElement(element, parserContext);
    return (parser != null ? parser.parse(element, parserContext) : null);
}

/**
 * Locates the {@link BeanDefinitionParser} from the register implementations using
 * the local name of the supplied {@link Element}.
 */
@Nullable
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
    String localName = parserContext.getDelegate().getLocalName(element);
    BeanDefinitionParser parser = this.parsers.get(localName);
    if (parser == null) {
        parserContext.getReaderContext().fatal(
                "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
    }
    return parser;
}

思路很明确,不用再解释了。

装饰的逻辑和这个一样。

总结记录

在有多种分支的代码中,尤其是每个分支都可能有复杂逻辑的代码中,尽量不要直接用

这两种方法做:

综上,像NameSpaceSupport这样将每个具体的处理逻辑拆成一个确定的类,找个专门的包放一下,也是个不错的选择。

这个和我之前看的别的后端组的逻辑很像:

在某些后端组,在manager或者service层会直接将各个服务接口分给对应的Handler,每个实例类负责一个服务接口的功能。

我们做的项目逻辑不是特别复杂,所以项目结构大概如下:

在逻辑简单的网关组,直接

  • controller层处理请求基本信息
  • service层处理业务逻辑
  • converter层用来做对象转换【此处有点像Util】【一般一个 service类对应一个converter类,也就是多个服务接口用一个converter类】

在逻辑复杂的后端组,一般采用的是:

  • service层处理请求基本信息
  • manager层负责根据service整合n个adapter的基本功能【此处在极度复杂的情况下可能会有过长的风险】
  • adapter层负责封装对接的后端接口

问题

传进来的上下文都是什么样子的?

扩展

上一篇下一篇

猜你喜欢

热点阅读