tags: C# decoration pattern Unity decoration mode Decorator mode in the game Decorator pattern Design Patterns
In software development, we often encounter that we want to add different functions to a class of objects. For example, in a game, a game character can wear different items and come in different appearances. This is what we often say about skin like: boots, wrists, weapons, belts, helmets, armor, etc., which gives players different attributes. To solve this problem, we can use the decorator pattern to dynamically add additional blame to an object. Let's discuss the decorator mode together.
Decorator Pattern
The decorator mode is to dynamically add some more blame to an object. In terms of functionality, the decorator pattern is more flexible than generating subclasses.
Below is the class diagram of the decorator pattern, let's take a look!
From the above picture, it is not difficult to find that there are four roles in the decorator mode:
The specific implementation code is as follows:
Component class, abstract interface specification is added to the object of responsibility:
abstract class Component
{
public abstract void Operate();
}
ConcreteComponent class, the object whose responsibilities are added specifically
class ConcreteComponent : Component
{
public override void Operate()
{
Console.WriteLine("Operation of specific objects!");
}
}
Decorator abstract class, inheriting the Component class, extending the functionality of the Component class from the outer class
abstract class Decorator : Component
{
protected Component component;
public void SetComponent(Component component)
{
this.component = component;
}
public override void Operate()
{
if (component != null)
{
component.Operate();//The actual execution is the parent class (COmponent's operate())
}
}
}
ConcreteDecoratorA and ConcreteDecoratorB classes, these two classes are concrete decorations, which function to add responsibilities to Component
class ConcreteDecoratorA : Decorator
{
private string addedState;
public override void Operate()
{
base.Operate();
addedState = "new state";
Console.WriteLine("The operation of the specific decorator A!");
}
}
class ConcreteDecoratorB : Decorator
{
public override void Operate()
{
base.Operate();
AddedBehavior();
Console.WriteLine("Operation of the specific decorator B!");
}
public void AddedBehavior()
{
Console.WriteLine("Add behavior!");
}
}
have a test:
ConcreteComponent c = new ConcreteComponent();
ConcreteDecoratorA a = new ConcreteDecoratorA();
ConcreteDecoratorB b = new ConcreteDecoratorB();
a.SetComponent(c);
b.SetComponent(a);
b.Operate();
Console.ReadKey();
operation result:
The operation of specific objects!
Concrete decoratorAOperation!
Add behavior!
The operation of the specific decorator B!
There is also the decorator pattern implementation in the .NET class library. This class is System.IO.Stream. Let's take a look at the Stream class structure:
In the picture above, BufferedStream, CryptoStream and GZipStream are actually two concrete decoration classes. The decorator pattern here omits the abstract decoration role (Decorator). The following demonstrates how the client dynamically adds functions to MemoryStream.
MemoryStream memoryStream = new MemoryStream(new byte[] {95,96,97,98,99});
// Extended buffer function
BufferedStream buffStream = new BufferedStream(memoryStream);
// Add encryption function
CryptoStream cryptoStream = new CryptoStream(memoryStream,new AesManaged().CreateEncryptor(),CryptoStreamMode.Write);
// Add compression function
GZipStream gzipStream = new GZipStream(memoryStream, CompressionMode.Compress, true);
The above is a detailed introduction of the decorator mode, let's analyze its advantages and disadvantages.
advantage:
Under what circumstances the decorator mode is used, it is also summarized here. The decorator mode should be used in the following cases:
Let's set a scenario:
In ARPG games, weapons and ornaments use this mode to expand the behavior of weapons. For example, a gem on a sword makes the sword increase the basic attack function and make the enemy stun. You may think that as long as it is in the sword class Wouldn’t it be good to add a stun method, but after doing so, all the instance objects of the sword have the stun function, which is not what we want, we just want to add the stun function to an object separately, you might say yes The decorative object derives a gem sword class, so that the instantiated object of the gem sword class has a stun function, which will cause some sorts of combined classes, because the decoration is diverse, there will be ruby swords, sapphire swords Classes, if the weapon has a knife, it will also have a ruby knife class, a sapphire knife class, and a large number of sorting combinations make the code difficult to maintain. Generalization (inheritance) can extend the functionality of a class. Don’t forget that composition can also extend functionality. The object-oriented principle is to prefer composition over inheritance. The decorator pattern uses both inheritance and composition to expand the capabilities of the weapon.
The following is the UML class diagram:
Let’s implement the following together:
Base class of weapons:
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// Weapons
/// </summary>
public abstract class Weapon
{
/// <summary>
/// Attack method
/// </summary>
public abstract void Attack();
}
Decorator (to attack with incoming weapons):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
/// <summary>
/// Decorator base class
/// </summary>
public abstract class Decorator:Weapon
{
private Weapon m_weapon;
public Decorator(Weapon weapon)
{
this.m_weapon = weapon;
}
/// <summary>
/// Weapon attack
/// </summary>
public override void Attack()
{
m_weapon.Attack();
}
}
Swords (a type of weapon):
using UnityEngine;
/// <summary>
/// Swords
/// </summary>
public class Sword : Weapon
{
/// <summary>
/// Attack method
/// </summary>
public override void Attack()
{
Debug.Log("Sword attack!");
}
}
Ruby weapon:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
/// <summary>
/// ruby
/// </summary>
public class RedDiamond : Decorator
{
public RedDiamond(Weapon weapon) : base(weapon)
{
}
private void Dizziness()
{
Debug.Log("dizziness...");
}
public override void Attack()
{
base.Attack();
Dizziness();
}
}
Sapphire weapon:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
/// <summary>
/// sapphire
/// </summary>
public class BlueDiamond : Decorator
{
public BlueDiamond(Weapon weapon) : base(weapon)
{
}
public override void Attack()
{
base.Attack();
Frozen();
}
/// <summary>
/// Frozen
/// </summary>
private void Frozen()
{
Debug.Log("Frozen...");
}
}
Test class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// test
/// </summary>
public class DecoratorTest : MonoBehaviour {
void Start () {
Weapon sw = new Sword();
sw.Attack();
print("----------------------------");
sw = new RedDiamond(sw);
sw.Attack();
print("========================");
sw = new BlueDiamond(sw);
sw.Attack();
}
}
Run it, the result is as follows:
In this way, if there are decorative derived classes or weapon derived classes, they can be well extended:
Continue to expand weapons and daggers
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
/// <summary>
/// dagger
/// </summary>
public class Dagger : Weapon
{
public override void Attack()
{
Debug.Log("Dagger General Attack...");
}
}
Pesticides (poisons):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;
public class YellowDiamond : Decorator
{
public YellowDiamond(Weapon weapon) : base(weapon)
{
}
public override void Attack()
{
base.Attack();
Poisoning();
}
private void Poisoning()
{
Debug.Log("Poisoning...");
}
}
test:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// test
/// </summary>
public class DecoratorTest : MonoBehaviour {
void Start () {
Weapon sw = new Sword();
sw.Attack();
print("----------------------------");
sw = new RedDiamond(sw);
sw.Attack();
print("========================");
sw = new BlueDiamond(sw);
sw.Attack();
print("+++++++++++++++++++=");
Weapon wp = new Dagger();
wp.Attack();
print("------------------------");
wp = new YellowDiamond(wp);
wp.Attack();
}
// Update is called once per frame
void Update () {
}
}
Run again, the result is as follows:
We used decorators to add functionality to the weapon without having to worry about how to add this feature. In this way, the objects are separated and you only need to care about your own functions.
To tell the truth, here, the introduction of the decorator pattern is over. The decorator pattern uses object composition instead of inheritance to achieve the ability to dynamically extend the function of the object at runtime, and can extend multiple functions as needed, avoiding The "poor flexibility" and "multi-subclass derivation problem" brought by the use of inheritance alone. At the same time, it fits well with the principles of "first use of object composition rather than inheritance" and "open-closed" principles in object-oriented design principles. The decorator pattern is a type of structural pattern.
At the end of the article, we give the project download link of the above example, which is convenient for friends to discuss and exchange! This demo version Unity5.6.3f1 (64-bit), friends who need to download VS2015, pleaseClick here to download。
The End
Ok, today’s sharing is here, if there are any shortcomings, I hope you can correct me in time, please feel free to discuss and exchange! ! !
Friends you like, please help, like, comment! Yours is definitely my endless motivation for writing!
Related Reading
C# 23 design patterns (unity demo)
Extend the function of an object without changing the original state, by creating a class to wrap the previous object. Example: Girls love makeup, the prototype is a girl, the base makeup package prot...
Decorator mode (DECRATOR): In order to realize the dynamic addition of functions to the object, that is, to add related functions to the object from the outside. It can be understood in this way. For ...
Decorator mode (DECRATOR):In order to realize the dynamic addition of functions to the object, that is, to add related functions to the object from the outside. It can be understood in this way. For e...
Decorator mode The Decorator Pattern allows adding new functionality to an existing object without changing its structure. This type of design pattern belongs to the structural pattern, which serves a...
Introduction to the decorator pattern Add some additional responsibilities to an object dynamically. In terms of increasing functionality, it is more flexible than generating subclasses. This mode cre...
Decorator mode effect: The decoration mode can dynamically add functions to an object, which is to add functions to an object from outside the object. Without having to change the original clas...
Article Directory Background Overview of the decorator pattern concept UML diagram Role in the pattern advantage Disadvantages of decorative patterns Applicable scene Background In many cases, when a ...
One: Case scenario In software development, we often want to add different functions to a class of objects, such as adding security to the house, house heating, house waterproofing, etc. If you use in...
Wikipedia definition Decoration mode refers to dynamically expanding the function of an object without having to change the original file and use inheritance. It is by creating a packaging object, tha...
1. Procedure description A newly opened coffee shop can add various ingredients to the coffee, such as milk, sugar, and milk foam. According to object-oriented design, the first thing we thought of wa...