美文网首页
10-NameSpaceHandlerSupport

10-NameSpaceHandlerSupport

作者: 鹏程1995 | 来源:发表于2020-02-18 16:43 被阅读0次

    背景简介

    出现的原因

    我们上面介绍了 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;
    }
    

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

    装饰的逻辑和这个一样。

    总结记录

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

    • if-else
    • if-elseprivate函数

    这两种方法做:

    • 只用if-else容易造成缩进过多,单个方法过长的问题,也不便扩展
    • if-elseprivate函数在逻辑复杂时能很好的将逻辑拆分到多个函数中,但是如果命名空间的逻辑太多,容易造成单个类的不可控

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

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

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

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

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

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

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

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

    问题

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

    扩展

    相关文章

      网友评论

          本文标题:10-NameSpaceHandlerSupport

          本文链接:https://www.haomeiwen.com/subject/fnngfhtx.html