docs: update type object

This commit is contained in:
Ilkka Seppälä
2024-05-22 19:17:57 +03:00
parent e87b18edf3
commit 84df9ad48a
16 changed files with 227 additions and 212 deletions
+1 -1
View File
@@ -166,7 +166,7 @@
<module>spatial-partition</module>
<module>priority-queue</module>
<module>commander</module>
<module>typeobjectpattern</module>
<module>type-object</module>
<module>bytecode</module>
<module>leader-election</module>
<module>data-locality</module>
+222
View File
@@ -0,0 +1,222 @@
---
title: Type Object
category: Creational
language: en
tag:
- Abstraction
- Code simplification
- Data processing
- Game programming
- Extensibility
- Instantiation
- Object composition
- Polymorphism
---
## Also known as
* Type Descriptor
* Type Safe Enumeration
## Intent
Allow creation of flexible and extensible sets of related types.
## Explanation
Real-world example
> An analogous real-world example of the Type Object pattern can be seen in a role-playing game (RPG) character customization system. In such a game, players can choose from various character classes like Warrior, Mage, and Archer, each with its unique set of abilities and attributes. The Type Object pattern allows the game to define these character classes and their behaviors dynamically. Instead of hardcoding the details of each class, the game uses a flexible system where new character types can be added or existing ones modified without changing the underlying game logic. This extensibility lets the developers introduce new character classes through updates or expansions, keeping the game fresh and engaging for players.
In plain words
> The Type Object pattern allows for the creation and management of flexible and extensible sets of related types dynamically, without modifying existing code.
Gameprogrammingpatterns.com says
> Define a type object class and a typed object class. Each type object instance represents a different logical type. Each typed object stores a reference to the type object that describes its type.
**Programmatic example**
The Type Object pattern is a design pattern that allows for the creation of flexible and reusable objects by creating a class with a field that represents the 'type' of the object. This pattern is useful when the types needed are not known upfront, or when there is a need to modify or add new types conveniently without recompiling repeatedly.
In the provided code, the Type Object pattern is implemented in a mini candy-crush game. The game has many different candies, which may change over time as the game is upgraded.
Let's break down the key components of this implementation:
1. **Candy Class**: This class represents the 'type' object in this pattern. Each candy has a name, parent, points, and type. The type is an enum that can be either `CRUSHABLE_CANDY` or `REWARD_FRUIT`.
```java
class Candy {
String name;
Candy parent;
String parentName;
int points;
Type type;
Candy(String name, String parentName, Type type, int points) {
// constructor implementation
}
int getPoints() {
// implementation
}
Type getType() {
// implementation
}
void setPoints(int a) {
// implementation
}
}
```
2. **JsonParser Class**: This class is responsible for parsing the JSON file that contains the details about the candies. It creates a `Candy` object for each candy in the JSON file and stores them in a `Hashtable`.
```java
public class JsonParser {
Hashtable<String, Candy> candies;
JsonParser() {
this.candies = new Hashtable<>();
}
void parse() throws JsonParseException {
// implementation
}
void setParentAndPoints() {
// implementation
}
}
```
3. **Cell Class**: This class represents a cell in the game matrix. Each cell contains a candy that can be crushed. It also contains information on how crushing can be done, how the matrix is to be reconfigured, and how points are to be gained.
```java
class Cell {
Candy candy;
int positionX;
int positionY;
Cell() {
// implementation
}
Cell(Candy candy, int positionX, int positionY) {
// implementation
}
void crush(CellPool pool, Cell[][] cellMatrix) {
// implementation
}
// other methods...
}
```
4. **CandyGame Class**: This class contains the rules for the continuation of the game.
```java
class CandyGame {
Cell[][] cells;
CellPool pool;
int totalPoints;
CandyGame(int num, CellPool pool) {
// implementation
}
boolean continueRound() {
// implementation
}
// other methods...
}
```
5. **CellPool Class**: This class is a pool that reuses the candy cells that have been crushed instead of creating new ones repeatedly.
```java
class CellPool {
int pointer;
List<Cell> pool;
Candy[] randomCode;
CellPool(int num) {
// implementation
}
void addNewCell(Cell c) {
// implementation
}
Candy[] assignRandomCandytypes() {
// implementation
}
Cell getNewCell() {
// implementation
}
}
```
6. **App Class**: This class contains the main method that starts the game.
```java
@Slf4j
public class App {
public static void main(String[] args) {
// implementation
}
}
```
In this implementation, the Type Object pattern allows for the flexible creation of `Candy` objects. The type of each candy is determined at runtime by parsing a JSON file, which makes it easy to add, modify, or remove candy types without having to recompile the code.
## Class diagram
![Type Object](./etc/typeobjectpattern.urm.png "Type Object")
## Applicability
This pattern can be used when:
* Use when you need to create an extensible set of related classes without modifying existing code.
* Ideal for scenarios where types and their behaviors need to be defined at runtime or in a flexible manner.
* Suitable for situations where the number of types is large and may change over time.
* The difference between the different 'types' of objects is the data, not the behaviour.
## Known uses
* Java Collections Framework: Utilizing various collection types like List, Set, and Map.
* Graphics Libraries: Defining different shapes with specific properties and behaviors.
* Game Development: Creating different types of characters or items with unique attributes and behaviors.
## Consequences
Benefits:
* Increases flexibility and extensibility of the code.
* Simplifies the addition of new types without modifying existing code.
* Enhances code readability by organizing related behaviors and properties.
Trade-offs:
* Can increase complexity if not managed properly.
* May lead to performance overhead due to dynamic type checking and handling.
## Related patterns
* [Factory Method](https://java-design-patterns.com/patterns/factory-method/): Often used in conjunction with Type Object to create instances of the types.
* [Strategy](https://java-design-patterns.com/patterns/strategy/): Similar in that it defines a family of algorithms or behaviors, but focuses more on interchangeable behaviors.
* [Prototype](https://java-design-patterns.com/patterns/prototype/): Can be used to create new instances by copying existing ones, supporting dynamic and flexible type creation.
## Credits
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://amzn.to/3w0pvKI)
* [Effective Java](https://amzn.to/4cGk2Jz)
* [Java Design Patterns: A Hands-On Experience with Real-World Examples](https://amzn.to/3yhh525)
* [Game Programming Patterns - Type Object](http://gameprogrammingpatterns.com/type-object.html)
* [Types as Objects Pattern - Jon Pearce](http://www.cs.sjsu.edu/~pearce/modules/patterns/analysis/top.htm)

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

@@ -32,7 +32,7 @@
<artifactId>java-design-patterns</artifactId>
<version>1.26.0-SNAPSHOT</version>
</parent>
<artifactId>typeobjectpattern</artifactId>
<artifactId>type-object</artifactId>
<dependencies>
<dependency>
<groupId>com.google.code.gson</groupId>
@@ -29,13 +29,14 @@ import com.iluwatar.typeobject.Candy.Type;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
/**
* The CellPool class allows the reuse of crushed cells instead of creation of new cells each time.
* The reused cell is given a new candy to hold using the randomCode field which holds all the
* candies available.
*/
@Slf4j
public class CellPool {
private static final SecureRandom RANDOM = new SecureRandom();
public static final String FRUIT = "fruit";
@@ -49,7 +50,7 @@ public class CellPool {
try {
this.randomCode = assignRandomCandytypes();
} catch (Exception e) {
e.printStackTrace();
LOGGER.error("Error occurred: ", e);
//manually initialising this.randomCode
this.randomCode = new Candy[5];
randomCode[0] = new Candy("cherry", FRUIT, Type.REWARD_FRUIT, 20);
-208
View File
@@ -1,208 +0,0 @@
---
title: Type-Object
category: Behavioral
language: en
tag:
- Game programming
- Extensibility
---
## Intent
As explained in the book Game Programming Patterns by Robert Nystrom, type object pattern helps in
> Allowing flexible creation of new “classes” by creating a single class, each instance of which represents a different type of object
## Explanation
Real-world example
> You are working on a game with many different breeds of monsters. Each monster breed has different values for the attributes, such as attack, health, intelligence, etc. You want to create new monster breeds, or modify the attributes of an existing breed, without needing to modify the code and recompiling the game.
In plain words
> Define a type object class, and a typed object class. We give each type object instance a reference to a typed object, containing the information for that type.
**Programmatic example**
Suppose we are developing a game of Candy Crush. There are many different candy types, and we may want to edit or create new ones over time as we develop the game.
First, we have a type for the candies, with a field name, parent, points and Type.
```java
@Getter(AccessLevel.PACKAGE)
public class Candy {
enum Type {
CRUSHABLE_CANDY,
REWARD_FRUIT
}
String name;
Candy parent;
String parentName;
@Setter
private int points;
private final Type type;
Candy(String name, String parentName, Type type, int points) {
this.name = name;
this.parent = null;
this.type = type;
this.points = points;
this.parentName = parentName;
}
}
```
The field data for candy types are stored in the JSON file ```candy.json```. New candies can be added just by appending it to this file.
```json
{"candies" : [
{
"name" : "fruit",
"parent" : "null",
"type" : "rewardFruit",
"points" : 20
},
{
"name" : "candy",
"parent" : "null",
"type" : "crushableCandy",
"points" : 10
},
{
"name" : "cherry",
"parent" : "fruit",
"type" : "rewardFruit",
"points" : 0
},
{
"name" : "mango",
"parent" : "fruit",
"type" : "rewardFruit",
"points" : 0
},
{
"name" : "purple popsicle",
"parent" : "candy",
"type" : "crushableCandy",
"points" : 0
},
{
"name" : "green jellybean",
"parent" : "candy",
"type" : "crushableCandy",
"points" : 0
},
{
"name" : "orange gum",
"parent" : "candy",
"type" : "crushableCandy",
"points" : 0
}
]
}
```
The JSON file is parsed, instanciating each Candy type, and storing it in a hashtable. The ```type``` field is matched with the ```Type``` enum defined in the Candy class.
```java
public class JsonParser {
Hashtable<String, Candy> candies;
JsonParser() {
this.candies = new Hashtable<>();
}
void parse() throws JsonParseException {
var is = this.getClass().getClassLoader().getResourceAsStream("candy.json");
var reader = new InputStreamReader(is);
var json = (JsonObject) com.google.gson.JsonParser.parseReader(reader);
var array = (JsonArray) json.get("candies");
for (var item : array) {
var candy = (JsonObject) item;
var name = candy.get("name").getAsString();
var parentName = candy.get("parent").getAsString();
var t = candy.get("type").getAsString();
var type = Type.CRUSHABLE_CANDY;
if (t.equals("rewardFruit")) {
type = Type.REWARD_FRUIT;
}
var points = candy.get("points").getAsInt();
var c = new Candy(name, parentName, type, points);
this.candies.put(name, c);
}
setParentAndPoints();
}
void setParentAndPoints() {
for (var e = this.candies.keys(); e.hasMoreElements(); ) {
var c = this.candies.get(e.nextElement());
if (c.parentName == null) {
c.parent = null;
} else {
c.parent = this.candies.get(c.parentName);
}
if (c.getPoints() == 0 && c.parent != null) {
c.setPoints(c.parent.getPoints());
}
}
}
}
```
## In Plain Words
The Type-Object pattern in Java is a method to encapsulate type-specific properties and behaviors within an object. This design pattern facilitates the addition of new types without necessitating changes to existing code, thereby enhancing codebase expansion and maintenance.
## Wikipedia Says
While there isn't a specific Wikipedia entry for the Type-Object pattern, it is a commonly used technique in object-oriented programming. This pattern assists in managing objects that share similar characteristics but have different values for those characteristics. It finds widespread use in game development, where numerous types of objects (like enemies) share common behavior but have different properties.
## Programmatic Example
Consider an example involving different types of enemies in a game. Each enemy type has distinct properties like speed, health, and damage.
```java
public class EnemyType {
private String name;
private int speed;
private int health;
private int damage;
public EnemyType(String name, int speed, int health, int damage) {
this.name = name;
this.speed = speed;
this.health = health;
this.damage = damage;
}
// getters and setters
}
public class Enemy {
private EnemyType type;
// Encapsulating type information in an object
public Enemy(EnemyType type) {
this.type = type;
}
// other methods
}
```
In the above example, `EnemyType` encapsulates type-specific properties (name, speed, health, damage), and `Enemy` uses an instance of `EnemyType` to define its type. This way, you can add as many enemy types as you want without modifying the `Enemy` class.
## Applicability
This pattern can be used when:
* We dont know what types we will need up front.
* We want to be able to modify or add new types without having to recompile or change code.
* Only difference between the different 'types' of objects is the data, not the behaviour.
## Another example with class diagram
![alt text](./etc/typeobjectpattern.urm.png "Type-Object pattern class diagram")
## Credits
* [Game Programming Patterns - Type Object](http://gameprogrammingpatterns.com/type-object.html)
* [Types as Objects Pattern](http://www.cs.sjsu.edu/~pearce/modules/patterns/analysis/top.htm)