docs: update abstract document

This commit is contained in:
Ilkka Seppälä
2024-05-24 07:26:08 +03:00
parent 8389456532
commit 6e123be3bd
+45 -37
View File
@@ -4,8 +4,11 @@ category: Structural
language: en
tag:
- Abstraction
- Extensibility
- Decoupling
- Dynamic typing
- Encapsulation
- Extensibility
- Polymorphism
---
## Intent
@@ -18,7 +21,7 @@ The Abstract Document pattern enables handling additional, non-static properties
Real world example
> Consider a car that consists of multiple parts. However, we don't know if the specific car really has all the parts, or just some of them. Our cars are dynamic and extremely flexible.
> Imagine a library system where books can have different formats and attributes: physical books, eBooks, and audiobooks. Each format has unique properties, such as page count for physical books, file size for eBooks, and duration for audiobooks. The Abstract Document design pattern allows the library system to manage these diverse formats flexibly. By using this pattern, the system can store and retrieve properties dynamically, without needing a rigid structure for each book type, making it easier to add new formats or attributes in the future without significant changes to the codebase.
In plain words
@@ -30,6 +33,8 @@ Wikipedia says
**Programmatic Example**
Consider a car that consists of multiple parts. However, we don't know if the specific car really has all the parts, or just some of them. Our cars are dynamic and extremely flexible.
Let's first define the base classes `Document` and `AbstractDocument`. They basically make the object hold a property map and any amount of child objects.
```java
@@ -127,47 +132,47 @@ public class Car extends AbstractDocument implements HasModel, HasPrice, HasPart
And finally here's how we construct and use the `Car` in a full example.
```java
LOGGER.info("Constructing parts and car");
LOGGER.info("Constructing parts and car");
var wheelProperties=Map.of(
Property.TYPE.toString(),"wheel",
Property.MODEL.toString(),"15C",
Property.PRICE.toString(),100L);
var wheelProperties = Map.of(
Property.TYPE.toString(), "wheel",
Property.MODEL.toString(), "15C",
Property.PRICE.toString(), 100L);
var doorProperties=Map.of(
Property.TYPE.toString(),"door",
Property.MODEL.toString(),"Lambo",
Property.PRICE.toString(),300L);
var doorProperties = Map.of(
Property.TYPE.toString(), "door",
Property.MODEL.toString(), "Lambo",
Property.PRICE.toString(), 300L);
var carProperties=Map.of(
Property.MODEL.toString(),"300SL",
Property.PRICE.toString(),10000L,
Property.PARTS.toString(),List.of(wheelProperties,doorProperties));
var carProperties = Map.of(
Property.MODEL.toString(), "300SL",
Property.PRICE.toString(), 10000L,
Property.PARTS.toString(), List.of(wheelProperties, doorProperties));
var car=new Car(carProperties);
var car = new Car(carProperties);
LOGGER.info("Here is our car:");
LOGGER.info("-> model: {}",car.getModel().orElseThrow());
LOGGER.info("-> price: {}",car.getPrice().orElseThrow());
LOGGER.info("-> parts: ");
car.getParts().forEach(p->LOGGER.info("\t{}/{}/{}",
p.getType().orElse(null),
p.getModel().orElse(null),
p.getPrice().orElse(null))
);
LOGGER.info("Here is our car:");
LOGGER.info("-> model: {}", car.getModel().orElseThrow());
LOGGER.info("-> price: {}", car.getPrice().orElseThrow());
LOGGER.info("-> parts: ");
car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}", p.getType().orElse(null), p.getModel().orElse(null), p.getPrice().orElse(null)));
```
// Constructing parts and car
// Here is our car:
// model: 300SL
// price: 10000
// parts:
// wheel/15C/100
// door/Lambo/300
The program output:
```
07:21:57.391 [main] INFO com.iluwatar.abstractdocument.App -- Constructing parts and car
07:21:57.393 [main] INFO com.iluwatar.abstractdocument.App -- Here is our car:
07:21:57.393 [main] INFO com.iluwatar.abstractdocument.App -- -> model: 300SL
07:21:57.394 [main] INFO com.iluwatar.abstractdocument.App -- -> price: 10000
07:21:57.394 [main] INFO com.iluwatar.abstractdocument.App -- -> parts:
07:21:57.395 [main] INFO com.iluwatar.abstractdocument.App -- wheel/15C/100
07:21:57.395 [main] INFO com.iluwatar.abstractdocument.App -- door/Lambo/300
```
## Class diagram
![alt text](./etc/abstract-document.png "Abstract Document Traits and Domain")
![Abstract Document](./etc/abstract-document.png "Abstract Document Traits and Domain")
## Applicability
@@ -199,7 +204,7 @@ The key idea behind the Abstract Document design pattern is to provide a flexibl
## Consequences
Benefits
Benefits:
* Flexibility: Accommodates varied document structures and properties.
@@ -209,7 +214,7 @@ Benefits
* Reusability: Typed views enable code reuse for accessing specific attribute types.
Trade-offs
Trade-offs:
* Complexity: Requires defining interfaces and views, adding implementation overhead.
@@ -217,6 +222,9 @@ Trade-offs
## Credits
* [Wikipedia: Abstract Document Pattern](https://en.wikipedia.org/wiki/Abstract_Document_Pattern)
* [Martin Fowler: Dealing with properties](http://martinfowler.com/apsupp/properties.pdf)
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI)
* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3yhh525)
* [Pattern-Oriented Software Architecture Volume 4: A Pattern Language for Distributed Computing (v. 4)](https://amzn.to/49zRP4R)
* [Patterns of Enterprise Application Architecture](https://amzn.to/3WfKBPR)
* [Abstract Document Pattern (Wikipedia)](https://en.wikipedia.org/wiki/Abstract_Document_Pattern)
* [Dealing with Properties (Martin Fowler)](http://martinfowler.com/apsupp/properties.pdf)