C# 设计模式

C#设计模式

  • 什么是设计模式?

    • 在长久的面向对象开发过程以来,遇到种种的场景和问题,提出的解决问题的思路和方案。沉淀下来后,总结出来的解决问题的套路
  • 什么是设计原则?

    • 面向对象过程中,前辈大咖们推荐的一些指导性原则 遵循这些原则可以让你的设计更有竞争力。

      六大设计原则

单一职责原则(SRP:Single Responsibility Principle)

单一职责原则,SRP又称单一功能原则,面向对象五个基本原则(SOLID)之一。它规定一个类应该只有一个发生变化的原因。该原则由罗伯特C.马丁(Robert C.Martin)于《敏捷软件开发:原则、模式和实践》一书中给出的。

  • 定义

    • 一个模块只负责一件事。

    • 一个类只负责一件事

    • 一个方法只负责一件事。

  • 常见违背单一职责场景

    • 在方法中出现多个分支,分别去执行各自的逻辑,功能虽然可以实现。

    • 但如果需求变更,就会非常的不稳定。

  • 如何遵守单一职责原则

    • 定义抽象父类or父类虚方法
    • 子类继承后重写,不同的实现
  • 实例:不同动物的叫声处理,喊叫方法中多个分支,还是不同类不同喊叫方法。

  • 单一职责的优缺点

    • 优点

      • 每个类相对简单,只负责自己的事情。

      • 需求变更时,只修改变更类,其他类不受影响。

    • 缺点

      • 代码量会有所增加

      • 解读代码成本增加

  • 何时遵循?何时不遵守?

    • 类型逻辑足够简单,方法足够少,可以不遵守

    • 类型复杂,方法很多,一定要遵循单一职责原则

  • 单一职责的不同层面

    • 以方法为单位

      • 一个方法只负责一件事

      • 方法中可以封装成一个新方法的,就封装成一个新方法

    • 以类为单位

      • 一个类只负责一件事

      • 不属于该类的内容,创建新的类去封装

    • 以模块/项目为单位

      • 一个模块/项目只负责一件事

      • 不属于该模块的内容,交由属于的模块去负责
        abstract override

里氏替换原则(LSP:Liskov Substitution Principle)

里氏替换原则,OCP作为OO的高层原则,主张使用“抽象(Abstraction)"和“多态(Polymorphism)"将设计中的静态结构改为动态结构,维持设计的封闭性。“抽象”是语言提供的功能。“多态”由继承语义实现。

  • 定义

    • 任何使用基类的地方,都可以安全的去使用其子类。

      • 父类有的内容,子类必须有【类的强继承】

        • 如果父类出现了子类不应该有的内容,那么就应该断开两个类的继承关系

        • 然后,重新创建新的父类,包含子类该拥有的内容

      • 父类已经实现的内容,子类不要再写【不要使用new关键词隐藏父类方法]

        • 如果子类希望可以重写父类方法,父类方法用abstruct或virtual修饰
  • 实例:游戏角色中的攻击方法,不能被不能攻击的子类继承。
    对于子类自己独有的行为特征 不在父类中定义再override 而是直接在子类定义

迪米特法则(LKP:Least Knowledge Principle)

迪米特法则(Law of Demeter)又叫作最少知识原则(Least Knowledge Principle 简写LKP),一个类对于其他类知道的越少越好,就是说一个对象应当对其他对象有尽可能少的了解,只和朋友通信,不和陌生人说话.

  • 定义

    • 一个对象应该对其他对象保持最少的了解 只与直接朋友进行通信。
  • 类与类之间的关系:

    • 纵向:继承关系

    • 横向:聚合、组合、关联、依赖「出现在方法内部」

  • 高内聚、低耦合

    • 降低耦合度的方法

      1. 少使用类的继承,多用接口隐藏实现的细节。
      2. 模块的功能化分尽可能的单一,道理也很简单,功能单一的模块供其它模块调用的机会就少。(其实这是高内聚的一种说法,高内聚低耦合一般同时出现)。
      3. 遵循一个定义只在一个地方出现
      4. 少使用全局变量。
      5. 类属性和方法的声明少用public,多用private关键字。
      6. 多用设计模式,比如采用MVC的设计模式就可以降低界面与业务逻辑的耦合度。
      7. 尽量不用”硬编码”的方式写程序,同时也尽量避免直接用SQL语句操作数据库.
      8. 避免直接操作或调用其它模块或类(内容耦合);如果模块间必须存在耦合,原则上尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,避免使用内容耦合。
    • 增强内聚度方法

      1. 模块只对外暴露最小限度的接口,形成最低的依赖关系。
      2. 只要对外接口不变,模块内部的修改,就不得影响其他模块;
      3. 删除一个模块,应当只影响有依赖关系的其他模块,而不应该影响其他无关部分;
    • 通过降低访问修饰符权限,减少联系,减少耦合

依赖倒置原则(DIP:Dependence Inversion Principle)

依赖倒置原则(Dependence Inversion Principle)是程序要依赖于抽象接口,不要依赖于具体实现。简单的说就是要求对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。

  • 定义
    • 高层模块不应该依赖于低层模块,两者应该依赖抽象 而不是依赖细节。
    • 高层:方法调用方
    • 底层:被调用方
  • 面向抽象编程
    • 属性、字段、方法参数、返回值,一切都尽量使用抽象【类接口】
    • 抽象不变,高层就不变
    • 抽象一般是稳定的,低层的扩展变化不会影响到高层,低层就可以横向的自由扩展,架构稳定
    • 80%的设计模式跟抽象有关
  • 抽象的好处
    • 一个方法可以满足不同类型的参数传入
    • 支持动态扩展,只要是实现了这个抽象,不需要修改上层
  • 实例:学生类实现不同手机的使用方法,学生依赖手机,新手机出现时,学生类也要更新新方法。
    • 不同的手机应该依赖抽象(手机),学生类也应该依赖于抽象(手机用户)

接口隔离原则(ISP:Interface Segregation Principle)

客户端不应该依赖它不需要的接口。一个类对另一个类的依赖应该建立在最小的接口上。

  • 定义:
    • 使用多个专门的接口比使用单一的总接口要好,但也不建议一个接口只对应一个方法。
    • 一个类对另外一个类的依赖性应当是建立在最小的接口上的。
    • 一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。
  • 接口的正确定义
    • 既不能大而全,也不能一个接口一个方法
    • 应该按照功能的密不可分来定义接口
    • 应该是动态的,随业务变化而变化,设计的时候要留好提前量,避免抽象的变化
  • 实例:手机的核心功能就是打电话和发短信,拍照、上网等其他功能的接口,不要被手机所依颗。
  • 参看.Net类中的接口的设计与实现

开闭原则(OCP:Open Closed Principle)【总则】

在面向对象编程领域中,开闭原则规定“软件中的对象(类,模块,函数等等)应该对于扩展是开放的,但是对于修改是封闭的”,这意味着一个实体是允许在不改变它的源代码的前提下变更它的行为。该特性在产品化的环境中是特别有价值的,在这种环境中,改变源代码需要代码审查,单元测试以及诸如此类的用以确保产品使用质量的过程。遵循这种原则的代码在扩展时并不发生改变,因此无需上述的过程。

  • 定义
    • 对扩展开放 对修改关闭
      • 扩展:添加新代码(类)
      • 修改:修改原代码(类)
  • 开闭原则是一个目标,没有任何手段,又被称为总则
  • 为什么要遵循开闭原则
    • 面向对象语言是静态语言,最害怕变化,因为会波及很多东西。
    • 最理想的就是新增类,对原代码没有改动,原有代码才是可信的
  • 遇到需求变更该怎么办呢?
    • 直接修改现有方法 (最不可取)
    • 增加方法 (稍好一些)
    • 增加类 (那更好啦)
    • 增加类库/框架 (那最好啦)

设计模式

简单工厂模式

factory

Csharp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
public class LegencyFunction : MonoBehaviour {


private void Start()
{
#region Old

float? result = Count(10, 21, "*");

Debug.Log(result);

#endregion

#region New

BinaryOperation operation = OperationFactory.CreateOperation(1, 2, "+");
operation.SetNumber(2,3);
float newresult = operation.GetResult();
Debug.Log(newresult);

#endregion
}

#region Old


public float? Count(float num01, float num02, string sign)
{
switch (sign)
{
case "+":
return num01 + num02;
case "-":
return num01 - num02;
case "*":
return num01 * num02;
case "/":
return num01 / num02;
case "%":
return num01 % num02;
default:
return null;
}

}

#endregion



public abstract class BinaryOperation
{
protected float number01;
protected float number02;

public BinaryOperation() { }

public void SetNumber(float number01,float number02)
{
this.number01 = number01;
this.number01 = number02;
}

public BinaryOperation(float number01, float number02)
{
this.number01 = number01;
this.number02 = number02;
}

public abstract float GetResult();
}

public class PlusOperation : BinaryOperation
{
public PlusOperation(float number01, float number02) : base(number01, number02)
{
}

public override float GetResult()
{
return number01 + number02;
}
}

public class SubtractionOperation : BinaryOperation
{
public SubtractionOperation(float number01, float number02) : base(number01, number02)
{
}

public override float GetResult()
{
return number01 - number02;
}
}

public class MulOperation : BinaryOperation
{
public MulOperation(float number01, float number02) : base(number01, number02)
{
}

public override float GetResult()
{
return number01 * number02;
}
}

public class OperationFactory {

public static BinaryOperation CreateOperation(float number01, float number02,string sign)
{
switch (sign)
{
case "+":
return new PlusOperation(number01, number02);
case "-":
return new SubtractionOperation(number01, number02);
case "*":
return new MulOperation(number01, number02);
default:
return null;
}
}
}
}

Unity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//UnityAssetsFactory.cs
public class UnitAssetsFactory {

public static UnityAsset CreateUnityAsset(string assetType)
{
switch (assetType)
{
case "GameObject":
return new PrefabAsset("");
case "Sprite":
return new SpriteAsset("");
default:
return null;
}
}
}

public abstract class UnityAsset {

public string path;
protected object asset;

public UnityAsset(string path) {
this.path = path;
}

public void Load() {
asset = Resources.Load(path);
}
public abstract void Instantiate();
public abstract void Show();

}

public class PrefabAsset : UnityAsset
{
public PrefabAsset(string path) : base(path)
{
}

public override void Instantiate()
{
GameObject go = GameObject.Instantiate(asset as GameObject);
}

public override void Show()
{
}
}

public class SpriteAsset : UnityAsset
{
public SpriteAsset(string path) : base(path)
{
}

public override void Instantiate()
{
GameObject go = new GameObject("Sprite");
SpriteRenderer spriteRenderer = go.AddComponent<SpriteRenderer>();

Sprite sprite = Sprite.Create(asset as Texture2D, new Rect(0, 0, 100, 100), Vector2.zero);
sprite.name = "sprite";
spriteRenderer.sprite = sprite;
}

public override void Show()
{
}
}
//UnitySingtonFactory.cs
public class UnitySingtonFactory : MonoBehaviour {

public static UnitySingtonFactory instance;

private void Awake()
{
instance = this;
DontDestroyOnLoad(gameObject);
}

private void OnEnable()
{

}

public T GetAsset<T>(string assetPath) where T : Object
{
return Resources.Load<T>(assetPath);
}

public T[] GetAssets<T>(string assetsPath) where T : Object
{
return Resources.LoadAll<T>(assetsPath);
}
}
//UnityFactoryConsole.cs
public class UnityFactoryConsole : MonoBehaviour {

private void Start()
{
//第一步,工厂生产对象
//UnityAsset unityAsset = UnitAssetsFactory.CreateUnityAsset("GameObject", "Cube");
//UnityAsset unityAsset = UnitAssetsFactory.CreateUnityAsset("Sprite");
//unityAsset.path = "sword";
////第二步,对象加载资源
//unityAsset.Load();
////第三步,生产该资源
//unityAsset.Instantiate();


//单例工厂 --> 直接获取资源
GameObject cubePrefab = UnitySingtonFactory.instance.GetAsset<GameObject>("Cube");
Instantiate(cubePrefab);

}
}

策略模式

strategy

工厂模式输入参数返回对象obj
策略模式输入参数返回方法

Csharp

strategy1
strategy2
strategy3

Unity 游戏角色攻击方式不同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//Skill.cs
public abstract class Skill {

public GameHero[] AttackTargets { get; set; }

public GameHero SkillFireHero { get; set; }

public float[] SkillParameters { get; set; }

public float Damage { get; set; }

public abstract void TakeDamage();

}

/// <summary>
/// 圆形攻击技能
/// </summary>
public class CircleSkill : Skill
{
public override void TakeDamage()
{
//拿到玩家坐标
Vector3 playerPos = SkillFireHero.HeroTra.position;
//计算技能中心--> playerPos + forword * length
Vector3 skillCenter = playerPos + SkillFireHero.HeroTra.forward * SkillParameters[0];

for (int i = 0; i < AttackTargets.Length; i++)
{
//计算该目标与技能中心的距离
float dis = Vector3.Distance(skillCenter, AttackTargets[i].HeroTra.position);

//如果距离小于技能半径
if (dis <= SkillParameters[1])
{
AttackTargets[i].TakeDamage(Damage);
}
}
}
}

/// <summary>
/// 矩形攻击技能
/// </summary>
public class CubeSkill : Skill
{
public override void TakeDamage()
{
//拿到玩家坐标
Vector3 playerPos = SkillFireHero.HeroTra.position;
//计算技能中心--> playerPos + forword * length
Vector3 skillCenter = playerPos + SkillFireHero.HeroTra.forward * SkillParameters[0];

for (int i = 0; i < AttackTargets.Length; i++)
{
//计算该目标与技能中心的距离
Vector3 dir = AttackTargets[i].HeroTra.position - skillCenter;

//计算技能方向向量在横向Right和纵向Forword的投影向量
Vector3 rightDir = Vector3.Project(dir, SkillFireHero.HeroTra.right);
Vector3 forwardDir = Vector3.Project(dir, SkillFireHero.HeroTra.forward);
//如果在矩形范围内
if (rightDir.magnitude < SkillParameters[1]/2 && forwardDir.magnitude < SkillParameters[2]/2)
{
//收到伤害
AttackTargets[i].TakeDamage(Damage);
}
}
}
}
/// <summary>
/// 扇形攻击技能
/// </summary>
public class SectorSkill : Skill
{
public override void TakeDamage()
{
}
}

public class GameHero {

private string name;
public float HeroHP { get; set; }
public Transform HeroTra { get; set; }
public Skill Skill { get; set; }

public GameHero(string name)
{
this.name = name;
}

public void FireSkill()
{
Skill.SkillFireHero = this;
Skill.TakeDamage();
}

public void TakeDamage(float damage)
{
HeroHP -= damage;

Debug.Log(name + "收到伤害" + damage);
}
}
//StrategyConsole.cs
public class StrategyConsole : MonoBehaviour {

public Transform angelTra;
public Transform libaiTra;

private IEnumerator Start()
{
GameHero angel = new GameHero("安琪拉");
angel.HeroHP = 1000;
angel.HeroTra = angelTra;
GameHero libai = new GameHero("李白");
libai.HeroHP = 1200;
libai.HeroTra = libaiTra;

GameHero[] allHeros = new GameHero[] { angel, libai };

Skill skill01 = new CubeSkill();
skill01.Damage = 100;
skill01.SkillParameters = new float[] { 5, 4, 3 };
skill01.AttackTargets = allHeros;

Skill skill02 = new CircleSkill();
skill02.Damage = 100;
skill02.SkillParameters = new float[] { 5, 3 };
skill02.AttackTargets = allHeros;

angel.Skill = skill01;
libai.Skill = skill02;

while (true)//协程一直释放技能
{
yield return 0;
angel.FireSkill();
}
}
}

外观模式

facade

Csharp

facade1
facade2
facade3
facade4
facade5

Unity 框架启动模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//UIFrameFacade.cs
public class UIFrameFacade {

public void FrameStart()
{
UIAssets.instance.LoadPanel("MainPanel");
UIManager.instance.PushPanel("MainPanel");
}
}

public class UIAssets {

public static readonly UIAssets instance = new UIAssets();
private UIAssets() { }

public void LoadPanel(string panelName)
{
Debug.Log(panelName + "的资源已经加载完成!");
}
}

public class UIManager {

public static readonly UIManager instance = new UIManager();
private UIManager() { }

public void PushPanel(string panelName) {

Debug.Log("已经打开窗口..." + panelName);

}
}
//FacadeConsole.cs
public class FacadeConsole : MonoBehaviour {

private void Start()
{
//框架启动
UIFrameFacade facade = new UIFrameFacade();
facade.FrameStart();

}
}
//DemoWindowFacade.cs
public class DemoWInodwFacade : MonoBehaviour {

private Button[] buttons;

private void Awake()
{
buttons = GetComponentsInChildren<Button>();
}

public void BindEvent(UnityAction unityAction)
{
for (int i = 0; i < buttons.Length; i++)
{
buttons[i].onClick.AddListener(unityAction);
}
}
}

观察者模式

observer

Unity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//NormalObserver.cs 简单观察者模式
public class NormalObserver : MonoBehaviour {

public float interval = 3f;
private float timer = 0;

private void Update()
{
timer += Time.deltaTime;

if (timer > interval)
{
//TODO:

timer = 0;
}
}
}
//复杂
//Observer.cs
/// <summary>
/// 抽象观察者
/// </summary>
public abstract class AbObserver {

public abstract void ReveiveBeatifulGirlMsg(string canDateTime);

}

/// <summary>
/// 具体的观察者
/// </summary>
public class Observer : AbObserver
{
public string name;

public Observer(string name)
{
this.name = name;
}

public override void ReveiveBeatifulGirlMsg(string canDateTime)
{
Debug.Log(name + canDateTime);
}
}
//Subject.cs
/// <summary>
/// 抽象的通知者
/// </summary>
public interface AbSubject {

/// <summary>
/// 添加观察者
/// </summary>
/// <param name="observer"></param>
void AddObserver(AbObserver observer);
/// <summary>
/// 移除观察者
/// </summary>
/// <param name="observer"></param>
void RemoveObserver(AbObserver observer);

/// <summary>
/// 通知消息
/// </summary>
void Notify();

}


/// <summary>
/// 具体的通知者
/// </summary>
public class Subject : MonoBehaviour, AbSubject
{
private IList<AbObserver> observers;

private string canDateTime = null;

private void Awake()
{
observers = new List<AbObserver>();
}

private void Update()
{
if (BeautifulGirl.instance.CanData())
{
//此时的时间
canDateTime = Time.time.ToString();
Notify();
}
}

public void AddObserver(AbObserver observer)
{
if (!observers.Contains(observer))
observers.Add(observer);
}

public void RemoveObserver(AbObserver observer)
{
if (observers.Contains(observer))
observers.Remove(observer);
}

public void Notify()
{
for (int i = 0; i < observers.Count; i++)
{
observers[i].ReveiveBeatifulGirlMsg(canDateTime);
}
}
}
//BeautifulGirl.cs
public class BeautifulGirl : MonoBehaviour {

private int canDateProbability = 1;

public static BeautifulGirl instance;

private void Awake()
{
instance = this;
}

private void OnEnable()
{

}

public bool CanData()
{
return Random.Range(1, 101) <= canDateProbability;
}
}
//ObserverConsole.cs
public class ObserverConsole : MonoBehaviour {

private void Start()
{
//ObserverConsole

AbObserver ceo = new Observer("老王");
AbObserver cto = new Observer("老李");
AbObserver cfo = new Observer("老刘");

AbSubject subjectZhao = GetComponent<Subject>();

subjectZhao.AddObserver(ceo);
subjectZhao.AddObserver(cto);
subjectZhao.AddObserver(cfo);
}
}

代理模式

proxy

Csharp

proxy1
proxy2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
public class CsharpProxy : MonoBehaviour {


private void Start()
{
PayFine self = new NormalDriver("老王","11011111111111111","1010101001");
FriendDrive friendProxy = new FriendDrive("小王", "11016666661111", "666666");

//建立代理关系
friendProxy.realDriver = self;
//自己交罚款
friendProxy.Pay(200,3);
}
}

public abstract class PayFine {

public string name;
/// <summary>
/// 违章者的身份证
/// </summary>
public string violatorID;
/// <summary>
/// 违章者驾驶证
/// </summary>
public string violatorDriveID;

protected PayFine(string name, string violatorID, string violatorDriveID)
{
this.name = name;
this.violatorID = violatorID;
this.violatorDriveID = violatorDriveID;
}

/// <summary>
/// 支付罚款、扣除分数
/// </summary>
/// <param name="money"></param>
/// <param name="score"></param>
public abstract void Pay(float money,float score);
}

public class NormalDriver : PayFine
{
public NormalDriver(string name, string violatorID, string violatorDriveID) : base(name, violatorID, violatorDriveID)
{
}

public override void Pay(float money, float score)
{
Debug.Log(string .Format(
"我是{0},身份证号{1},驾驶证号{2},今交罚款{3},扣除分数{4}",
name,violatorID,violatorDriveID,money,score));
}
}

public class FriendDrive : PayFine
{
/// <summary>
/// 真正的驾驶员,如果没有,设置为null
/// </summary>
public PayFine realDriver;

public FriendDrive(string name, string violatorID, string violatorDriveID) : base(name, violatorID, violatorDriveID)
{
}

public override void Pay(float money, float score)
{
if (realDriver != null)
{
Debug.Log("代理人:" + name);
realDriver.Pay(money,score);
}
}
}

Unity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class UnityProxy : MonoBehaviour {

private void Start()
{
gameObject.AddComponent<DelayProxy>();
//延时执行方法
//DelayProxy.instance.DelayCall(ShowTime,3);
}

private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
//获取方法
MethodInfo methodInfo = GetType().GetMethod("ShowCurrentTime");
//通过反射,延时执行方法
DelayProxy.instance.DelayCallByReflection(methodInfo, this, new object[] { Time.time }, 5);
}
}

public void ShowTime()
{
Debug.Log("Time:" + Time.time);
}

public void ShowCurrentTime(float crtTime)
{
Debug.Log("移动延时时间:" + crtTime);
Debug.Log("执行时间:" + Time.time);
}
}

public class DelayProxy : MonoBehaviour {

public static DelayProxy instance;

private void Awake()
{
instance = this;
}

public void DelayCallByReflection(MethodInfo methodInfo,object obj,object[] parameters,float delayTime = 3f)
{
StartCoroutine(IEDelayCallByReflection(methodInfo, obj, parameters, delayTime));

}

IEnumerator IEDelayCallByReflection(MethodInfo methodInfo, object obj, object[] parameters, float delayTime)
{
//等待几秒
yield return new WaitForSeconds(delayTime);
methodInfo.Invoke(obj, parameters);
}

public void DelayCall(System.Action action,float delayTime = 3f) {

StartCoroutine(IEDelayCall(action, delayTime));
}

IEnumerator IEDelayCall(System.Action action, float delayTime)
{
//等待几秒
yield return new WaitForSeconds(delayTime);
action();
}
}

×

喜欢就点赞,疼爱就打赏