定义:用于组织松散类型的键值存储中的对象并使用类型化的视图公开数据。 该模式的目的是在强类型语言中实现组件之间的高度灵活性,在这种语言中,可以在不丢失类型安全支持的情况下,将新属性动态地添加到对象树中。 该模式利用特征将类的不同属性分成不同的接口。
类图:
示例:考虑由多个部分组成的汽车。 但是,我们不知道特定汽车是否真的拥有所有零件,或者仅仅是零件中的一部分。 我们的汽车是动态而且非常灵活的。
代码示例:
1.创建Document接口,定义基本行为
public interface Document {
void put(String key,Object object);
Object get(String key);
<T> Stream<T> children(String key, Function<Map<String,Object>,T> constructor);
}
2.创建抽象类AbstractDoucument实现Document接口,实现抽象方法具体逻辑,定义属性,存放数据对象
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 object) {
properties.put(key, object);
}
@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();
}
}
3.定义枚举类,内容为文档的增强属性。
public enum Property {
PARTS, //零件
TYPE, //类型
PRICE,//价格
MODEL //模型
}
4.创建零件接口
public interface HasModel extends Document {
default Optional<String> getModel() {
return Optional.ofNullable((String) get(Property.MODEL.toString()));
}
}
public interface HasPrice extends Document{
default Optional<Number> getPrice(){
return Optional.ofNullable( (Number) get(Property.PRICE.toString()));
}
}
public interface HasType extends Document{
default Optional<String> getType(){
return Optional.ofNullable((String) get(Property.TYPE.toString()));
}
}
5.创建Part类,作为汽车零件的实现类
public class Part extends AbstractDocument implements HasPrice,HasModel,HasType{
public Part(Map<String, Object> properties) {
super(properties);
}
}
6.创建零件接口,返回零件对象
public interface HasParts extends Document {
default Stream<Part> getParts() {
return children(Property.PARTS.toString(),Part::new);
}
}
7.测试
public class Test {
public static void main(String[] args) {
Map<String, Object> map = new HashMap<>();
map.put(Property.MODEL.toString(),"300Ls");
map.put(Property.PRICE.toString(),1000L);
Map<String, Object> wheelProperties = new HashMap<>();
wheelProperties.put(Property.TYPE.toString(), "wheel");
wheelProperties.put(Property.MODEL.toString(), "15C");
wheelProperties.put(Property.PRICE.toString(), 100L);
Map<String, Object> doorProperties = new HashMap<>();
doorProperties.put(Property.TYPE.toString(), "door");
doorProperties.put(Property.MODEL.toString(), "Lambo");
doorProperties.put(Property.PRICE.toString(), 300L);
map.put(Property.PARTS.toString(), Arrays.asList(wheelProperties,doorProperties));
Car car = new Car(map);
car.getParts().forEach(x-> {System.out.println(x.getType());
System.out.println(x.getModel());
System.out.println(x.getPrice());
});
System.out.println("<---------->");
System.out.println(car.getPrice());
System.out.println(car.getModel());
}
}
输出为:
Optional[wheel]
Optional[15C]
Optional[100]
Optional[door]
Optional[Lambo]
Optional[300]
<---------->
Optional[1000]
Optional[300Ls]
参考:
https://java-design-patterns.com
https://github.com/iluwatar/java-design-patterns-vuepress-web