请输入您要查询的百科知识:

 

词条 Abstract Document Pattern
释义

  1. Definition

  2. Structure

      Pseudocode  

  3. Usage

  4. Example implementation

  5. References

{{Multiple issues|{{Orphan|date=June 2016}}{{One source|date=January 2016}}
}}

An object-oriented structural design pattern for organizing objects in loosely typed key-value stores and exposing the data using typed views. The purpose of the pattern is to achieve a high degree of flexibility between components in a strongly typed language where new properties can be added to the object-tree on the fly, without losing the support of type-safety. The pattern makes use of traits to separate different properties of a class into different interfaces.[1] The term "document" is inspired from document-oriented databases.

Definition

A document is an object that contains a number of properties. A property can for an example be a value like a number or a string, or it can be a list of other documents. Every property is referenced using a key.[2] When traversing the document tree, the user specifies a constructor to be used for creating the implementation class of the next level. The implementations are often a union of various traits that extend the Document interface, making it possible for them to handle setting and getting properties on their own.

Structure

The interface "Document" states that properties can be edited using the "put" method, read using the "get" method and sub-documents can be traversed using the "children" method. The "children" method requires a functional reference to a method that can produce a typed view of a child given a map of the data the child should have. The map should be a pointer to the original map so that changes in the view also affect the original document.

Implementations can inherit from multiple trait interfaces that describe different properties. Multiple implementations can even share the same map, the only restriction the pattern puts on the design of the implementation is that it must be stateless except for the properties inherited from "BaseDocument".

Pseudocode

  '''interface''' Document    put(key : String, value : Object) : Object    get(key : String) : Object    children(key : String, constructor : Map -> T) : T[]      '''abstract''' '''class''' BaseDocument : Document    properties : Map        '''constructor'''(properties : Map)        this->properties := properties            '''implement''' put(key : String, value : Object) : Object        '''return''' this->properties->put(key, value)            '''implement''' get(key : String) : Object        '''return''' this->properties->get(key)            '''implement''' children(key : String, constructor : Map -> T) : T[]        '''var''' result := '''new''' T[]                '''var''' children := this->properties->get(key) '''castTo''' Map[]        '''foreach''' ( child '''in''' children )            result[] := constructor->apply(child)                    '''return''' result

Usage

The Abstract Document Pattern allows the developer to store variables like configuration settings in an untyped tree structure and operate on the documents using typed views. New views or alternative implementations of views can be created without affecting the internal document structure. The advantage of this is a more loosely coupled system, but it also increases the risk of casting errors as the inherit type of a property is not always certain.

Example implementation

Document.java

public interface Document {

    Object put(String key, Object value);    Object get(String key);

Stream children(

            String key,            Function, T> constructor    );

}

BaseDocument.java

public abstract class BaseDocument implements Document {

    private final Map entries;    protected BaseDocument(Map entries) {        this.entries = requireNonNull(entries);    }    @Override    public final Object put(String key, Object value) {        return entries.put(key, value);    }    @Override    public final Object get(String key) {        return entries.get(key);    }    @Override    public final  Stream children(            String key,            Function, T> constructor) {        final List> children =             (List>) get(key);        return children == null                    ? Stream.empty()                    : children.stream().map(constructor);    }

}

Usage.java

Map source = ...;

Car car = new Car(source);

String model = car.getModel();

int price = car.getPrice();

List wheels = car.children("wheel", Wheel::new)

References

1. ^{{cite web|last=Forslund |first=Emil |url=https://ageofjava.blogspot.com/2016/01/the-best-of-both-worlds.html |title=Age of Java: The Best of Both Worlds |website=Ageofjava.blogspot.com |date=2016-01-15 |accessdate=2016-01-23}}
2. ^{{Cite web|url = http://martinfowler.com/apsupp/properties.pdf|title = Dealing with Properties|date = |access-date = 2016-01-29|website = |publisher = |last = Fowler|first = Martin}}

1 : Software design patterns

随便看

 

开放百科全书收录14589846条英语、德语、日语等多语种百科知识,基本涵盖了大多数领域的百科知识,是一部内容自由、开放的电子版国际百科全书。

 

Copyright © 2023 OENC.NET All Rights Reserved
京ICP备2021023879号 更新时间:2024/11/14 3:58:06