-
OOP Design Pattern - Creational Pattern프로그래밍 언어 2024. 1. 12. 17:49
Abstract Factory
Abstract Factory Pattern
- An interface for creating families of related or dependent objects without specifying their concrete classes
- Provides way to create families of related objects without imposing their concrete classes
- Encapsulating a group of individual factories that have a common theme without specifying their concrete classes
- The client does not know which concrete objects it receives from each of factories, because of using only the generic interfaces of their product
Overview
- Solves problem like:
- How can an application be independent of how its objects are created?
- How can a class be independent of how the objects that it requires are created?
- How can faimilies of related or dependent objects be created?
- Describes how to solve such problems:
- Encapsulate object creation in a separate (factory) object by defining and implementing an interface for creating objects
- Delegate object creation to a factory object instead of creating objects directly
Caution to use pattern
- May result in unnecessary complexity and extra work in the initial writing of code
- Higher levels of seperation and abstraction can result in systems that are more difficult to debug and maintain
Implements
- Create a concrete implementation of the abstract factory
- Uses the generic interface of the factory to create the concrete objects that are part of the family
Example
using System.Collections; using System.Collections.Generic; using UnityEngine; public abstract class AbsBossFactory { public Boss CreateBoss() { Boss t_boss = new Boss(){ monster = CreateMonster(), weapon = CreateWeapon() }; return t_boss; } public abstract Monster CreateMonster(); public abstract Weapon CreateWeapon(); } public class BossFactory1 : AbsBossFactory { public override Monster CreateMonster() { Monster t_mosnter = new Goblin(); return t_monster; } public override Weapon CreateWeapon() { Weapon t_weapon = new Sword(); return t_weapon; } } public class BossSpawner : Monobehaviour { private void Start() { AbsBossFactory t_bossFactory = new BossFactory1(); Boss t_boss = t_bossFactory.CreateBoss(); } }
Builder
Builder Pattern
- Provide a flexible solution to various object creation problems in OOP
- Separate the contruction of a complex object from its representation
- The same construction process can create different representations
Overview
- Solves problem like:
- How can a class (the same construction process) create different representations of a complex object?
- How can a class that includes creating a complex object be simplified?
- Describes how to solve such problems:
- Encapsulate creating and assembling the parts of a complex object in a separate Builder object
- A class delegates object creation to a Builder object instead of creating the objects directly
Caution to use pattern
- Benefits
- Allow to vary a product's internal representation
- Encapsulate code for construction and representation
- Provide control over steps of contruction process
- Drawbacks
- A distinct concrete builder must be created for each type of product
- Builder classes must be mutable
- May hamper / complicate dependency injection
Example
public class Bicycle // Represents a product created by the builder { public string make; public string model; public int height; public string colour; public Bicycle(string p_make, string p_model, int p_height, string p_colour) { make = p_make; model = p_model; height = p_height; colour = p_colour; } } public interface IBicycleBuilder // The builder abstraction { int height; string colour; Bicycle GetResult(); } public class GTBuilder : IBicycleBuilder // Concrete builder implementation { public int height; public string colour; public Bicycle GetResult() { return height == 29 ? new Bicycle("GT", "Avalanche", height, colour) : null; } } public class MountainBikeBuildDirector // director { private IBicycleBuilder builder; public MountainBikeBuildDirector(IBicycleBuilder p_builder) { builder = p_builder; } public void Construct() { builder.height = 29; builder.colour = "Red"; } public Bicycle GetResult() { return this.builder.GetResult(); } } public class Client { public void DoSomethingWithBicycles() { var t_director = new MountainBikeBuildDirector(new GTBuilder()); Bicycle t_bike = t_director.Construct().GetResult(); } }
Factory Method
Factory Method Pattern
- Define an interface for creating an object, but let subclasses decide which class to instantiate
- Uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object will be created
- Calls a factory method:
- Specified in an interface
- Implemented by child classes
- Implemented in a base class and optionally overriden by derived classes
Overview
- Solves problem like:
- How can an object be created so that subclasses can redefine which class to instantiate?
- How can a class defer instantiation to subclasses?
- Describes how to solve such problems:
- Define a separate operation (factory method) for creating an object
- Create an object by calling a factory method, not using a constructor
Caution to use pattern
- May result in unnecessary complexity and extra work in the initial writing of code
- Higher levels of seperation and abstraction can result in systems that are more difficult to debug and maintain
Example
using System.Collections; using System.Collections.Generic; using UnityEngine; public abstract class AbsMonsterFactory { public abstract Monster CreateMonster(int p_type); } public enum EGoblin { NONE = -1, RED, GREEN } public class GoblinFactory : AbsMonsterFactory { public RedGoblin redGoblin; public GreenGoblin greenGoblin; public override Monster CreateMonster(int p_type) { Monster t_monster = null; if(p_type.Equals((int)EGoblin.RED)) t_monster = Instantiate(redGoblin); else if(p_type.Equals((int)EGoblin.GREEN)) t_monster = Instantiate(greenGoblin); return t_monster; } } public class MonsterSpawner : Monobehaviour { private void Start() { AbsMonsterFactory t_goblinFactory = new GoblinFactory(); Monster t_monster = t_goblinFactory.CreateMonster((int)EGoblin.GREEN); } }
Prototype
Prototype Pattern
- Used when the type of objects to create is determined by a prototypical instance, which is cloned to produce new objects
- Used to avoid subclasses of an object creator in the client application
- Uses to avoid the inherent cost of creating a new object in the standard way (e.g., using the 'new' keyword) when it is prohibitively expensive for a given application
Overview
- One of design patterns that describe how to make objects that are easier to implement, change, test, and reuse
- Solves problem like:
- How can objects be created so that which objects to create can be specified at run-time?
- How can dynamically loaded classes be instantiated?
- Describes how to solve such problems:
- Define a Prototype object that returns a copy of itsself
- Create new objects by copying a Prototype object
- Not require subclassing, but require an "initialize" operation
Implementations
- Declares an abstract base class that specifies a pure virtual clone() method
- Any class that needs a "polymorphic constructor" capability derives itself from the abstract base class, and implements the clone() operation
- Instead of writing code that invokes the "new" operation,
- Calls the clone() method on the prototype
- Calls the factory method with a parameter designating the particular concrete derived class desired
- Invoke the clone() method through some mechanism provided by another design pattern
Example
public abstract class Foo // Normal implementation { public abstract Foo Clone(); } public class ConcreteFoo1 : Foo { public override Foo Clone() { return (Foo)this.MemberwiseClone(); // Clones the concrete class } } public class ConcreteFoo2 : Foo { public override Foo Clone() { return (Foo)this.MemberwiseClone(); // Clones the concrete class } }
Singleton
Singleton Pattern
- Restricts the instantiation of a class to a singular instance
- Useful when exactly one object is needed to coordinate actions across a system
- Allows object to:
- Ensure objects only have one instance
- Provide easy access to that instance
- Control their instantiation (e.g., hiding the constructors of a class)
Overview
- Preferred to global variables, not pollute the global namespace (or their containing namespace)
- Permit lazy allocation and initialization
- Used as basis for other design pattern because only one facade object is required
Implementations
- Ensure that only one instance of the singleton class ever exists declaring all constructors of the class to be private, which prevents it from being instantiated by other objects
- Typically provide global access to singleton instance providing a static method that returns a reference to the instance
- Lazy Initialization
Caution to use the pattern
- A potential dependency on the singleton by other objects occuring increased coupling, introducing difficulties with unit testing
- Violate the single-responsibility principle, responsible for enforcing their own uniqueness along with performing their normal functions
Example
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SingletonMonobehaviour<T> : MonoBehaviour where T : Component { private static T instance; public static T Instance { get { if (instance == null) { instance = FindObjectOfType(typeof(T)) as T; if (instance == null) instance = new GameObject(typeof(T).Name, typeof(T)).GetComponent<T>(); } return instance; } } protected virtual void Awake() { var t_objs = FindObjectsOfType<T>(); if (t_objs.Length > 1) { Destroy(gameObject); return; } if (transform.parent != null) DontDestroyOnLoad(transform.root.gameObject); else DontDestroyOnLoad(gameObject); } }
'프로그래밍 언어' 카테고리의 다른 글
[C#] Public Field vs Auto-Implemented Property (0) 2024.04.06 OOP Design Pattern - Structural Pattern (0) 2024.01.18 [C++] 이동 의미론 Move Semantics (0) 2023.11.20 입실론 테스트 (0) 2023.11.20 객체 지향 설계 SOLID (0) 2023.11.16