mirror of
https://github.com/tiennm99/java-design-patterns.git
synced 2026-05-16 18:59:21 +00:00
docs: update subclass sandbox
This commit is contained in:
+75
-22
@@ -1,26 +1,44 @@
|
||||
---
|
||||
---
|
||||
title: Subclass Sandbox
|
||||
category: Behavioral
|
||||
language: en
|
||||
tag:
|
||||
- Game programming
|
||||
---
|
||||
tag:
|
||||
- Abstraction
|
||||
- Code simplification
|
||||
- Decoupling
|
||||
- Extensibility
|
||||
- Game programming
|
||||
- Polymorphism
|
||||
---
|
||||
|
||||
## Intent
|
||||
The subclass sandbox pattern describes a basic idea, while not having a lot of detailed mechanics. You will need the pattern when you have several similar subclasses. If you have to make a tiny change, then change the base class, while all subclasses shouldn't have to be touched. So the base class has to be able to provide all of the operations a derived class needs to perform.
|
||||
## Also known as
|
||||
|
||||
* Hook Method
|
||||
|
||||
## Intent
|
||||
|
||||
To allow subclasses to alter the core behavior of a class by providing specific implementations of certain methods while keeping the overall structure unchanged.
|
||||
|
||||
## Explanation
|
||||
Real world example
|
||||
> Consider we want to create some superpower in the game, and they need to move accompanied by a sound effect and spawn particles. Create many classes that contain similar methods or need a base class to derivate them? The subclass-sandbox pattern allows you to deal with this problem in the second way.
|
||||
|
||||
Real-world example
|
||||
|
||||
> Imagine a cooking class where the instructor provides a standard recipe structure, including steps like "prepare ingredients," "cook," and "serve." Each student follows this structure but can customize specific steps to create their unique dish. For example, one student might choose to prepare a salad, while another might prepare a stir-fry, both adhering to the same overarching recipe format. This way, the instructor ensures that all dishes are made following a consistent process, but students have the flexibility to personalize the key parts of their recipes. This mirrors the Subclass Sandbox pattern, where the core structure is defined by the superclass, and specific behaviors are customized in subclasses.
|
||||
|
||||
In plain words
|
||||
> The subclass-sandbox is about moving the overlap methods in the subclasses to a base class which reduces the redundant rate in the classes.
|
||||
|
||||
Wikipedia says
|
||||
> The Subclass Sandbox pattern allows subclasses to customize specific behaviors within a predefined algorithm structure provided by the superclass.
|
||||
|
||||
[gameprogrammingpatterns.com](https://gameprogrammingpatterns.com/) says
|
||||
|
||||
> A base class defines an abstract sandbox method and several provided operations. Marking them protected makes it clear that they are for use by derived classes. Each derived sandboxed subclass implements the sandbox method using the provided operations.
|
||||
>
|
||||
**Programmatic Example**
|
||||
|
||||
**Programmatic Example**
|
||||
|
||||
Suppose you want to create various superpowers in a game, where each superpower needs to move with a sound effect and spawn particles. Should you create many classes with similar methods or derive them from a base class? The Subclass Sandbox pattern enables you to handle this efficiently by deriving these classes from a common base class.
|
||||
|
||||
We start with the base class `Superpower`. It contains an abstract sandbox method `active()` and some provided operations.
|
||||
|
||||
```
|
||||
public abstract class Superpower {
|
||||
|
||||
@@ -41,7 +59,9 @@ public abstract class Superpower {
|
||||
}
|
||||
}
|
||||
```
|
||||
Next we are able to create derived sandboxed subclass that implements the sandbox method using the provided operations. Here is the first power:
|
||||
|
||||
Next, we are able to create derived sandboxed subclass that implements the sandbox method using the provided operations. Here is the first power:
|
||||
|
||||
```
|
||||
public class SkyLaunch extends Superpower {
|
||||
|
||||
@@ -58,7 +78,9 @@ public class SkyLaunch extends Superpower {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here is the second power.
|
||||
|
||||
```
|
||||
public class GroundDive extends Superpower {
|
||||
|
||||
@@ -75,7 +97,9 @@ public class GroundDive extends Superpower {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Finally, here are the superpowers in active.
|
||||
|
||||
```
|
||||
LOGGER.info("Use superpower: sky launch");
|
||||
var skyLaunch = new SkyLaunch();
|
||||
@@ -84,7 +108,9 @@ Finally, here are the superpowers in active.
|
||||
var groundDive = new GroundDive();
|
||||
groundDive.activate();
|
||||
```
|
||||
|
||||
Program output:
|
||||
|
||||
```
|
||||
// Use superpower: sky launch
|
||||
// Move to ( 0.0, 0.0, 20.0 )
|
||||
@@ -95,17 +121,44 @@ Program output:
|
||||
// Play GROUNDDIVE_SOUND with volume 5
|
||||
// Spawn 20 particle with type GROUNDDIVE_PARTICLE
|
||||
```
|
||||
|
||||
## Class diagram
|
||||

|
||||
|
||||

|
||||
|
||||
## Applicability
|
||||
The Subclass Sandbox pattern is a very simple, common pattern lurking in lots of codebases, even outside of games. If you have a non-virtual protected method laying around, you’re probably already using something like this. Subclass Sandbox is a good fit when:
|
||||
|
||||
- You have a base class with a number of derived classes.
|
||||
- The base class is able to provide all of the operations that a derived class may need to perform.
|
||||
- There is behavioral overlap in the subclasses and you want to make it easier to share code between them.
|
||||
- You want to minimize coupling between those derived classes and the rest of the program.
|
||||
|
||||
* Use when you want to create a framework that allows users to define their own behaviors by extending classes.
|
||||
* Applicable in scenarios where you need to enforce a specific algorithm structure while allowing certain steps to be overridden.
|
||||
|
||||
## Known Uses
|
||||
|
||||
* Template method pattern in GUI frameworks where the framework provides the structure and the subclasses implement the specifics.
|
||||
* Game development where the core game loop is defined, but specific behaviors are provided by subclassing.
|
||||
* Java libraries like the `AbstractList` where core methods are defined and certain behaviors can be customized by extending classes.
|
||||
|
||||
## Consequences
|
||||
|
||||
Benefits:
|
||||
|
||||
* Encourages code reuse by allowing shared code in the superclass.
|
||||
* Simplifies the addition of new behaviors through subclassing.
|
||||
* Enhances code readability and maintainability by separating the algorithm's structure from specific implementations.
|
||||
|
||||
Trade-offs:
|
||||
|
||||
* Can lead to a large number of subclasses.
|
||||
* Requires careful design to ensure that the base class is flexible enough for various extensions.
|
||||
* Increases complexity in understanding the code flow due to multiple layers of inheritance.
|
||||
|
||||
## Related Patterns
|
||||
|
||||
* [Template Method](https://java-design-patterns.com/patterns/template-method/): Similar in enforcing a structure where certain steps can be overridden by subclasses.
|
||||
* [Strategy](https://java-design-patterns.com/patterns/strategy/): Both involve interchangeable behaviors, but Strategy pattern uses composition over inheritance.
|
||||
|
||||
## Credits
|
||||
|
||||
* [Game Programming Patterns - Subclass Sandbox](https://gameprogrammingpatterns.com/subclass-sandbox.html)
|
||||
|
||||
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI)
|
||||
* [Effective Java](https://amzn.to/4cGk2Jz)
|
||||
* [Game Programming Patterns](https://amzn.to/3K96fOn)
|
||||
* [Subclass Sandbox - Game Programming Patterns](https://gameprogrammingpatterns.com/subclass-sandbox.html)
|
||||
|
||||
@@ -31,7 +31,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* of detailed mechanics. You will need the pattern when you have several similar
|
||||
* subclasses. If you have to make a tiny change, then change the base class,
|
||||
* while all subclasses shouldn't have to be touched. So the base class has to be
|
||||
* able to provide all of the operations a derived class needs to perform.
|
||||
* able to provide all the operations a derived class needs to perform.
|
||||
*/
|
||||
@Slf4j
|
||||
public class App {
|
||||
|
||||
Reference in New Issue
Block a user