设计模式之抽象文档模式

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; }@Overridepublic Object get(String key) {return properties.get(key); }
@Overridepublic void put(String key, Object value) { properties.put(key, value); }
@Overridepublic <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之间可以共享实现。

以上是关于设计模式之抽象文档模式的主要内容,如果未能解决你的问题,请参考以下文章

23中设计模式之抽象工厂模式

设计模式之工厂方法和抽象工厂

设计模式之抽象工厂模式

创建型模式之抽象工厂模式实例及代码操作

设计模式之接口型模式

设计模式探秘之抽象工厂模式