抽象文档模式

作用

可以在对象的属性不确定的情况下,动态的修改对象的属性

类结构图

代码

定义一个接口和一个抽象类

1
2
3
4
5
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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public abstract class AbstractDocument implements Document{

private final Map<String,Object> properties;

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) {
return Stream.ofNullable(this.get(key))
.filter(Objects::nonNull)
.map(el -> (List<Map<String,Object>>) el)
.findAny()
.stream()
.flatMap(Collection::stream)
.map(constructor);
}
}

定义基本属性枚举

1
2
3
public enum Property {
PARTS,TYPE,PRICE,MODEL
}

定义可选接口

1
2
3
4
5
public interface HasModel extends Document{
default Optional<String> getModel(){
return Optional.ofNullable((String) get(Property.MODEL.toString()));
}
}
1
2
3
4
5
public interface HasParts extends Document{
default Stream<Part> getParts(){
return children(Property.PARTS.toString(),Part::new);
}
}
1
2
3
4
5
public interface HasPrice extends Document{
default Optional<Number> getPrice(){
return Optional.ofNullable((Number) get(Property.PRICE.toString()));
}
}
1
2
3
4
5
public interface HasType extends Document{
default Optional<String> getType(){
return Optional.ofNullable((String) get(Property.TYPE.toString()));
}
}

定义主要类

1
2
3
4
5
public class Part extends AbstractDocument implements HasModel,HasParts,HasPrice,HasType{
public Part(Map<String,Object> properties){
super((properties));
}
}
1
2
3
4
5
public class Car extends AbstractDocument implements HasModel,HasParts,HasPrice,HasType{
public Car(Map<String,Object> properties){
super((properties));
}
}

最后-测试方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
log.info("Constrcting parts and card");

var wheelProperties = Map.of(
Property.TYPE.toString(), "wheel",
Property.MODEL.toString(), "15C",
Property.PRICE.toString(), 100L
);

var doorProperties = Map.of(
Property.TYPE.toString(), "door",
Property.MODEL.toString(), "lambo",
Property.PRICE.toString(), 300L
);

var carProperties = Map.of(
Property.MODEL.toString(), "300SL",
Property.PRICE.toString(), 10000L,
Property.PARTS.toString(), List.of(wheelProperties,doorProperties)
);

var car = new Car((carProperties));

log.info("这是我们的车:");
log.info("-> model : {}",car.getModel().orElseThrow());
log.info("-> price : {}",car.getPrice().orElseThrow());
log.info("-> parts : ");
car.getParts().forEach(p -> log.info("\t{}/{}/{}",
p.getType().orElse(null),
p.getModel().orElse(null),
p.getPrice().orElse(null)
));

输出:

1
2
3
4
5
6
7
Constrcting parts and card
这是我们的车:
-> model : 300SL
-> price : 10000
-> parts :
wheel/15C/100
door/lambo/300