目录
定义:
抽象文档模式支持处理附加的非静态属性。该模式使用特征的概念来实现类型安全,并将不同类的属性分离到一组接口中。
请考虑一辆由多个部件组成的车。然而,我们不知道具体的汽车是否真的拥有所有的零件,或者只是其中的一部分。我们的汽车是动态的,非常灵活。
>抽象文档模式允许在对象不知道的情况下将属性附加到对象。
一种面向对象的结构设计模式,用于在松散类型的键值存储中组织对象,并使用类型化视图公开数据。该模式的目的是在强类型语言中实现组件之间的高度灵活性,在这种语言中,可以动态地向对象树添加新属性,而不会失去类型安全性的支持。该模式利用特征将类的不同属性分离到不同的接口中。
场景:
生活中经常有部分和整体互相嵌套构成完整对象的场景。比如文件夹和文件,文件夹里可以嵌套文件和文件夹。汽车由轮子,发动机,外壳组成。外壳又是玻璃窗和金属框组成。通常我们的做法是定义一个包含自己的对象。抽象出来就是抽象文档设计模式。
设计:
目录结构:
结果:
Here is our car:
-> model: {特斯拉S}
-> price: {10000}
-> parts: {
wheel///米其林轮胎///100}
door///飞虎门窗///300}
实现:
package com.study_abs_doucument.damain;
import com.study_abs_doucument.AbstractDocument;
import java.util.Map;
/**
* 汽车实体。
*/
public class Car extends AbstractDocument implements HasModel, HasParts, HasPrice {
public Car(Map<String, Object> properties) {
super(properties);
}
}
package com.study_abs_doucument.damain;
import com.study_abs_doucument.Document;
import java.util.Optional;
/**
* HasModel特性用于静态访问“model”属性。
*/
public interface HasModel extends Document {
default Optional<String> getModel() {
return Optional.ofNullable((String) get(Property.MODEL.toString()));
}
}
package com.study_abs_doucument.damain;
import com.study_abs_doucument.Document;
import java.util.stream.Stream;
/**
HasParts特性用于静态访问“parts”属性。
*/
public interface HasParts extends Document {
default Stream<Part> getParts(){
return children(Property.PARTS.toString(),Part::new);
}
}
/*
* The MIT License
* Copyright © 2014-2021 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.study_abs_doucument.damain;
import com.study_abs_doucument.Document;
import java.util.Optional;
/**
* HasPrice trait for static access to 'price' property.
*/
public interface HasPrice extends Document {
default Optional<Number> getPrice() {
return Optional.ofNullable((Number) get(Property.PRICE.toString()));
}
}
/*
* The MIT License
* Copyright © 2014-2021 Ilkka Seppälä
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.study_abs_doucument.damain;
import com.study_abs_doucument.Document;
import java.util.Optional;
/**
* HasType trait for static access to 'type' property.
*/
public interface HasType extends Document {
default Optional<String> getType() {
return Optional.ofNullable((String) get(Property.TYPE.toString()));
}
}
package com.study_abs_doucument.damain;
import com.study_abs_doucument.AbstractDocument;
import java.util.Map;
/**
* 部分实体
*/
public class Part extends AbstractDocument implements HasModel, HasPrice, HasType {
public Part(Map<String, Object> properties) {
super(properties);
}
}
package com.study_abs_doucument.damain;
/**
* 枚举以描述属性类型do
*/
public enum Property {
PARTS, TYPE, PRICE, MODEL
}
package com.study_abs_doucument;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Stream;
/**
*
* @Description 文档接口的抽象实现
* @Date 2022/1/6 16:42
*/
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);
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(get(key))
.filter(Objects::nonNull)
.map(el -> (List<Map<String, Object>>) el)
.findAny()
.stream()
.flatMap(Collection::stream)
.map(constructor);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(getClass().getName()).append("[");
properties.forEach((key, value) -> builder.append("[").append(key).append(" : ").append(value)
.append("]"));
builder.append("]");
return builder.toString();
}
}
package com.study_abs_doucument;
import com.study_abs_doucument.damain.Car;
import com.study_abs_doucument.damain.Property;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
/**
* <p>
* 抽象文档模式支持处理附加的非静态属性。该模式使用特征的概念来实现类型安全,
* 并将不同类的属性分离到一组接口中<p> 在抽象文档模式中,
* ({@link AbstractDocument})完全实现了{@link Document})接口。
* 然后定义特征,以便以通常的静态方式访问属性。
*/
public class App {
public static void main(String[] args) {
Map<String, ? extends Serializable> wheel = Map.of(Property.TYPE.toString(), "wheel",
Property.MODEL.toString(), "米其林轮胎",
Property.PRICE.toString(), 100L);
Map<String, ? extends Serializable> door = Map.of(Property.TYPE.toString(), "door",
Property.MODEL.toString(), "飞虎门窗",
Property.PRICE.toString(), 300L);
Map<String, Object> car = Map.of(
Property.MODEL.toString(), "特斯拉S",
Property.PRICE.toString(), 10000L,
Property.PARTS.toString(), List.of(wheel, door));
Car carEntity = new Car(car);
System.out.println("Here is our car:");
System.out.println("-> model: {"+ carEntity.getModel().orElseThrow() +"}");
System.out.println("-> price: {"+ carEntity.getPrice().orElseThrow() + "}");
System.out.println("-> parts: " + "{");
carEntity.getParts().forEach(p -> System.out.println(
p.getType().orElse(null)+"///"+
p.getModel().orElse(null)+"///"+
p.getPrice().orElse(null) +"}")
);
}
}
package com.study_abs_doucument;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Stream;
/**
* 文档接口
*
* 适合有相同属性,但是存在组合,上下级的模式,内嵌模式
* 文件夹与文件,汽车,树型
*
*/
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);
}