设计模式—抽象文档模式

1.概要

抽象文档模式可以处理其他非静态属性,放入Map<String,Object> 来进行存储。 此模式使用接口中的默认方法、Optional和Stream来启用类型安全性,并将不同类的属性分离为一组接口(如下的HasModel、HasParts等等)。

2. 代码结构

在这里插入图片描述

  • Document接口

  • public interface Document {
      
      Void put(String key, Object value);
      
      Object get(String key);
      
      <T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor);
    }
    
  • AbstractDocument抽象类,Document的抽象实现类

    public abstract class AbstractDocument implements Document {
    
      private final Map<String, Object> properties;
    
      protected AbstractDocument(Map<String, Object> properties) {
        this.properties = properties;
      }
    
      @Override
      public Void put(String key, Object value) {
        properties.put(key, value);
        return null;
      }
    
      @Override
      public Object get(String key) {
        return properties.get(key);
      }
    
      @Override
      public <T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor) {
        Optional<List<Map<String, Object>>> any = Stream.of(get(key))
          .filter(el -> el != null)
          .map(el -> (List<Map<String, Object>>) el)
          .findAny();
        return any.isPresent() ? any.get().stream().map(constructor) : Stream.empty();
      }
    
      @Override
      public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(getClass().getName()).append("[");
        properties.entrySet()
            .forEach(e -> builder.append("[").append(e.getKey()).append(" : ").append(e.getValue()).append("]"));
        builder.append("]");
        return builder.toString();
      }
    }
    
  • HasModel接口,继承了Document接口

    public interface HasModel extends Document {
      
      String PROPERTY = "model";
    
      default Optional<String> getModel() {
        return Optional.ofNullable((String) get(PROPERTY));
      }
    
    }
    
  • HasParts接口,继承了Document接口

    public interface HasParts extends Document {
    
      String PROPERTY = "parts";
    
      default Stream<Part> getParts() {
        return children(PROPERTY, Part::new);
      }
    
    }
    
  • HasPrice接口,继承了Document接口

    public interface HasPrice extends Document {
    
      String PROPERTY = "price";
    
      default Optional<Number> getPrice() {
        return Optional.ofNullable((Number) get(PROPERTY));
      }
    
    }
    
  • HasType接口,继承了Document接口

    public interface HasType extends Document {
    
      String PROPERTY = "type";
    
      default Optional<String> getType() {
        return Optional.ofNullable((String) get(PROPERTY));
      }
    
    }
    
  • Part类,继承AbstractDocument,实现了HasType、 HasModel、 HasPrice

    public class Part extends AbstractDocument implements HasType, HasModel, HasPrice {
    
      public Part(Map<String, Object> properties) {
        super(properties);
      }
    
    }
    
  • Car实体类,继承AbstractDocument,实现了HasType、 HasModel、 HasPrice

    public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts {
    
      public Car(Map<String, Object> properties) {
        super(properties);
      }
    
    }
    
  • 测试类

    public static void main(String[] args) {
        LOGGER.info("Constructing parts and car");
        // 车属性map
        Map<String, Object> carProperties = new HashMap<>();
        carProperties.put(HasModel.PROPERTY, "300SL");
        carProperties.put(HasPrice.PROPERTY, 10000L);
    
        // 轮子属性map
        Map<String, Object> wheelProperties = new HashMap<>();
        wheelProperties.put(HasType.PROPERTY, "wheel");
        wheelProperties.put(HasModel.PROPERTY, "15C");
        wheelProperties.put(HasPrice.PROPERTY, 100L);
    
        // 门属性map
        Map<String, Object> doorProperties = new HashMap<>();
        doorProperties.put(HasType.PROPERTY, "door");
        doorProperties.put(HasModel.PROPERTY, "Lambo");
        doorProperties.put(HasPrice.PROPERTY, 300L);
    
        carProperties.put(HasParts.PROPERTY, Arrays.asList(wheelProperties, doorProperties));
    
        Car car = new Car(carProperties);
    
        LOGGER.info("Here is our car:");
        LOGGER.info("-> model: {}", car.getModel().get());
        LOGGER.info("-> price: {}", car.getPrice().get());
        LOGGER.info("-> parts: ");
        car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}", p.getType().get(), p.getModel().get(), p.getPrice().get()));
    }
    

3.使用场景

  • 当你想灵活像树结构组织对象时,或者需要动态地添加属性时,采用抽象文档模式可以使系统更加松耦合

4.总结

  • 所有的属性都通过Map<String,Object>存储,不需要关心具体的类型是什么。
  • 对象可以有子对象。比如,Car有Wheel,door,其中wheel和door都是子对象。通过car可以获得wheel和door子对象,通过子对象设置和获取子对象的属性。
  • 通过基类封装基本操作。这样不同Car之间可以共享实现。
  • 该模式在强类型语言中实现了组件之间的高度灵活性,使新的属性可以在对象树上快速添加,而不会失去类型安全的支持。

5.参考

https://github.com/iluwatar/java-design-patterns

https://java-design-patterns.com/patterns/

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bboyzqh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值