C# Design Pattern (3) Decorator Pattern (unity demo)

tags: C# decoration pattern  Unity decoration mode  Decorator mode in the game  Decorator pattern  Design Patterns

1 Introduction

   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.

2. Detailed explanation of the decorator mode

2.1 Definition

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.

2.2 Mode structure

   Below is the class diagram of the decorator pattern, let's take a look!装饰者模式UML类图
From the above picture, it is not difficult to find that there are four roles in the decorator mode:

  • The role of abstract component (the object of this kind of decoration): Give an abstract interface to regulate the object to which the responsibility is added;
  • The role of the concrete component (the concrete component to be decorated): define a concrete object that will receive additional responsibilities;
  • Decorative abstract class (Decorator): Holds an instance of a component object and defines an interface that is consistent with the abstract component interface;
  • Specific decorative objects (ConcreteDecoratorA and ConcreteDecoratorB): responsible for "adding" additional responsibilities to component objects. Play the function of adding blame to Component.

2.3 Class diagram implementation

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!

3. The decorator pattern is applied in .NET

   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);

4. The advantages and disadvantages of the decorator pattern

The above is a detailed introduction of the decorator mode, let's analyze its advantages and disadvantages.

  • advantage:

    1. The purpose of this pattern of decoration and inheritance is to extend the function of the object, but the decorator pattern is more flexible than inheritance
    2. By using different specific decoration categories and the arrangement and combination of these categories, the designer can create many combinations of different behaviors
      The decorator pattern has good scalability
  • Disadvantages:
    1. The decorator pattern will cause many small objects to appear in the design. If it is overused, it will make the program more complicated. And more objects will make troubleshooting difficult, especially since these objects look very similar.

5. Applicable scene of decorator mode

   Under what circumstances the decorator mode is used, it is also summarized here. The decorator mode should be used in the following cases:

  • Need to extend the functionality of a class or add additional responsibilities to a class.
  • Need to dynamically add functions to an object, these functions can be dynamically canceled.
  • Need to add a very large number of functions resulting from the arrangement and combination of some basic functions

6. Application examples (unity)

   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.

7. Summary

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.

8. Unity demo project download

  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)

Intelligent Recommendation

C#--design pattern (decorator pattern)

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 pattern of C++ design pattern

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 pattern of design pattern (C++)

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...

C++ design pattern: decorator pattern

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...

C# design pattern-decorator pattern

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...

More Recommendation

C++ design pattern---decorator pattern

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...

C++ design pattern-decorator pattern

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 ...

"C# Design Pattern" [Decorator Pattern]

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...

Design pattern (3) Decorator pattern (Decorator)

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...

The simplest design pattern Demo: Decorator Pattern [Decorator Pattern]

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...

Copyright  DMCA © 2018-2026 - All Rights Reserved - www.programmersought.com  User Notice

Top