前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式之装饰者模式

设计模式之装饰者模式

作者头像
路行的亚洲
发布2020-12-02 09:38:15
2100
发布2020-12-02 09:38:15
举报

在前面我们看到了单例模式的使用,在dubbo中,同样有单例模式的使用,找到dubbo中的ExtensionLoader类可以看到这样的代码:

/**
 * Find the extension with the given name. If the specified name is not found, then {@link IllegalStateException}
 * will be thrown.
 */
@SuppressWarnings("unchecked")
public T getExtension(String name) {
    return getExtension(name, true);
}

获取扩展:

public T getExtension(String name, boolean wrap) {
    if (StringUtils.isEmpty(name)) {
        throw new IllegalArgumentException("Extension name == null");
    }
    if ("true".equals(name)) {
        return getDefaultExtension();
    }
    final Holder<Object> holder = getOrCreateHolder(name);
    Object instance = holder.get();
    if (instance == null) {
        synchronized (holder) {
            instance = holder.get();
            if (instance == null) {
                instance = createExtension(name, wrap);
                holder.set(instance);
            }
        }
    }
    return (T) instance;
}

同时在createExtension中看到装饰者模式的使用,是否需要进行装饰wrap,如果需要,则对其进行装饰:

private T createExtension(String name, boolean wrap) {
    Class<?> clazz = getExtensionClasses().get(name);
    if (clazz == null) {
        throw findException(name);
    }
    try {
        T instance = (T) EXTENSION_INSTANCES.get(clazz);
        if (instance == null) {
            EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
            instance = (T) EXTENSION_INSTANCES.get(clazz);
        }
        injectExtension(instance);


        if (wrap) {

            List<Class<?>> wrapperClassesList = new ArrayList<>();
            if (cachedWrapperClasses != null) {
                wrapperClassesList.addAll(cachedWrapperClasses);
                wrapperClassesList.sort(WrapperComparator.COMPARATOR);
                Collections.reverse(wrapperClassesList);
            }

            if (CollectionUtils.isNotEmpty(wrapperClassesList)) {
                for (Class<?> wrapperClass : wrapperClassesList) {
                    Wrapper wrapper = wrapperClass.getAnnotation(Wrapper.class);
                    if (wrapper == null
                            || (ArrayUtils.contains(wrapper.matches(), name) && !ArrayUtils.contains(wrapper.mismatches(), name))) {
                        instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                    }
                }
            }
        }

        initExtension(instance);
        return instance;
    } catch (Throwable t) {
        throw new IllegalStateException("Extension instance (name: " + name + ", class: " +
                type + ") couldn't be instantiated: " + t.getMessage(), t);
    }
}

上面是使用wrapper的场景进行装饰,也可以说成是包装,本质就是装饰者模式的体现。除了wrapper,在spring中也有装饰者模式的体现。

在前面的注册beanDefintion的时候,进行默认标签解析时,会经过四步:

/**
 * Process the given bean element, parsing the bean definition
 * and registering it with the registry.
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
   //解析beanDefintion元素 
   BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
   if (bdHolder != null) {
      //进行装饰
      bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
      try {
         // Register the final decorated instance.
          //注册最终被装饰的实例
         BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
      }
      catch (BeanDefinitionStoreException ex) {
         getReaderContext().error("Failed to register bean definition with name '" +
               bdHolder.getBeanName() + "'", ele, ex);
      }
      // Send registration event.
      //发送注册事件 
      getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
   }
}

除了这里使用装饰者模式之外,对于wrapper的对象也是采用了装饰者模式。如果我们需要实现一个装饰者模式,那么怎样实现呢?

/**
 * Decorate the given bean definition through a namespace handler, if applicable.
  如果使用,通过名称空间处理程序装饰给定的beanDefintion
 * @param ele the current element  当前元素ele
 * @param originalDef the current bean definition 当前的beanDefintion =>originalDef
 * @param containingBd the containing bean definition (if any)
 * @return the decorated bean definition 返回被装饰好的beanDefintion
 */
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
      Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

   BeanDefinitionHolder finalDefinition = originalDef;

   // Decorate based on custom attributes first.
   NamedNodeMap attributes = ele.getAttributes();
   for (int i = 0; i < attributes.getLength(); i++) {
      Node node = attributes.item(i);
      finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
   }

   // Decorate based on custom nested elements.
   NodeList children = ele.getChildNodes();
   for (int i = 0; i < children.getLength(); i++) {
      Node node = children.item(i);
      if (node.getNodeType() == Node.ELEMENT_NODE) {
         finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
      }
   }
   return finalDefinition;
}

进行装饰如果需要:

/**
 * Decorate the given bean definition through a namespace handler,
 * if applicable.
 * @param node the current child node
 * @param originalDef the current bean definition
 * @param containingBd the containing bean definition (if any)
 * @return the decorated bean definition
 */
public BeanDefinitionHolder decorateIfRequired(
      Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) {

   String namespaceUri = getNamespaceURI(node);
   if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) {
      NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
      if (handler != null) {
         BeanDefinitionHolder decorated =
               handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
         if (decorated != null) {
            return decorated;
         }
      }
      else if (namespaceUri.startsWith("http://www.springframework.org/")) {
         error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
      }
      else {
         // A custom namespace, not to be handled by Spring - maybe "xml:...".
         if (logger.isDebugEnabled()) {
            logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
         }
      }
   }
   return originalDef;
}

如果debug的时候,可以看到程序中在默认标签中,如果存在自定义的标签时,此时就需要对自定义标签进行解析,此时会寻找命名空间getNamespaceURI,使用命名空间处理器进行标签的解析:this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)。这个就是自定义标签解析的套路。

要实现装饰者模式,需要完成:

1.继承处理接口
2.提供构造函数或者set方法
3.覆盖原有接口方法

装饰者的使用场景:

如果不想要改变原有接口的实现,而又想增加新的功能或者特性时,此时就可以考虑使用装饰者模式对原有的功能进行只增强

下面我们来看一个装饰者模式的例子:

原始的例子:

在小商店还很小的时候,只提供做煎饼的业务,这个时候的样式比较单一,这个时候师傅只做煎饼,随着客户的反馈,之后在煎饼的基础之上又加上了鸡蛋,但随后有加上了香肠,形成了煎饼+鸡蛋+香肠的方式,代码来源于github…

原始接口:

public class BatterCake {

    //商品信息
    public String getMsg() {
        return "煎饼";
    }

    //获取价格
    public int getPrice() {
        return 5;
    }
}

原始的实现方式:

煎饼+鸡蛋

public class BatterCakeWithEgg extends BatterCake {
    @Override
    public String getMsg() {
        return super.getMsg() +" + 1个鸡蛋";
    }

    @Override
    public int getPrice() {
        return super.getPrice()+1;
    }
}

煎饼+鸡蛋+香肠:

//在原有煎饼+鸡蛋的基础之上,加1个香肠
public class BatterCakeWithEggAndHotdog extends BatterCakeWithEgg {
    @Override
    public String getMsg() {
        return super.getMsg() +" + 1个香肠";
    }

    @Override
    public int getPrice() {
        return super.getPrice() +2;
    }
}

进行商品、价格获取:

public class BatterCakeTest {
    public static void main(String[] args) {
        //创建一个对象煎饼
        BatterCake batterCake = new BatterCake();
        System.out.println(batterCake.getMsg() +" 的价格是:"+batterCake.getPrice());

        //创建一个煎饼+鸡蛋对象
        batterCake = new BatterCakeWithEgg();
        System.out.println(batterCake.getMsg() +" 的价格是:"+batterCake.getPrice());

        //创建一个煎饼+鸡蛋+香肠
        batterCake = new BatterCakeWithEggAndHotdog();
        System.out.println(batterCake.getMsg() +" 的价格是:"+batterCake.getPrice());
    }
}

结果:

使用装饰者模式进行重构:

原始接口:

public abstract class BatterCake {

    //商品信息
    protected abstract String getMsg();
    //价格
    protected abstract int getPrice();
}

原始接口实现:

public class BaseBatterCake extends BatterCake {
    protected String getMsg() {
        return "煎饼";
    }

    protected int getPrice() {
        return 5;
    }
}

待装饰的类:

// 装饰类继承原始接口
public class BatterCakeDecorator extends BatterCake {
   //原始接口对象
    private BatterCake batterCake;

    //提供构造函数
    public BatterCakeDecorator(BatterCake batterCake) {
        this.batterCake = batterCake;
    }

    //重写原始接口的方法
    @Override
    protected String getMsg() {
        return this.batterCake.getMsg();
    }

    @Override
    protected int getPrice() {
        return this.batterCake.getPrice();
    }
}

进行装饰:

//进行装饰:在原有的基础上进行装饰
public class BatterCakeEggDecorator extends BatterCakeDecorator {

    //原始的数据构造函数
    public BatterCakeEggDecorator(BatterCake batterCake) {
        super(batterCake);
    }

    //重写原始方法
    @Override
    protected String getMsg() {
        return super.getMsg() +" 1 个鸡蛋";
    }

    //重写原始方法
    @Override
    protected int getPrice() {
        return super.getPrice() +1;
    }
}

进行装饰:

//进行进一步装饰
public class BatterCakeWihHotdogDecorator extends BatterCakeDecorator {
    //需要装饰的对象
    public BatterCakeWihHotdogDecorator(BatterCake batterCake) {
        super(batterCake);
    }

    //重写被装饰方法
    @Override
    protected String getMsg() {
        return super.getMsg() +" 1 个香肠";
    }

    @Override
    protected int getPrice() {
        return super.getPrice() + 2;
    }
}

进行测试:

public class BatterCakeDecoratorTest {
    public static void main(String[] args) {
       //原始被修饰对象
        BaseBatterCake baseBatterCake = new BaseBatterCake();
        //装饰对象
        BatterCakeDecorator batterCakeDecorator = new BatterCakeDecorator(baseBatterCake);
        //创建装饰后对象
        batterCakeDecorator = new BatterCakeEggDecorator(batterCakeDecorator);
        //创建最终装饰的对象
        batterCakeDecorator = new BatterCakeWihHotdogDecorator(batterCakeDecorator);

        System.out.println(batterCakeDecorator.getMsg() +" 的总价是: "+batterCakeDecorator.getPrice());
    }
}

最终被增强的对象的信息:

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-11-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 后端技术学习 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档