From 42db186033d6035c9efc68f63616a55d0b80f82e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilkka=20Sepp=C3=A4l=C3=A4?= Date: Sun, 26 May 2024 15:38:04 +0300 Subject: [PATCH] docs: update null object --- null-object/README.md | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/null-object/README.md b/null-object/README.md index 0f6913fab..7dd31477f 100644 --- a/null-object/README.md +++ b/null-object/README.md @@ -19,9 +19,11 @@ To provide a default behavior for an object, avoiding the need for null checks a ## Explanation -Real world example +Real-world example -> We are building a binary tree from nodes. There are ordinary nodes and "empty" nodes. Traversing the tree normally should not cause errors, so we use null object pattern where necessary. +> A real-world analogy for the Null Object pattern can be found in the context of customer service. Imagine a customer service system where there are different types of support representatives: human agents and automated bots. When a customer request is received, the system can assign it to a human agent or, if no agents are available, to an automated bot. If neither human agents nor automated bots are available, the system assigns the request to a "Null Representative." +> +> The Null Representative is a placeholder that does nothing but ensures that the system doesn't crash or raise errors due to the absence of a support representative. It provides default responses like "Your request is being processed" without any actual processing, thereby maintaining system stability and avoiding the need for null checks throughout the codebase. In plain words @@ -33,6 +35,8 @@ Wikipedia says **Programmatic Example** +We are building a binary tree from nodes. There are ordinary nodes and "empty" nodes. Traversing the tree normally should not cause errors, so we use null object pattern where necessary. + Here's the definition of `Node` interface. ```java @@ -60,9 +64,6 @@ public class NodeImpl implements Node { private final Node left; private final Node right; - /** - * Constructor. - */ public NodeImpl(String name, Node left, Node right) { this.name = name; this.left = left; @@ -142,17 +143,9 @@ public final class NullNode implements Node { Then we can construct and traverse the binary tree without errors as follows. ```java - var root = new NodeImpl("1", - new NodeImpl("11", - new NodeImpl("111", NullNode.getInstance(), NullNode.getInstance()), - NullNode.getInstance() - ), - new NodeImpl("12", - NullNode.getInstance(), - new NodeImpl("122", NullNode.getInstance(), NullNode.getInstance()) - ) - ); - root.walk(); +var root = new NodeImpl("1", new NodeImpl("11", new NodeImpl("111", NullNode.getInstance(), NullNode.getInstance()), NullNode.getInstance()), + new NodeImpl("12", NullNode.getInstance(), new NodeImpl("122", NullNode.getInstance(), NullNode.getInstance()))); +root.walk(); ``` Program output: @@ -165,10 +158,6 @@ Program output: 122 ``` -## Class diagram - -![Null Object](./etc/null-object.png "Null Object") - ## Applicability * When you need to provide a default behavior in place of a null object. @@ -202,8 +191,8 @@ Trade-offs: ## Credits -* [Pattern Languages of Program Design 3](https://www.amazon.com/gp/product/0201310112/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201310112&linkCode=as2&tag=javadesignpat-20&linkId=7372ffb8a4e39a3bb10f199b89aef921) -* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7) * [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI) * [Effective Java](https://amzn.to/4cGk2Jz) +* [Pattern Languages of Program Design 3](https://amzn.to/3UZkRF6) +* [Refactoring to Patterns](https://amzn.to/3VOO4F5) * [Refactoring: Improving the Design of Existing Code](https://amzn.to/3UJ7etA)