Software Design Patterns
It's harder to read code than to write it. - Joel Spolsky
// Single thread implementation
public class SimpleSingleton
{
private static SimpleSingleton instance;
//private constructor to not allow external initialization
private SimpleSingleton() { }
//static method to intialize class without creating class instance
public static SimpleSingleton Instance
{
get
{
if (instance == null)
{
instance = new SimpleSingleton();
}
return instance;
}
}
} Singleton
one-instance, global-access, creation on demand, runtime-initialization, supports inheritance
if wrongly used as "helper" class = decrease-readability, promotes-coupling
concurrency-unfriendly, can not know when initialization will happen
Alternative = Pass instance, Store instance in base class, global class, Service Locator
// Flyweight interface
interface Shape {
void draw(int x, int y);
}
// Concrete Flyweight
class Circle implements Shape {
private String color; // *Intrinsic state*
public Circle(String color) {
this.color = color;
}
@Override
public void draw(int x, int y) {
System.out.println( color +
" x,y = " + x + "," + y;
}
} Flyweight
efficiently-reuse-objects , share large numbers of similar objects, save memory.
splits the state into intrinsic (shared) and extrinsic (unique) parts
Game Development, Networking Applications, Text Editors
Interface → Implementation stores intrinsic state ← Factory ← Client stores extrinsic state
Empty ScriptableObject for Enum like comparison! Easier to extend.
[CreateAssetMenu(fileName='GameItem')]
public class GameItem : ScriptableObject
{ // Every GameItem can now be used as Enum GameItemType
//Lets extend it with some business logic
public GameItem weakness;
public bool IsWinner(GameItem other)
{
return other.weakness == this;
}
} Scriptable Objects
Unity, data containers for shared data, static game configuration data, "read-only" persistent data.
First-class objects, reduce memory usage, assign to variable, pass as argument, method return, data type in data structures, serialiable, dynamic creation/destruction at runtime.
Can change values at runtime but maintains new values after execution termination.
Supports Unity events Awake, OnEnable, OnDestroy, OnDisable, OnValidate and Reset .
Inventories. Enemy, player, or item statistics. Audio collections
data containers = data that does not need to change at runtime
To avoid tampering = Encryption. Digital signatures (fingerprint algorithm to verify). Server-side validation (Authority rejects anything manipulated)
Finite State Machine
one state at any moment in time , finite number of states, decompose an object's behavior into 'chunks' or states.
-
Two core operations
- ChangeState = can operate on input to make transitions from one state to another
- Execute = to cause an output or action to take place.
- state transition table =
Conditions and the states those conditions
lead to.
- Embed the rules for the state transitions within the states themselves.
- Provides an elegant way of implementing state-driven behavior.
- Add enter and exit actions to each state; and call them via the agent's ChangeState method.
+-----------+ +--------------+
|Interface |-->|Magic Ability|
+-----+-----+ +------+-------+
|
|
| +-----+------+ +-------------+
+--------->+ Ability +------>|Fire Damage |
| Decorator | |Decorator |
+------------+ +-------+----+
|
| +---------------+
+---------->|Heal Decorator |
+-------+-------+
+-----------+ +----------------+
|Controller |--->|Ability Definition|
+-----+-----+ +--------+-------+
|
| +--------------+
+--------->|Ability Factory|
+------+-------+
Decorator
Wrapper pattern, Wrap around objects, add behaviour to **individual objects** without affecting the behaviour of other objects of same class.
Different characters - with same base spells - but merge with different spells.
Controller = Object creation using factory, Call Manager, Cast Spell
Manager = Singleton = Merge two abilities
Command Pattern
Action Pattern, method call &=rarr a stand-alone object.
Everything needed to execute that command is available to the class
Instead of directly calling a method to perform an action, you create a command object that holds all the information needed to execute that action.
Entity-Component System
ECS, Components are pure classes, almost entirely for data.
MVC
decouples views and models. multiple views to attach to a model.
Nestable, Utilizes Observer and Composite patterns
Controller class = implement response statergy = [Statergy Pattern](#statergy)
Factory Method = specify controller class
Decorator = add scrolling to view
Broker Chain Pattern
// data class
class BaseStats {
int damage;
int heal;
}
enum StatType {Damage, Heal}
class Stats {
readonly BaseStats baseStats;
int Damage { get {}} //modifier
int Heal { get {} } //modifier
}
class StatsMediator {
// Keep in memory because it is meant to access frequently
readonly LinkedList<StatModifier> modifiers = new ();
event EventHandler<Query> Queries;
void PerformQuery(object sender, Query query) => Queries?.Invoke(sender, query);
public void AddModifier(StatModifier modifier) {
modifiers.AddLast(modifier);
}
}
class Query {
readonly StatType StatType;
int Value;
Query(StatType statType, int value) {
StatType = statType;
Valye = value;
}
}
abstract class StatModifier {}