Вызов разом всех методов в классах,реализующих интерфейс
Допустим у меня есть интерфейс Initialization,в нем метод Init, мне нужно как то разом вызвать его во всех экземплярах класса, реализующих интерфейс, но вот проблема в том,что я не знаю как это сделать.Из контекста этот метод должен запускаться строго первым у всех классов,значит делегат или подписка через сингелтон не поможет (заносить в список тоже не вариант), точно нельзя знать где класс создан.
хотел попробовать при создании экземпляра записывать класс куда либо, но не вышло
p.s хочу реализовать похожую систему как в zenject (по атрибутам метода инжектить класс)
Ответы (1 шт):
этот метод должен запускаться строго первым у всех классов
Первым, что запускается в любом классе это конструктор! Из вопроса не понятно в чём проблема.
В MonoBehaviour есть Awake вызываемый сразу при инициализации компонента или Start в первом кадре, если объект активен, либо OnEnable при каждой активакии.
разом вызвать его во всех экземплярах класса, реализующих интерфейс
public interface IInit
{
void Init ();
}
Если метод объектов нужно вызвать одновременно, то для этого существует паттерн Obsever.
// Реализация в виде универсального класса
public class Observable<T>
{
private readonly Action<T> _notify;
private readonly List<T> _targets = new List<T>();
public Observable (Action<T> notify)
=> _notify = notify;
public void Register (T observer)
=> _targets.Add(observer);
public void Notify ()
=> _targets.ForEach(_notify);
}
Observable<IInit> initTargets = new Observable<IInit>(i => i.Init());
initTargets.Register(initA);
initTargets.Register(initB);
initTargets.Register(initC);
initTargets.Notify();
Либо паттерн Strategy.
// Данный кластер может содержать, как отдельные объекты, так и другие кластеры,
// вообще всё что угодно под интерфейсом IInit.
public class InitCluster : IInit
{
private List<IInit> _targets = new List<IInit>();
public void Add (IInit init)
=> _targets.Add(init);
public void Init ()
=> _targets.ForEach(i => i.Init());
}
IInit initTarget = new InitCluster();
initTarget.Add(initA);
initTarget.Add(initВ);
initTarget.Add(initС);
initTarget.Init();
В случае наблюдателя так-же можно использовать стратегию. Как стратегии можно использовать любые условия. Например можно создавать что-то вроде выбора, что вызывает одно из двух вариантов, в зависимости от условий, где опять-же под вариантом могут быть объекты, кластеры или последующие выборы, что угодно, сколь сложные конструкции.
public class InitChoice : IInit
{
public InitChoice (IInit a, IInit b, Func<bool> condition)
...
}
IInit myInterface = new InitChoice(mobileInterface, pcInterface, () => Application.isMobilePlatform);
initTarget.Add(myInterface);
через сингелтон не поможет, точно нельзя знать где класс создан.
Зачем вообще знать где целевой объект, если все знают, где тот, кто должен его обрабатывать? Потому что он static, потому что он один!
public class InitMaster
{
public static InitMaster _instance;
private List<IInit> _targets = new List<IInit>();
private InitMaster ()
{
}
public static InitMaster Instance
{
get {
if (_instance == null)
_instance = new InitMaster();
return _instance;
}
}
public void Add (IInit init)
=> _targets.Add(init);
public void Remove (IInit init)
=> _targets.Remove(init);
public void Init ()
=> _targets.ForEach(i => i.Init());
}
// Пример ленивого варианта (трешкод!)
public class Foo : IInit
{
// авто добавление в конструкторе
public Foo ()
=> InitMaster.Instance.Add(this);
// авто удаление в деструкторе
~Foo ()
=> InitMaster.Instance.Remove(this);
public void Init ()
=> Debug.Log("Hello");
}
InitMaster.Instance.Init();