1. 程式人生 > >Java 抽象文件設計模式例子分析

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(部分)
300SL 10000 輪子,窗戶
輪子(children document)
type(型別) model(模型) price(價值)
wheel 15C 100
門(children document)
type(型別) model(模型) price(價值)
door Lambo 300

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);
  }