From 6e123be3bddcb2d8e653977da78f538c48ab1e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Fri, 24 May 2024 07:26:08 +0300 Subject: [PATCH] docs: update abstract document --- abstract-document/README.md | 82 ++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/abstract-document/README.md b/abstract-document/README.md index 9e97f33c4..e5bb1889f 100644 --- a/abstract-document/README.md +++ b/abstract-document/README.md @@ -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)