设计模式之抽象文档模式
Posted 优享JAVA
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之抽象文档模式相关的知识,希望对你有一定的参考价值。
抽象文档模式(abstract-document)的意图是保持类型安全的情况下实现无类型语言的灵活性, 通过抽象的方式更加灵活的配置类的属性,更加安全对属性进行配置
来自维基百科的介绍——抽象文档模式
面向对象的结构设计模式,用于在松散类型的键值存储中组织对象并使用类型化视图公开数据。该模式的目的是在强类型语言中实现组件之间的高度灵活性,其中可以动态地将新属性添加到对象树,而不会失去对类型安全的支持。该模式利用特征将类的不同属性分成不同的接口。“文档”的灵感来自面向文档的数据库。
抽象文档模式的适用性和特点
需要动态添加新属性时而不影响组织结构,类属性变化频率较大
想要一种灵活的方式来组织树状结构中的域
想要更松散耦合的系统
通过集合存储属性
建立属性表统一维护类的属性
通过接口来配置获取和添加属性的方式
实例
1.抽象出基类,提供存储属性的集合。
2.通过接口定义存储和获取的方法
HasType 类型属性
HasPrice 价格属性
HasColor 颜色属性
HasSize 尺码属性
HasSeason 季节属性
HasClothes 用于关联下级映射关系
Goods 商品父接口
Hat 帽子实体
Clothes 衣服实体
Costume 服饰实体,实现HasClothes即可设置Clothes相关属性
/**
* 衣服类别
*/
public interface HasClothes extends Goods {
String PROPERTY = "clothes";
default Stream<Clothes> getClothes() {
return children(PROPERTY, Clothes::new);
}
}
/**
* 颜色属性
*/
public interface HasColor extends Goods {
String PROPERTY = "color";
default Optional<String> getColor() {
return Optional.ofNullable((String) get(PROPERTY));
}
}
/**
* 价格属性
*/
public interface HasPrice extends Goods {
String PROPERTY = "price";
default Optional<String> getPrice() {
return Optional.ofNullable((String) get(PROPERTY));
}
}
/**
* 季节属性
*/
public interface HasSeason extends Goods {
String PROPERTY = "season";
default Optional<String> getSeason() {
return Optional.ofNullable((String) get(PROPERTY));
}
}
/**
* 尺码属性
*/
public interface HasSize extends Goods {
String PROPERTY = "size";
default Optional<String> getSize() {
return Optional.ofNullable((String) get(PROPERTY));
}
}
/**
* 类型属性
*/
public interface HasType extends Goods {
String PROPERTY = "type";
default Optional<String> getType() {
return Optional.ofNullable((String) get(PROPERTY));
}
}
/**
* 商品接口的抽象实现
*/
public abstract class AbstractGoods implements com.company.base.Goods {
private final Map<String, Object> properties;
protected AbstractGoods(Map<String, Object> properties) {
// JDK工具类,是一些静态方法组成,主要用于操作对象、计算对象的哈希码,返回对象的字符串和比较两个对象
Objects.requireNonNull(properties, "properties map is required");
this.properties = properties;
}
@Override
public Object get(String key) {
return properties.get(key);
}
@Override
public void put(String key, Object value) {
properties.put(key, value);
}
@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();
}
}
/**
* 商品的超级接口
*/
public interface Goods {
void put(String key, Object value);
Object get(String key);
<T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor);
}
/**
* 衣服的实体类
*/
public class Clothes extends AbstractGoods implements HasPrice, HasColor, HasType, HasSize {
public Clothes(Map<String, Object> properties) {
super(properties);
}
}
/**
* 服饰的实体
*/
public class Costume extends AbstractGoods implements HasSeason, HasClothes{
public Costume(Map<String, Object> properties) {
super(properties);
}
}
/**
* 帽子的实体类
*/
public class Hat extends AbstractGoods implements HasPrice, HasColor, HasType, HasSize {
public Hat(Map<String, Object> properties) {
super(properties);
}
}
/**
* 一种面向对象的结构设计模式,用于在松散类型的键值存储中组织对象并使用类型化视图公开数据。
*/
public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
public App() {
Map<String, Object> clothesProperties = new HashMap<>();
clothesProperties.put(HasSize.PROPERTY, "XXL");
clothesProperties.put(HasPrice.PROPERTY, "399元");
clothesProperties.put(HasColor.PROPERTY, "棕色带图案");
clothesProperties.put(HasType.PROPERTY, "男士上衣");
Map<String, Object> clothes1Properties = new HashMap<>();
clothes1Properties.put(HasSize.PROPERTY, "中号");
clothes1Properties.put(HasPrice.PROPERTY, "188元");
clothes1Properties.put(HasColor.PROPERTY, "黑色");
clothes1Properties.put(HasType.PROPERTY, "鸭舌帽");
Map<String, Object> costumeProperties = new HashMap<>();
costumeProperties.put(HasSeason.PROPERTY, "春季新款");
costumeProperties.put(HasClothes.PROPERTY,
Arrays.asList(clothesProperties, clothes1Properties));
com.company.Costume costume = new com.company.Costume(costumeProperties);
LOGGER.debug("季节上新:");
LOGGER.debug("-------------------------");
LOGGER.debug("--> 季节: {}", costume.getSeason().get());
LOGGER.debug("--> 明细: ");
costume.getClothes().forEach(clothes -> LOGGER.debug("-->\t {}/{}/{}/{}",
clothes.getPrice().get(), clothes.getColor().get(),
clothes.getSize().get(), clothes.getType().get()));
}
public static void main(String[] args) {
new App();
}
}
总结
1、所有的属性都通过Map存储。所以存储的时候不需要关心具体的类型是什么。
2、对象可以有子对象。比如,Costume有Hat,Clothes。Hat和Clothes都是子对象。通过Costume可以获得Hat和Clothes子对象,通过子对象设置和获取子对象的属性。
3、通过继承接口,实现获取类型相关的属性。Costume继承并实现接口HasSeason。如果想获得 Costume的season属性,需要调用getSeason().get()。从而实现取出的属性类型相关。
4、通过基类封装基本操作。这样不同Costume或者Costume和Hat、Clothes之间可以共享实现。
以上是关于设计模式之抽象文档模式的主要内容,如果未能解决你的问题,请参考以下文章