Java 抽象文档设计模式例子分析

Document.interface


/**
 * Document 接口
 */
public interface Document {

  /**
   * 设置目标键相关联的值
   *
   * @param key   element key
   * @param value element value
   * @return Void
   */
  Void put(String key, Object value);

  /**
   * 得到目标键相关联的值
   *
   * @param key element key
   * @return value or null
   */
  Object get(String key);

  /**
   * 得到孩子文档
   *
   * @param key         element key
   * @param constructor constructor of child class
   * @return child documents
   */
  <T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor);
}
上面三个方法就是抽象文档的三个接口,put()和get()方法很好理解,问题关键在于理解children方法,何为得到孩子文档?
举个例子,一辆小汽车有很多属性组成,轮子 ,窗户,发动机,…..很多时候我们想知道小汽车自身的价格,以及他的轮子,窗户。后面又想知道汽车的牌子是奥迪还是宝马。如果依依定义出确切的对象以及子对象是非常痛苦的。但是我们似乎可以定义出一组共用的类型,赋给小汽车和他的组成对象:
小汽车(root document)
model(模型)price(价值)parts(部分)
300SL10000轮子,窗户
轮子(children document)
type(类型)model(模型)price(价值)
wheel15C100
门(children document)
type(类型)model(模型)price(价值)
doorLambo300
App.class

  public class App {

  private static final Logger LOGGER = LoggerFactory.getLogger(App.class);

  /**
   * Executes the App
   */
  public App() {
    LOGGER.info("Constructing parts and car");
 //汽车的属性
 Map<String, Object> carProperties = new HashMap<>();
 carProperties.put(HasModel.PROPERTY, "300SL");
 carProperties.put(HasPrice.PROPERTY, 10000L);

 //汽车轮子的属性
 Map<String, Object> wheelProperties = new HashMap<>();
 wheelProperties.put(HasType.PROPERTY, "wheel");
 wheelProperties.put(HasModel.PROPERTY, "15C");
 wheelProperties.put(HasPrice.PROPERTY, 100L);

 //汽车窗户的属性
 Map<String, Object> doorProperties = new HashMap<>();
 doorProperties.put(HasType.PROPERTY, "door");
 doorProperties.put(HasModel.PROPERTY, "Lambo");
 doorProperties.put(HasPrice.PROPERTY, 300L);

 //把轮子和窗户放入Parts中
 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()

  }

  /**
   * Program entry point
   *
   * @param args command line args
   */
  public static void main(String[] args) {
    new App();
  }



结果输出:
  • Constructing parts and car
  • Here is our car:
  • -> model: 300SL
  • -> price: 10000
  • -> parts:
  • wheel/15C/100
  • door/Lambo/300
AbstractDocument.class
public abstract class AbstractDocument implements Document {

  private final Map<String, Object> properties;
  //以map的形式存放键值类型
  protected AbstractDocument(Map<String, Object> properties) {
    Objects.requireNonNull(properties, "properties map is required");
    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)//将object转换成List<Map<String, Object>>
    .findAny();//取任意一个值
    return any.isPresent() //判断是否存在
    ? any.get().stream().map(constructor) //将Map<String, Object> 转换成类型T
     : 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.interface
public interface HasModel extends Document {

  String PROPERTY = "model";

  default Optional<String> getModel() {
    return Optional.ofNullable((String) get(PROPERTY));
  }

}
HasParts.interface
public interface HasParts extends Document {

  String PROPERTY = "parts";

  default Stream<Part> getParts() {
    return children(PROPERTY, Part::new); //Part::new 拉姆达构造函数引用
  }

}
HasPrice .interface
public interface HasPrice extends Document {

  String PROPERTY = "price";

  default Optional<Number> getPrice() {
    return Optional.ofNullable((Number) get(PROPERTY));
  }

}
HasType.interface
public interface HasType extends Document {

  String PROPERTY = "type";

  default Optional<String> getType() {
    return Optional.ofNullable((String) get(PROPERTY));
  }

}

Part.class
public class Part extends AbstractDocument implements HasType, HasModel, HasPrice {

  public Part(Map<String, Object> properties) {
    super(properties);
  }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值