设计模式之抽象文档模式 _ JAVA


来自维基百科的介绍——抽象文档模式

面向对象的结构设计模式,用于在松散类型的键值存储中组织对象并使用类型化视图公开数据。该模式的目的是在强类型语言中实现组件之间的高度灵活性,其中可以动态地将新属性添加到对象树,而不会失去对类型安全的支持。该模式利用特征将类的不同属性分成不同的接口。“文档”的灵感来自面向文档的数据库。

抽象文档模式的适用性和特点

  • 需要动态添加新属性时而不影响组织结构,类属性变化频率较大

    设计模式之抽象文档模式 _ 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();
    }
}

总结

  1. 所有的属性都通过Map存储。所以存储的时候不需要关心具体的类型是什么。

  2. 对象可以有子对象。比如,Costume有Hat,Clothes。Hat和Clothes都是子对象。通过Costume可以获得Hat和Clothes子对象,通过子对象设置和获取子对象的属性。

  3. 通过继承接口,实现获取类型相关的属性。Costume继承并实现接口HasSeason。如果想获得 Costume的season属性,需要调用getSeason().get()。从而实现取出的属性类型相关。

  4. 通过基类封装基本操作。这样不同Costume或者Costume和Hat、Clothes之间可以共享实现。

发布于 2020-04-19 22:35:39
收藏
分享
海报
0 条评论
184
上一篇:StopWatch使用介绍 _ JAVA 下一篇:决定Java未来的三大主要项目! _ JAVA
目录

    0 条评论

    本站已关闭游客评论,请登录或者注册后再评论吧~

    忘记密码?

    图形验证码