Java 抽象文件設計模式例子分析
阿新 • • 發佈:2019-02-19
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);
}