觀察者模式
一、Demo展示
二、設計思路
我們假設一種情況,在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();
完整程式碼:
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的儲存;
以上是我對觀察者模式的理解,如果有更好的想法可以給我留言;