HOME
BLOG
设计模式专题
9月 04 2022

委托

| 委托的定义和使用

  • 作用

    • 把方法作为函数来进行传递,用到委托。委托是一个类型,这个类型可以赋值一个方法的引用。

    • C# 的委托通过 delegate 关键字来声明。

  • 声明委托

    • (1) delegate void MyDelegate1( int x )

    • (2) delegate void MyDelegate2<T>( T x )

  • 使用委托

    • (1) MyDelegate1 mydelegate = new MyDelegate( func )

    • (2) MyDelegate1 mydelegate = func

演示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BaseDelegate : MonoBehaviour
{
    public delegate void ShowDelegate();
    public delegate void ShowDelegate2(int a, int b);
    public delegate int ShowDelegate3();
    public delegate void ShowDelegate4<T>(T a);

    void Start()
    {
        ShowDelegate show = Show1;
        show();
        //show.Invoke();

        ShowDelegate2 show2 = Show2;
        show2(1, 2);


        ShowDelegate3 show3 = Show3;
        int a = show3();
        Debug.Log(a);

        ShowDelegate4<string> show4 = Show4;
        show4("Hello World");
    }

    private void Show1()
    {
        Debug.Log("Show1");
    }

    private void Show2(int a, int b)
    {
        Debug.Log("Show2 -> a+b:" + (a + b));
    }

    private int Show3()
    {
        return 1000;
    }

    private void Show4(string a)
    {
        Debug.Log("Show4 -> a:" + a);
    }
}

| 系统内置 Action 委托

需要命名空间: using Ststem;

什么是Action委托:

Action<T> 是.NET Framework内置的泛型委托,可以使用 Action<T> 委托以参数形式传递方法,而不用显示声明自定义的委托。封装的方法必须与此委托定义的方法签名相对时应。也就是说,封装的方法必须具有一个通过值传递给它的参数,并且不能有返回值。 还有一种是非泛型委托 Action

注意点:

  • Action 委托至少 0 个参数,至多 16 个参数,无返回值

  • Action 表示无参,无返回值的委托

  • Action< int, string> 表示有传入参数 int,string 无返回值的委托

  • Action< int, string, bool> 表示有传入参数 int,string,bool 无返回值的委托

  • Action< int, int, int, int> 表示有传入 4 个 int 型参数,无返回值的委托

演示:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SystemAction : MonoBehaviour
{
    void Start()
    {
        Action action1 = Show1;
        action1();

        Action<int, int> action2 = Show2;
        action2(1, 2);

        //Action<
    }

    void Show1()
    {
        Debug.Log("Show1");
    }

    void Show2(int arg1, int arg2)
    {
        Debug.Log("Action:" + (arg1 + arg2));
    }
}

| 系统内置 Func 委托

什么是 Func 委托:

Func 是 .NET Framework 内置的带有返回类型的泛型委托。

注意点:

  • Func :至少 0 个传入参数,至多16个传入参数,根据返回值 泛型 返回。必须有 返回值,不可void。

  • Func<int> :表示没有传入参数,返回值为 int 类型的委托。

  • Func<object,string,int> :表示传入参数为为object,string ,返回值为 int 类型的委托。

  • Func<object,string,int> :表示传入参数为为object,string,返回值为 int 类型的委托。

  • Func<T1,T2..T3,int> : 表示传入参数为T1, T2..T3(泛型),返回值为 int 类型的委托。

  • System.Func 可以不带参数,但是必须带一个返回值

  • System.Func 若是调用的多个泛型的委托定义,最后的参数的数据类型 是函数的返回值类型,需要保持一致;非最后一个泛型T的声明,需要与实现函数的参数个数及类型保持一致

演示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class SystemFunc : MonoBehaviour
{
    void Start()
    {
        Func<string> func1 = Show1;
        string a =  func1();
        Debug.Log(a);

        //Func<string, int> func2 = Show2;
        Func<int,string> func2 = Show2;
        string b =  func2(1000);
        Debug.Log(b);

        //Func<
    }

    string Show1()
    {
        return "Show1";
    }

    //int Show2(string a)
    //{
    //    return int.Parse(a);
    //}

    string Show2(int a)
    {
        return a.ToString();
    }
}

| 匿名方法、event 事件、多播委托

什么是匿名方法:

  • 没有名字的方法称之为匿名方法

什么是 Event 事件:

  • event 事件本身就是一种委托,只是该委托只能作为类的成员,且不可在类外进行调用

  • 注意点

    • (1)
      • event 事件 只允许作为类的成员变量 且仅在类的内部使用才可以,外部不得直接调用。
    • (2)
      • 当作为 A 类的成员 event事件 在外部类赋值时,只能通过 += 的方法;
      • 而对于 普通的 Action 则可以 = / += -= 的方式进行赋值

什么是多播委托:

  • 在 C# 语言中多播委托是指在一个委托中注册多个方法,在注册方法时可以在委托中使用 加号运算符 或者 减号运算符 来实现添加或者撤销方法

  • 注意点

    • += & -=

    • 委托属于引用类型,引用类型的默认值是 null,直接使用的话会报错空异常;所以在使用之前需要先判断委托对象(引用对象)是否为空

演示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class MyEventClass
{
    public event Action eventAction;
    public Action defaultAction;
    public void Send()
    {
        if(eventAction != null)
        {
            eventAction();
        }
    }
}

public class BoardCast : MonoBehaviour
{
    //event Action action;
    void Start()
    {
        //Action action = Show1;
        //Action action = delegate ()
        //{
        //    Debug.Log("匿名函数 被执行");
        //};
        //action();

        //Action action = Show1;
        //action += Show2;
        //action -= Show2;
        //action -= Show1;
        //if(action != null)
        //   action();

        //action = Show1;
        //action();

        MyEventClass myClass = new MyEventClass();
        myClass.eventAction += Show1;
        myClass.Send();
        //myClass.eventAction(); error
        //myClass.eventAction -= Show1;
        myClass.defaultAction = Show2;
        myClass.defaultAction();
    }

    private void Show1()
    {
        Debug.Log("Show1 被执行");
    }

    private void Show2()
    {
        Debug.Log("Show2 被执行");
    }
}

设计模式相关内容

| 设计模式(Design pattern)

分类:

  • 创建型模式:共 5 种 - 工厂方法模式抽象工厂模式单例模式 、建造者模式 、原型模式

  • 结构型模式:共 7 种 - 适配器模式 、装饰器模式 、代理模式 、外观模式 、桥接模式 、组合模式 、享元模式

  • 行为型模式:共 11 种 - 策略模式 、模板方法模式 、观察者模式 、迭代子模式 、责任链模式 、命令模式 、备忘录模式 、状态模式 、访问者模式 、中介者模式 、解释器模式


| 单例模式

即所谓的一个类只能有一个实例,也就是类只能在内部实例一次,然后提供这一实例,外部无法对此类实例化。多用在 管理器

特点:

  • 实例全局唯一

    • static 静态变量 属于全局,并不属于类对象本身
  • 实例只能在类的内部发生

    • 需要将构造函数私有化
  • 需要提供一个供外部访问的变量

  • 只能自己创建自己的唯一实例

演示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MySingleton
{
    private static MySingleton _instance;
    public static MySingleton instance
    {
        get //初始化
        {
            if (_instance == null)
            {
                _instance = new MySingleton();
            }
            return _instance;
        }
    }

    private MySingleton()
    {
        Debug.Log("构造函数执行");
    }

    public void Show()
    {
        Debug.Log("Show");
    }
}

public class Singleton : MonoBehaviour
{
    void Start()
    {
        //MySingleton single1 = new MySingleton();
        //MySingleton single2 = new MySingleton();
        //MySingleton single3 = new MySingleton();

        //Debug.Log("single1 =" + single1.GetHashCode() + ",single2 =" + single2.GetHashCode() + ",single3 =" + single3.GetHashCode());

        MySingleton single1 = MySingleton.instance;
        single1.Show();

        MySingleton single2 = MySingleton.instance;
        single2.Show();

        MySingleton single3 = MySingleton.instance;
        single3.Show();

        Debug.Log("single1 =" + single1.GetHashCode() + ",single2 =" + single2.GetHashCode() + ",single3 =" + single3.GetHashCode());
    }
}

| 观察者模式

有时被称为 发布 / 订阅模式,观察者定义了一种 一对多 的依赖关系,让多个观察者对象同时监听某一主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己。此种模式通常被用来实现事件处理系统。

特点: 发布者 + 订阅者 = 观察者模式

观察者模式相关博文:【Unity与23种设计模式】观察者模式(Observer) - Lumious - 博客园

演示:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

/*
 *    观察者模式
 *            需求:
 *                野猫来了,老鼠 A B C 惊吓逃走
 */

public class Animal
{
    protected string Name;
    public Animal(string name)
    {
        this.Name = name;
    }

    public virtual void Run()
    {

    }
}

public class Cat : Animal
{
    public Action actions; // 发布者

    public Cat(string name): base(name)
    {

    }

    public void Coming(/*Animal mouseA, Animal mouseB, Animal mouseC, Animal mouseD*/)
    {
        Debug.Log(Name + "来了");
        //mouseA.Run();
        //mouseB.Run();
        //mouseC.Run();
        //mouseD.Run();
        if (actions != null)
        {
            actions(); // 通过 多播委托 实现一对多的关系
        }
        this.Run();
    }

    public override void Run()
    {
        Debug.Log(Name + "开始追三只老鼠...");
    }
}

public class Mouse : Animal
{
    public Mouse(string name,Cat cat) : base(name)
    {
        cat.actions += this.Run; // 订阅者
    }

    public override void Run()
    {
        Debug.Log(Name + "逃跑");
    }
}

#region Temp
//public class MouseB : Animal
//{
//    public MouseB(string name) : base(name)
//    {

//    }
//    public override void Run()
//    {
//        Debug.Log(Name + "逃跑");
//    }
//}

//public class MouseC : Animal
//{
//    public MouseC(string name) : base(name)
//    {

//    }
//    public override void Run()
//    {
//        Debug.Log(Name + "逃跑");
//    }
//}
#endregion

public class Visit : MonoBehaviour
{
    void Start()
    {
        Cat cat = new Cat("小野猫");

        Animal mouseA = new Mouse("mouseA", cat);
        Animal mouseB = new Mouse("mouseB", cat);
        Animal mouseC = new Mouse("mouseC", cat);
        Animal mouseD = new Mouse("mouseD", cat);
        Animal mouseE = new Mouse("mouseE", cat);

        cat.Coming(/*mouseA, mouseB, mouseC, mouseD*/);
    }
}

| 工厂模式

分类:

  • 简单工厂模式

    • 属于创建型模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族种最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现。

    • 特点:只生产一种品牌(类型)的产品,在工厂种动态创建

    • 简单工厂模式推荐阅读:C#设计模式(1)——简单工厂模式 - Frank_520 - 博客园

    • 图解:

SampleFactor:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


namespace Factor
{
    public class SampleFactor
    {
        public AbstructMouse CreateMouse(MouseType emMouseType)
        {
            AbstructMouse mouse = null;

            switch (emMouseType)
            {
                case MouseType.HpMouse:
                    mouse = new HpMouse();
                    break;
                case MouseType.DellMouse:
                    mouse = new DellMouse();
                    break;

                default:
                    break;
            }
            return mouse;
        }
    }
}

HpMouse:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


namespace Factor
{
    public class HpMouse : AbstructMouse
    {
        public override void Print()
        {
            Debug.Log("生产了一个Hp鼠标");
        }
    }
}

DellMouse:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//using Factor;

namespace Factor
{
    public class DellMouse : /*Factor.*/ AbstructMouse
    {
        public override void Print()
        {
            Debug.Log("生产了一个Dell鼠标");
        }
    }

}

AbstructMouse:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Factor
{
    public abstract class AbstructMouse
    {
        public abstract void Print();
    }
}

FactorMain:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Factor;

public enum MouseType
{
    None,
    DellMouse,
    HpMouse,
}

public class FactorMain : MonoBehaviour
{
    void Start()
    {
        //RunNormal();
        RunSampleFactor();
    }

    void RunNormal()
    {
        DellMouse dellMouse = new DellMouse();
        dellMouse.Print();

        HpMouse hpMouse = new HpMouse();
        hpMouse.Print();

    }
    void RunSampleFactor()
    {
        SampleFactor factor = new SampleFactor();
        AbstructMouse dellMouse = factor.CreateMouse(MouseType.DellMouse);
        dellMouse.Print();

        AbstructMouse hpMouse = factor.CreateMouse(MouseType.HpMouse);
        hpMouse.Print();

    }
    void RunFactor()
    {

    }

    void Update()
    {

    }
}
  • 工厂模式

    • 避免简单工厂模式种,新增产品品牌(类型)时,直接修改工厂类。为了解决这个问题出现了 工厂模式。

    • 特点:只生产一种品牌(类型)的产品,在具体的子类工厂中创建。为了解决系列产品的问题,就有了抽象工厂模式。

    • 工厂模式推荐阅读:C#设计模式(2)——工厂模式 - Frank_520 - 博客园

    • 图解:

FactorBase:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Factor
{
    public abstract class FactorBase
    {
        public abstract AbstructMouse CreateMouse();
    }
}

DellFactor:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Factor;

public class DellFactor : FactorBase
{
    public override AbstructMouse CreateMouse()
    {
        return new DellMouse();
    }
}

HpFactor:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Factor;

public class HpFactor : FactorBase
{
    public override AbstructMouse CreateMouse()
    {
        return new HpMouse();
    }
}

AppleFactor:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Factor;

public class AppleFactor : FactorBase
{
    public override AbstructMouse CreateMouse()
    {
        return new AppleMouse();
    }
}

FactorMain:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Factor;

public class FactorMain : MonoBehaviour
{
    void Start()
    {
        //RunNormal();
        //RunSampleFactor();
        RunFactor();
    }
    void RunFactor()
    {
        DellFactor dellFactor = new DellFactor();
        AbstructMouse dellMouse = dellFactor.CreateMouse();
        dellMouse.Print();

        HpFactor hpFactor = new HpFactor();
        AbstructMouse hpMouse = hpFactor.CreateMouse();
        hpMouse.Print();

        AppleFactor appleFactor = new AppleFactor();
        AbstructMouse appleMouse = appleFactor.CreateMouse();
        appleMouse.Print();
    }
}

AbstructKeyBoard:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Factor;

public abstract class AbstructKeyBoard 
{
    public abstract void Print();
}

AppleKeyboard / DellKeyboard / HpKeyboard :

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Factor;

public class AppleKeyboard : AbstructKeyBoard // 其他两个同理
{
    public override void Print()
    {
        Debug.Log("Apple键盘");
    }
}

AbstructFactor_Base:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Factor;


public abstract class AbstructFactor_Base 
{
    public abstract AbstructMouse CreateMouse();
    public abstract AbstructKeyBoard CreateKeyBoard();
}

AbstructFactor_Apple / AbstructFactor_Dell / AbstructFactor_Hp:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Factor;

public class AbstructFactor_Apple : AbstructFactor_Base // 其他两个同理
{
    public override AbstructKeyBoard CreateKeyBoard()
    {
        return new AppleKeyboard();
    }

    public override AbstructMouse CreateMouse()
    {
        return new AppleMouse();
    }
}

FactorMain:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Factor;

public class FactorMain : MonoBehaviour
{
    void Start()
    {
        //RunNormal();
        //RunSampleFactor();
        //RunFactor();

        RunAbstructFactor();
    }

    void RunAbstructFactor()
    {
        AbstructFactor_Apple apple = new AbstructFactor_Apple();
        AbstructMouse appleMouse = apple.CreateMouse();
        appleMouse.Print();
        AbstructKeyBoard appleKeyBoard = apple.CreateKeyBoard();
        appleKeyBoard.Print();

        Debug.Log("------------------------------------------");

        AbstructFactor_Dell dell = new AbstructFactor_Dell();
        AbstructMouse dellMouse = dell.CreateMouse();
        dellMouse.Print();
        AbstructKeyBoard dellKeyBoard = dell.CreateKeyBoard();
        dellKeyBoard.Print();

        Debug.Log("------------------------------------------");

        AbstructFactor_Hp hp = new AbstructFactor_Hp();
        AbstructMouse hpMouse = hp.CreateMouse();
        hpMouse.Print();
        AbstructKeyBoard hpKeyBoard = hp.CreateKeyBoard();
        hpKeyBoard.Print();
    }
}

| 适配模式

问题:Android / iOS 充电线标准不一样,只有一根线时,如何完成不同型号手机充电?

解决:适配器模式

适配模式推荐阅读: C#设计模式(7)——适配器模式 - Frank_520 - 博客园

图解:

Adaptor:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Adaptor
{
    public enum AdaptorType
    {
        None,
        Android,
        iOS,
    }

    public interface IAdaptor
    {
        /// <summary>
        /// 统一调用接口,大一统
        /// </summary>
        /// <param name="adaptorType"></param>

        void Charge(AdaptorType adaptorType);
    }

    public class Adaptor : IAdaptor
    {
        // 之前已经写了非常多的代码,但是 现在需要增加一个转换器的接口
        // 接口 用于拓展原始类不足的功能

        AndroidLine androidLine = new AndroidLine();
        IosLine iosLine = new IosLine();

        public void Charge(AdaptorType adaptorType)
        {
            if (adaptorType == AdaptorType.Android)
                androidLine.AndroidCharge();
            else if (adaptorType == AdaptorType.iOS)
                iosLine.IOSCharge();
        }
    }
}

IosLine:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Adaptor
{
    public class IosLine
    {
        public void IOSCharge()
        {
            Debug.Log("借助iOS充电线充电中...");
        }
    }
}

AndroidLine:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Adaptor
{
    public class AndroidLine
    {
        public void AndroidCharge()
        {
            Debug.Log("借助Android充电线充电中...");
        }
    }
}

AdaptorMain:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


namespace Adaptor
{
    public class AdaptorMain : MonoBehaviour
    {
        void Start()
        {
            IAdaptor adaptor = new Adaptor();
            adaptor.Charge(AdaptorType.Android);
            adaptor.Charge(AdaptorType.iOS);
        }
    }
}


👾 - Morikiiii - 👾

C# Study