设计模式之抽象文档模式 _ JAVA
来自维基百科的介绍——抽象文档模式
面向对象的结构设计模式,用于在松散类型的键值存储中组织对象并使用类型化视图公开数据。该模式的目的是在强类型语言中实现组件之间的高度灵活性,其中可以动态地将新属性添加到对象树,而不会失去对类型安全的支持。该模式利用特征将类的不同属性分成不同的接口。“文档”的灵感来自面向文档的数据库。
抽象文档模式的适用性和特点
需要动态添加新属性时而不影响组织结构,类属性变化频率较大
想要一种灵活的方式来组织树状结构中的域
想要更松散耦合的系统
通过集合存储属性
建立属性表统一维护类的属性
通过接口来配置获取和添加属性的方式
实例
1.抽象出基类,提供存储属性的集合。2.通过接口定义存储和获取的方法
HasType 类型属性
HasPrice 价格属性
HasColor 颜色属性
HasSize 尺码属性
HasSeason 季节属性
HasClothes 用于关联下级映射关系
Goods 商品父接口
Hat 帽子实体
Clothes 衣服实体
Costume 服饰实体,实现HasClothes即可设置Clothes相关属性
/**
* 衣服类别
*/
public interface HasClothes extends Goods {
String PROPERTY = "clothes";
default StreamgetClothes() {
return children(PROPERTY, Clothes::new);
}
}/**
* 颜色属性
*/
public interface HasColor extends Goods {
String PROPERTY = "color";
default OptionalgetColor() {
return Optional.ofNullable((String) get(PROPERTY));
}
}/**
* 价格属性
*/
public interface HasPrice extends Goods {
String PROPERTY = "price";
default OptionalgetPrice() {
return Optional.ofNullable((String) get(PROPERTY));
}
}/**
* 季节属性
*/
public interface HasSeason extends Goods {
String PROPERTY = "season";
default OptionalgetSeason() {
return Optional.ofNullable((String) get(PROPERTY));
}
}/**
* 尺码属性
*/
public interface HasSize extends Goods {
String PROPERTY = "size";
default OptionalgetSize() {
return Optional.ofNullable((String) get(PROPERTY));
}
}/**
* 类型属性
*/
public interface HasType extends Goods {
String PROPERTY = "type";
default OptionalgetType() {
return Optional.ofNullable((String) get(PROPERTY));
}
}/**
* 商品接口的抽象实现
*/
public abstract class AbstractGoods implements com.company.base.Goods {
private final Mapproperties;
protected AbstractGoods(Mapproperties) {
// 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
publicStreamchildren(String key, Function<Map, T> constructor) {
Optional<List<Map>> any = Stream.of(get(key)).filter(el -> el != null).map(el -> (List<Map>) 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);Streamchildren(String key, Function<Map, T> constructor);
}/**
* 衣服的实体类
*/
public class Clothes extends AbstractGoods implements HasPrice, HasColor, HasType, HasSize {
public Clothes(Mapproperties) {
super(properties);
}
}/**
* 服饰的实体
*/
public class Costume extends AbstractGoods implements HasSeason, HasClothes{
public Costume(Mapproperties) {
super(properties);
}
}/**
* 帽子的实体类
*/
public class Hat extends AbstractGoods implements HasPrice, HasColor, HasType, HasSize {
public Hat(Mapproperties) {
super(properties);
}
}/**
* 一种面向对象的结构设计模式,用于在松散类型的键值存储中组织对象并使用类型化视图公开数据。
* 该模式的目的是在强类型语言中实现组件之间的高度灵活性,其中可以动态地将新属性添加到对象
* 树,而不会失去对类型安全的支持。该模式利用特征将类的不同属性分成不同的接口
*/
public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
public App() {
MapclothesProperties = new HashMap<>();
clothesProperties.put(HasSize.PROPERTY, "XXL");
clothesProperties.put(HasPrice.PROPERTY, "399元");
clothesProperties.put(HasColor.PROPERTY, "棕色带图案");
clothesProperties.put(HasType.PROPERTY, "男士上衣");
Mapclothes1Properties = new HashMap<>();
clothes1Properties.put(HasSize.PROPERTY, "中号");
clothes1Properties.put(HasPrice.PROPERTY, "188元");
clothes1Properties.put(HasColor.PROPERTY, "黑色");
clothes1Properties.put(HasType.PROPERTY, "鸭舌帽");
MapcostumeProperties = 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("--> {}/{}/{}/{}",
clothes.getPrice().get(), clothes.getColor().get(),
clothes.getSize().get(), clothes.getType().get()));
}
public static void main(String[] args) {
new App();
}
}总结
所有的属性都通过Map存储。所以存储的时候不需要关心具体的类型是什么。
对象可以有子对象。比如,Costume有Hat,Clothes。Hat和Clothes都是子对象。通过Costume可以获得Hat和Clothes子对象,通过子对象设置和获取子对象的属性。
通过继承接口,实现获取类型相关的属性。Costume继承并实现接口HasSeason。如果想获得 Costume的season属性,需要调用getSeason().get()。从而实现取出的属性类型相关。
通过基类封装基本操作。这样不同Costume或者Costume和Hat、Clothes之间可以共享实现。
推荐阅读
-
4个理由告诉你Java为何排行第一
本文由码农网 –单劼原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!Java已经有20年的历史了,甚...
-
写给精明Java开发者的测试技巧
我们都会为我们的代码编写测试,不是吗?毫无疑问,我知道这个问题的答案可能会从“当然,但你知道怎样才能避免写测试吗?”到“必须...
-
Java 微服务框架 Redkale 入门介绍
Redkale功能Redkale虽然只有1.xM大小,但是麻雀虽小五脏俱全。既可作为服务器使用,也可当工具包使用。作为独立的工...
-
Java内存管理原理及内存区域详解
一、概述Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干不同的数据区域,这些区域都有各自的用途以及创建和销毁...
-
2015年Java开发岗位面试题归类
下面是我自己收集整理的Java岗位今天面经遇到的面试题,可以用它来好好准备面试。一、Java基础1.String...
-
Java 虚拟机类加载机制和字节码执行引擎
引言我们知道java代码编译后生成的是字节码,那虚拟机是如何加载这些class字节码文件的呢?加载之后又是如何进行方法调用的呢?...
-
Java常量池理解与总结
一.相关概念什么是常量用final修饰的成员变量表示常量,值一旦给定就无法改变!final修饰的变量有三种:静态...
-
Java 实现线程死锁
概述春节的时候去面试了一家公司,笔试题里面有一道是使用简单的代码实现线程的‘死锁’,当时没有想到这道题考的是Sync...
-
Java:过去、未来的互联网编程之王
Java对你而言是什么?一门你大学里学过的语言?一个IT行业的通用语言?你相信Java已经为下一次互联网爆炸做好了准备么?Java...
-
20个高级Java面试题汇总
本文由码农网 –小峰原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!这是一个高级Java面试系列题中...
