零基础自学C#——Part5:委托和设计模式

一、委托

委托是用户自定义的类,它定义了方法的类型。储存的是一系列具有相同参数和返回类型方法的地址列表,调用委托时,此委托列表的所有方法都将被执行

C#中的委托通过Delegates关键字来声明

第一种方式:delegate void MyDelegate1(int x)

第二种方式:delegate void MyDelegate2<T>(T x)

使用委托的两种方式:

第一种方式:MyDelegate1 mydelegate=new MyDelegate1(func)

第二种方式:MyDelegate1 mydelegate=func

有两个关于设计模式的博客,内容丰富,可以参考

C#设计模式总结_dz45693的博客-CSDN博客

C#设计模式之总结篇_weixin_34166847的博客-CSDN博客

1:委托的实现

①不带参数的委托(无返回值)

public delegate void  ShowDelgate();
void Start()
    {
        ShowDelgate show=Show1;    //传递Show1给show
        show();                   //下面为调用show的两种方法
        show.Invoke();
    }

private void Show1()
    {
        Console.WriteLine("Show1");
    }

②带参数的委托(无返回值)

public delegate void ShowDelgate2(int a,int b);
void Start()
    {
        ShowDelgate2 show2=Show2;
        show2(1,2);
    }
private void Show2(int a,int b)
    {
        Console.WriteLine("Show2->a+b:"+(a+b));
    }

③带返回值的无参数委托

public delegate int ShowDelgate3();  //带有int类型的返回值
void Start()
    {

        ShowDelgate3 show3=Show3;
        int a=show3();                //用a来接收Show3的返回值
        Console.WriteLine(a);     
    }
private int Show3()  //如果不加private也行,默认的类型就是private
    {
        return 1000;                  //返回1000
    }

④带泛型的委托

public delegate void ShowDelgate4<T>(T a);  //
    void Start()
    {
        ShowDelgate4<string>show4=Show4;      //string类型约束
        show4("Hello");
    }
void Show4(string a)
    {
        Console.WriteLine("Show4->a:"+a);
    }


2:系统内置的Action和Func委托

①Action委托

Action<T>是.NET Framwork内置的泛型委托,可以使用Action<T>委托以参数形式传递方法,而不用显示声明自定义的委托(省去delegate的声明步骤)

封装的方法与此委托定义的方法签名相对应。也就是说,封装的方法必须具有一个通过值传递给它的参数没并且不能有返回值,还有一种是非泛型委托Action.

注意:
Action委托至少0个参数,至多16个参数,无返回值。

Action代表无参,无返回值的委托。

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

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

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

void Start
{
   Action action =Show1;       //直接使用Action即可,不用再声明delegate
   action();
}
void Show1()
    {
      Console.WriteLine("Show1");
    }

带参数的Action委托

void Start()
{
        Action<int,int>action2=Show2;    // 带两个int类型
        action2(1,2);         //调用

}

 void Show2(int arg1,int arg2)
    {
        Console.WriteLine("Action"+(arg1+arg2));
    }

②Func委托

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

注意:

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

     Func<int>表示没有输入参数,返回值为int类型的委托。(最后一个是返回值)

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

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

不带参数,但必须带一返回值

void Start()
    {
        Func<string>func1=Show1;
        string a=func1();
        Debug.Log(a);
    }
 
string Show1()
    {
        return"Show1";             //带有返回值
    }

带参数和返回值

void Start()
{
        Func<int,string>func2= Show2;    //参数是int类型,返回值是string类型
        string b=func2(1000);
        Debug.Log(b);
}
string Show2(int a)                 //返回值类型是string,此处参数为int,需要把a改为string
    {
        return a.ToString();
    }

3:匿名方法

没有名字的方法称为匿名方法,具体实现方法如下:

using System;   //调用系统的命名空间来引入委托
void Start()
    {

        Action action=delegate()                 //匿名函数的写法
        {
            Debug.Log("匿名函数被执行");
        };                                   //大括号外也有分号
        action();
private void Show1()
        {
            Debug.Log("Show1 被执行");
        }

4:event事件

本身是一种委托,只是该委托只能作为类的成员,且不可在类外进行调用(可通过send方式)

event事件在外部类赋值时,只能通过+=的方法;而对于普通的Action则可以通过 =/ +=/ -= 的方式进行赋值;

public class MyClass 
{
    public Action action1;          //普通action 
    public event Action action2;   //event的action不能放在函数内部
    void Start()
    {
      MyClass myClass = new MyClass();
      myClass.action2 += Show1;         //event事件只能通过+=赋值
      myClass.action1 = Show2;          //普通的委托可通过=赋值
    }
private void Show1()
    {
        Debug.Log("Show1 被执行");
    }
    private void Show2()
    {
        Debug.Log("Show2 被执行");
    }
}

通过send来在外部执行event

public class MyClass
{
  public event Action eventAction;
  public void send               //在类内使用send方法,则可从外部访问event
  {
    if(eventAction!= null)     
    eventAction();
  }
}
  myClass.Send();                 //通过Send就可以访问到eventAction

5:多播委托

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

+=  -=

委托属于引用类型,引用类型的默认值是null,直接使用的话会报错空异常,所以在使用之前必须判断委托对象(引用对象)是否为空,具体实现如下:

using System;   //调用Action,必须使用System命名空间

public class broadcast : MonoBehaviour
{
void Strat()
{
Action action = Show1;
        action+= Show2;       //多播中的+=  此时添加了Show2
        action-= Show2;       //多播中的-= 此时show2就不执行了
        action-= Show1;
        if(action!=null)    //在把Show1移除后,判断是否为空,如果不是空的,则会跳过执行,输出为空
          action();

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

二、设计模式 

定义:帮助我们解决实际开发过程中的方法,该方法是为了降低对象之间的耦合度,然而解决方法有很多种,所以前人就总结了一些常用的解决方法作为数据,这本书就是设计模式。

23种设计模式的分类: 

        创建型模式,五种:工厂方法模式,抽象工厂模式,单例模式,创建者模式,原型模式。

        结构型模式,七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式

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

C#设计模式 ---- 总结汇总_狂奔之林的博客-CSDN博客_c#设计模式

更多详细介绍可以看这篇博客

1:单例模式

解决的是实例化对象的个数的问题,该模式是把对象的数量控制为一个,该模式可以扩展,可以把实例对象扩展为N个对象,N>=2。比如对象池的实现。

特点:只能有一个实例

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

         全局唯一。

代码实现:

public class MySingleton                   //实例全局唯一:static属于全局,并不属于类对象本身
{
    private static MySingleton _instance;  //实例只能在类的内部发生:需要将构造函数私有化

    public static MySingleton instance      //单例需要提供一个供外部访问的变量
    {
        get
        {
            if(_instance==null)
             _instance =new MySingleton();
            return _instance;        
        }
    }
    
    private MySingleton()                      //将public改为private,私有的访问权限仅在类的内部,外部无法访问,因此此时MySingleton无法进行实例化
    {
        Debug.Log("构造函数执行");
    }
    
    public void Show()
    {
        Debug.Log("Show");
    }
}
public class singleton : MonoBehaviour
{
    void Start()
    {

        MySingleton single1=MySingleton.instance;    
        single1.Show();
        
        MySingleton single2=MySingleton.instance;
        single2.Show();
        
        MySingleton single3=MySingleton.instance;
        single3.Show();
        Debug.Log("single="+single1.GetHashCode()+",single2="+single2.GetHashCode()+",single3"+single3.GetHashCode());
    }

2:观察者模式

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

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

需求:野猫来了,老鼠 A B C惊吓逃走

①传统创建类

public class Animal               //创建父类,动物
{
  protected string Name;          //声明受保护的成员变量Name
  public Animal(string name)      //有参构造函数 
  {
    this.Name=name              //通过this关键字可以明确的访问一个类的成员变量,解决成员变量与局 
                                //部变量名称冲突问题。
  }
  public virtual void Run()     //使用virtual,让子类可以重构函数
  {
   
  }
}

public class Cat: Animal         //创建猫的子类
{
  public Cat(string name):base(name)   //创建猫的构造函数,并调用基类构造函数
  {
   
  }
  public void Coming(MouseA mouseA, MouseB mouseB, MouseC mouseC)//创建猫来了的方法
  {
    Debug.Log(Name+"来了");
    mouseA.Run();
    mouseB.Run();
    mouseC.Run();
    this.Run();
  }
  public override void Run()
  {
    Debug.Log("name+开始追三只老鼠");
  }
}


public class MouseA: Animal         //创建老鼠A的子类
{
  public MouseA(string name):base(name)   
  {
   
  }
  public override void Run()
  {
     Debug.Log(Name+"逃跑");
  }

}

public class MouseB: Animal         //创建老鼠B的子类
{
  public MouseB(string name):base(name)   
  {
   
  }
  public override void Run()
  {
     Debug.Log(Name+"逃跑");
  }

}

public class MouseC: Animal         //创建老鼠C的子类
{
  public MouseC(string name):base(name)   //创建猫的构造函数,并调用基类构造函数
  {
   
  }
  public override void Run()
  {
     Debug.Log(Name+"逃跑");
  }

}



public class 不用观察者:MonoBehaviour
{
  void Start()
  {
     Cat cat =new Cat("小野猫");               //对小野猫类进行实例化
     MouseA mouseA = new MouseA("mouseA");     //分别对三只老鼠进行实例化
     MouseB mouseB = new MouseB("mouseB");
     MouseC mouseC = new MouseC("mouseC");
     cat.Coming(mouseA,mouseB,mouseC);          //调用Coming函数

  }

}

②多播委托

using System;
public class Animal
{
  protected string Name;
  public Animal(string name)
  {
     this.Name = name;
  }
  public virtual void Run()
  {
    
  }
}

public class Cat:Animal
{
  public Action action              //使用委托,发布者
  public Cat(string name):base(name)
  {
    
  }
  public void Coming()
  {
   Debug.Log("Name+来了");
   if(action!= null)
      action();                    //使用多播委托实现一对多的关系
      this.Run();
  }
  public override void Run()
  {
    Debug.Log(Name+"开始追三只老鼠");
  }
}

public class Mouse:Animal
{
  public Mouse(string name,Cat cat):base(name)
  {
     cat.action += this.Run;  //订阅者
  }   
  public override void Run()
  {
    Debug.Log(Name+"逃跑");
  }
}

public class 使用多播委托:MonoBehaviour
{
  void Start()
  {
     Animal cat =new Cat("小野猫");               
     Animal mouseA = new MouseA("mouseA");    
     Animal mouseB = new MouseB("mouseB");
     Animal mouseC = new MouseC("mouseC");
     cat.Coming();               //调用Coming函数
  }
}


3:简单工厂模式

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

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

 具体代码实现:

②:抽象父类的创建

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

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

②:子类产品的创建和类的继承

Hp鼠标

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

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

Dell鼠标

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

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

Apple鼠标

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

namespace Factor
{
    public class AppleMouse : AbstractMouse
    {
        public override void Print()
        {
            Debug.Log("生产一个Apple鼠标");
        }
    }
}

③:简单工厂的方法

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

public enum MouseType
{
    None,
    DellMouse,
    HpMouse,
    AppleMouse,

}
public class FactorMain : MonoBehaviour
{
  void Start()
    {
      RunSimpleFactor();
    }
      void RunSimpleFactor()
      {
        SimpleFactor factor=new SimpleFactor();
        AbstractMouse dellMouse = factor.CreateMouse(MouseType.DellMouse);
        dellMouse.Print();

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

        AbstractMouse appleMouse = factor.CreateMouse(MouseType.AppleMouse);
        appleMouse.Print();
      }
    }
}

④:简单工厂的创建

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

namespace Factor
{
    public class SimpleFactor
    {
        public AbstractMouse CreateMouse(MouseType emMouseType)
        {
           AbstractMouse mouse =null;

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

4:工厂模式

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

      特点:只生产一种品牌(类型)的产品,在具体的子类工厂中创建。

 ①:产品的创建和类的继承和命名空间

Hp鼠标中间键

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Factor
{
    public class HpFactor : FactorBase
    {
        public override AbstractMouse CreateMouse()
        {
            return new HpMouse();
        }
    }
}

Dell鼠标中间键

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

namespace Factor
{
    public class DellFactor : FactorBase
    {
        public override AbstractMouse CreateMouse()
        {
            return new DellMouse();

        }
    }
}

Apple鼠标中间键

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

namespace Factor
{
  public class AppleFactor : FactorBase
  {
      public override AbstractMouse CreateMouse()
      {
          return new AppleMouse();
      }
  }
}

工厂中间件键

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

namespace Factor
{
    public abstract class FactorBase   //创建了工厂(中间件)的基类
    {
        public abstract AbstractMouse CreateMouse();
    }
}

②工厂的方法

void Start()
{
  RunFactor();
}
void RunFactor()
    {
        DellFactor dellFactor= new DellFactor();
        AbstractMouse dellMouse = dellFactor.CreateMouse();
        dellMouse.Print();

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

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

5:抽象工厂模式

为了解决系列产品的问题,就有了抽象工厂模式。

        特点:抽象工厂可以生产多种产品,而简单工厂/工厂模式只生产一种产品。

 ①:各类鼠标键盘的创建

Abstract的键盘和鼠标

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Factor
{
    public abstract class AbstractKeyBoard
    {
        public abstract void Print();
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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

Hp的键盘和鼠标

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Factor
{
    public class HpKeyBoard : AbstractKeyBoard
    {
        public override void Print()
        {
            Debug.Log("Hp键盘");
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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

Dell的键盘和鼠标

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Factor
{
    public class DellKeyBoard :AbstractKeyBoard
    {
        public override void Print()
        {
            Debug.Log("Dell键盘");
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

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

Apple的键盘和鼠标

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

namespace Factor
{
    public class AppleKeyBoard : AbstractKeyBoard
    {
        public override void Print()
        {
            Debug.Log("Apple键盘");
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Factor
{
    public class AppleMouse : AbstractMouse
    {
        public override void Print()
        {
            Debug.Log("生产一个Apple鼠标");
        }
    }
}

②:中间键的创建

Base中间键

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Factor
{
    public abstract class AbstractFactor_Base
    {
        public abstract AbstractMouse CreatMouse();
        public abstract AbstractKeyBoard CreateKeyBoard();
    }
}

Apple

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

namespace Factor
{
    public class AbstractFactor_Apple :AbstractFactor_Base
    {
        public override AbstractKeyBoard CreateKeyBoard()
        {
            return new AppleKeyboard();
        }
        public override AbstractMouse CreateMouse()
        {
            return new AppleMouse();
        }

    }
}

Dell

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

namespace Factor
{
    public class AbstractFactor_Apple :AbstractFactor_Base
    {
        public override AbstractKeyBoard CreateKeyBoard()
        {
            return new DellKeyboard();
        }
        public override AbstractMouse CreateMouse()
        {
            return new DellMouse();
        }

    }
}

Hp

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

namespace Factor
{
    public class AbstractFactor_Apple :AbstractFactor_Base
    {
        public override AbstractKeyBoard CreateKeyBoard()
        {
            return new HpKeyboard();
        }
        public override AbstractMouse CreateMouse()
        {
            return new HpMouse();
        }

    }
}

③方法调用

void Start()
{
  RunAbstractFactor();
}
void RunAbstractFactor()
    {
        AbstractFactor_Apple apple = new AbstractFactor_Apple();
        AbstractMouse appleMouse =apple.CreateMouse();
        appleMouse.Print();
        AbstractKeyBoard appleKeyBoard =apple.CreateKeyBoard();
        appleKeyBoard.Print();

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

        AbstractFactor_Dell dell = new AbstractFactor_Dell();
        AbstractMouse dellMouse =dell.CreateMouse();
        dellMouse.Print();
        AbstractKeyBoard dellKeyBoard =dell.CreateKeyBoard();
        dellKeyBoard.Print();

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

        AbstractFactor_Hp hp = new AbstractFactor_Hp();
        AbstractMouse hpMouse =hp.CreateMouse();
        hpMouse.Print();
        AbstractKeyBoard hpKeyBoard =hp.CreateKeyBoard();
        hpKeyBoard.Print();
    }

6:适配器模式

将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。

实现方式

    (1)类的适配器模式(采用继承实现)

     (2)对象适配器(采用对象组合方式实现)

 (部分引用自JAVA设计模式初探之适配器模式_炸斯特的博客-CSDN博客_适配器模式

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

解决:适配器模式

①分别创建IOS和Android充电的类和方法

Android

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

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

IOS

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

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

②:充电Main方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Adaptor
{
    public class AdaptouMain:MonoBehaviour
    {
        void Start() 
        {
            IAdaptor adaptor = new Adaptor();
            adaptor.Charge(AdaptorType.Android);
            adaptor.Charge(AdaptorType.IOS);
        }
    }
}

③:统一调用方法

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

namespace Adaptor
{
    public enum AdaptorType
    {
        none,
        Android,
        IOS,
    }
    
    //统一调用接口,使用不同的方法,完成不同行为
    public interface IAdaptor
    {
        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();
            androidLine.AndroidCharge();

        }
    }
}

在此处只详细学习了几类的设计模式,如果以后再用到了其他的方法,会继续添加。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Laker404

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值