来自维基百科的介绍——
面向对象的结构
抽象文档模式的适用性和特点
需要动态添加新属性时而不影响组织结构,类属性变化频率较大
想要一种灵活的方式来组织树状结构中的域
想要更松散耦合的系统
通过集合存储属性
建立属性表统一维护类的属性
通过接口来配置获取和添加属性的方式
实例
1.抽象出基类,提供存储属性的集合。
2.通过接口定义存储和获取的方法
代码示例类图
HasType 类型属性
HasPrice 价格属性
HasColor 颜色属性
HasSize 尺码属性
HasSeason 季节属性
HasClothes 用于关联下级映射关系
Goods 商品父接口
Hat 帽子实体
Clothes 衣服实体
Costume 服饰实体,实现HasClothes即可设置Clothes相关属性
/**
* 衣服类别
*/
public interface HasClothes extends Goods {
String PROPERTY = "clothes";
default Stream getClothes() {
return children(PROPERTY, Clothes::new);
}
}
/**
* 颜色属性
*/
public interface HasColor extends Goods {
String PROPERTY = "color";
default Optional getColor() {
return Optional.ofNullable((String) get(PROPERTY));
}
}
/**
* 价格属性
*/
public interface HasPrice extends Goods {
String PROPERTY = "price";
default Optional getPrice() {
return Optional.ofNullable((String) get(PROPERTY));
}
}
/**
* 季节属性
*/
public interface HasSeason extends Goods {
String PROPERTY = "season";
default Optional getSeason() {
return Optional.ofNullable((String) get(PROPERTY));
}
}
/**
* 尺码属性
*/
public interface HasSize extends Goods {
String PROPERTY = "size";
default Optional getSize() {
return Optional.ofNullable((String) get(PROPERTY));
}
}
/**
* 类型属性
*/
public interface HasType extends Goods {
String PROPERTY = "type";
default Optional getType() {
return Optional.ofNullable((String) get(PROPERTY));
}
}
/**
* 商品接口的抽象实现
*/
public abstract class AbstractGoods implements com.company.base.Goods {
private final Map properties;
protected AbstractGoods(Map 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 Stream children(String key, Function, T> constructor) {
Optional>> any = Stream.of(get(key)).filter(el -> el != null).map(el -> (List>) 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);
Stream children(String key, Function, T> constructor);
}
/**
* 衣服的实体类
*/
public class Clothes extends AbstractGoods implements HasPrice, HasColor, HasType, HasSize {
public Clothes(Map properties) {
super(properties);
}
}
/**
* 服饰的实体
*/
public class Costume extends AbstractGoods implements HasSeason, HasClothes{
public Costume(Map properties) {
super(properties);
}
}
/**
* 帽子的实体类
*/
public class Hat extends AbstractGoods implements HasPrice, HasColor, HasType, HasSize {
public Hat(Map properties) {
super(properties);
}
}
/**
* 一种面向对象的结构设计模式,用于在松散类型的键值存储中组织对象并使用类型化视图公开数据。
* 该模式的目的是在强类型语言中实现组件之间的高度灵活性,其中可以动态地将新属性添加到对象
* 树,而不会失去对类型安全的支持。该模式利用特征将类的不同属性分成不同的接口
*/
public class App {
private static final Logger LOGGER = LoggerFactory.getLogger(App.class);
public App() {
Map clothesProperties = new HashMap<>();
clothesProperties.put(HasSize.PROPERTY, "XXL");
clothesProperties.put(HasPrice.PROPERTY, "399元");
clothesProperties.put(HasColor.PROPERTY, "棕色带图案");
clothesProperties.put(HasType.PROPERTY, "男士上衣");
Map clothes1Properties = new HashMap<>();
clothes1Properties.put(HasSize.PROPERTY, "中号");
clothes1Properties.put(HasPrice.PROPERTY, "188元");
clothes1Properties.put(HasColor.PROPERTY, "黑色");
clothes1Properties.put(HasType.PROPERTY, "鸭舌帽");
Map 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();
}
}
执行结果
总结
所有的属性都通过Map存储。所以存储的时候不需要关心具体的类型是什么。
对象可以有子对象。比如,Costume有Hat,Clothes。Hat和Clothes都是子对象。通过Costume可以获得Hat和Clothes子对象,通过子对象设置和获取子对象的属性。
通过继承接口,实现获取类型相关的属性。Costume继承并实现接口HasSeason。如果想获得 Costume的season属性,需要调用getSeason().get()。从而实现取出的属性类型相关。
通过基类封装基本操作。这样不同Costume或者Costume和Hat、Clothes之间可以共享实现。