53 lines
2.7 KiB
Markdown
53 lines
2.7 KiB
Markdown
|
---
|
||
|
obj: concept
|
||
|
---
|
||
|
# Null Object Pattern
|
||
|
|
||
|
## **Description:**
|
||
|
The Null Object Pattern is a behavioral design pattern that provides an object as a surrogate for the lack of an object of a given type. It allows you to handle the absence of an object gracefully without explicit null checks, improving code readability and robustness. The null object typically provides default behavior or no-op implementations for the methods of the original object.
|
||
|
|
||
|
**How it's Used:**
|
||
|
1. **Interface or Abstract Class**: Define an interface or abstract class that represents the common behavior of the objects in question.
|
||
|
2. **Concrete Implementations**: Create concrete implementations of the interface or abstract class for real objects that provide meaningful functionality.
|
||
|
3. **Null Object**: Create a special null object class that also implements the interface or extends the abstract class. This null object should provide default or no-op implementations for the methods.
|
||
|
4. **Client Code**: In client code, use the null object when you expect an object of the interface type but want to gracefully handle the case when no real object is available.
|
||
|
|
||
|
## **Example:**
|
||
|
Let's create an example of the Null Object Pattern in [Python](../../languages/Python.md) for handling logging. We'll define an interface for a logger, create real logger and null logger implementations, and demonstrate their use.
|
||
|
|
||
|
```python
|
||
|
from abc import ABC, abstractmethod
|
||
|
|
||
|
# Step 1: Define an interface for the logger
|
||
|
class Logger(ABC):
|
||
|
@abstractmethod
|
||
|
def log(self, message):
|
||
|
pass
|
||
|
|
||
|
# Step 2: Create a real logger implementation
|
||
|
class ConsoleLogger(Logger):
|
||
|
def log(self, message):
|
||
|
print(f"Console Log: {message}")
|
||
|
|
||
|
# Step 3: Create a null logger implementation
|
||
|
class NullLogger(Logger):
|
||
|
def log(self, message):
|
||
|
pass
|
||
|
|
||
|
# Step 4: Client code
|
||
|
def main():
|
||
|
# Real logger
|
||
|
logger = ConsoleLogger()
|
||
|
logger.log("This is a real log message.")
|
||
|
|
||
|
# Null logger
|
||
|
null_logger = NullLogger()
|
||
|
null_logger.log("This will not be logged.")
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|
||
|
```
|
||
|
|
||
|
In this [Python](../../languages/Python.md) example, we define a `Logger` interface (Step 1) and create a real logger implementation (`ConsoleLogger`) that prints log messages to the console (Step 2). We also create a null logger implementation (`NullLogger`) that does nothing when `log` is called (Step 3).
|
||
|
|
||
|
In the `main` function (Step 4), we demonstrate using both the real logger and the null logger. When you use the null logger, you can safely handle the case where logging is not required without explicit null checks. This pattern is particularly useful when you want to avoid conditional statements throughout your code for handling null cases.
|