Unity——觀察者模式

小紫蘇xw發表於2021-10-08

觀察者模式

一、Demo展示

2

二、設計思路

我們假設一種情況,在app中修改了頭像,在所有顯示頭像的UI中都需要更改相應的圖片,一個個去獲取然後呼叫重新整理會非常麻煩;

因此我們需要一個自動響應機制——觀察者模式;

核心:一個key對應多個Action(委託);

流程:

1.提前在每個需要響應的UI中新增監聽事件;

2.修改資料同時註冊觀察者,需要引數可傳參;

3.每一幀在LateUpdate中呼叫響應函式,把所有新增了註冊了事件執行一遍;

三、關鍵類

1.帶引數委託

由於引數型別不確定,所以使用object型別;

public delegate void obsAct(object args);

2.ObserverMa(單例)

欄位:

private Dictionary<string,  List<obsAct>> dicAll //儲存所有事件和響應
private List<string> curAct = new List<string>();//儲存當前幀註冊的事件key值
private ArrayList objArgs = new ArrayList();	 //儲存key對應的引數

方法:

1)新增監聽

public void AddListener(string key, obsAct act)
{
    if (dicAll.ContainsKey(key))
    {
        dicAll[key].Add(act);
    }
    else
    {
        List<obsAct> actions = new List<obsAct>();
        actions.Add(act);
        dicAll.Add(key, actions);
    }
}

2)註冊事件

public void Register(string key,object args = null)
{
    if (dicAll.ContainsKey(key))
    {
        curAct.Add(key);
        objArgs.Add(args);
    }
    else
    {
        Debug.Log("未註冊觀察事件");
    }
}

3)響應事件

public void Respond()
{
    for (int i = 0; i < curAct.Count; ++i)
    {
        List<obsAct> acts = dicAll[curAct[i]];
        for (int j = 0; j < acts.Count; ++j)
        {
            acts[j](objArgs[i]);
        }
    }

    curAct.Clear();
    objArgs.Clear();
}

四、測試類

這裡為了方便,我只用了InputFiled和Text元件來完成;

InputFiled輸入文字,結束時通知4個Text,Text顯示輸入的文字;

在Canvas上了指令碼UIMa,UIMa的LateUpdate方法中呼叫了ObserverMa.I.Respond();

image-20210929173035588

完整程式碼:

1.InputFiled

public class InputStr : MonoBehaviour
{
    private InputField strInput;
    private string str = "";
    private bool isAdd = false;
    private void Start()
    {
        strInput = GetComponent<InputField>();
    }
    
    void Update()
    {
        if (strInput.isFocused && !isAdd)
        { 
            isAdd = true;
        }

        if (!strInput.isFocused && isAdd)
        {
            ObserverMa.I.Register(ObsStr.inputStr, strInput.text);
            isAdd = false;
        }
    }
}

2.Text

public class Text1 : MonoBehaviour
{
    public Text text;
    private void Start()
    {
        text = GetComponent<Text>();
        obsAct act = (str) => { text.text = str as string;};
        ObserverMa.I.AddListener(ObsStr.inputStr,act);
    }
}

五、優化方案

1.所有的key值可以自動使用const string 類替代,避免每次註冊需要手動輸入字串,且容易出錯;

2.無參委託和有參委託可以分開寫,寫兩套重寫的註冊方法,資料也分開儲存,減少Object = null的儲存;

以上是我對觀察者模式的理解,如果有更好的想法可以給我留言;

相關文章