C# Unity: В чем разница между вызовом функции другого класса напрямую и вызовом функции путем подписки на событие? - PullRequest
1 голос
/ 03 мая 2020

В разработке игр (Unity C#) в моей голове всегда был вопрос о лучшем методе или наилучшем подходе для вызова функции из другого класса, здесь я использую два метода:

МЕТОД 1

Создание функции DoSomething publi c в классе 1 и вызов ее из класса 2

Класс 1:

public class Class1 : MonoBehaviour{

    public static Class1 instance;

    private void Awake()
    {
        instance = this;
    }

    //The function we want to call
    public function DoSomething(){

        Debug.Log("Done something!");

    }

}

Класс 2:

public class Class2 : MonoBehaviour{

    private Class1 _class1;

    private void start(){
        _class1 = Class1.instance;
    }

    public function SomeFunction(){

        //Calling the function
        _class1.DoSomething();

    }

}

МЕТОД 2

Создание event в классе 2 и подписка на это событие в класс 1, таким образом функция будет вызвана, когда мы вызовем событие в классе 2

класс 1:

public class Class1 : MonoBehaviour{


    private void OnEnable()
    {
        Class2.OnSomeEvent += DoSomething;
    }


    private void OnDisable()
    {
        Class2.OnSomeEvent -= DoSomething;
    }

    //The function we want to call
    private function DoSomething(){

        Debug.Log("Done something!");

    }

}

класс 2:

public class Class2 : MonoBehaviour{

    public static event Action OnSomeEvent = delegate {};

    public function SomeFunction(){

        OnSomeEvent();

    }

}

В чем разница между этими двумя методами и какой из них обладает наилучшими функциональными возможностями и производительностью?

Ответы [ 3 ]

2 голосов
/ 03 мая 2020

Производительность зависит от варианта использования. Допустим, вы хотите запустить какой-нибудь метод в классе, когда здоровье игрока ниже определенного значения. Один из вариантов - проверять на каждом Обновлении , пора ли это делать. Это, однако, было бы неэффективно. Лучшим вариантом было бы подписаться на событие, которое срабатывает только при изменении состояния, и вместо этого выполнить проверку состояния.

Кроме того, это дополнительный инструмент для разработки архитектуры проекта. Вместо того, чтобы смешивать код вместе, у вас может быть один класс, который будет информировать других, когда происходит что-то X , и другие могут слушать это событие.

2 голосов
/ 03 мая 2020

В вашем втором решении с событием, Class2 не нужно ничего знать о Class1. Может быть, даже несколько других объектов могут подписаться на это событие, а может и нет. Class2, представляющее событие, может даже принадлежать библиотеке, написанной в то время, когда подписчик Class1 не существовал.

Пример: вы создаете элемент управления MySuperButton, который выглядит намного лучше, чем стандартные кнопки. Эта кнопка будет использоваться в разных местах и ​​вызывать разные обработчики кликов. Таким образом, при написании кода кнопки вы не знаете, какие методы будут вызываться при нажатии кнопки. Вы просто инициируете событие Click, и все готово.

Разницами в производительности можно пренебречь в большинстве случаев.

Руководство C# Программирование гласит:

  • События позволяют классу или объекту уведомлять другие классы или объекты, когда происходит что-то интересное.
  • Издатель определяет, когда происходит событие; подписчики определяют, какие действия предпринимаются в ответ на событие.

Таким образом, в основном вы получаете лучшее разделение проблем, а также инверсию зависимостей.

1 голос
/ 03 мая 2020

Различий в производительности нет. Использование системы событий может быть намного более эффективным и удобным. Предположим, вы хотите, чтобы что-то происходило в программе, когда вы хотите, чтобы DoSomething прекратил работу, просто отмените подписку на событие.

Class2.OnSomeEvent -= DoSomething;

Другой сценарий, предположим, что ваш старший разработчик хочет, чтобы Class3.SomethingMore и Class4.AnotherThing происходили тоже , Вместо того, чтобы связывать их с методом DoSomething, они также могут просто подписаться на событие с многоадресной рассылкой.

 // in Class 3 OnEnable
 Class2.OnSomeEvent += SomethingMore;

 // in Class 4 OnEnable
 Class2.OnSomeEvent += AnotherThing;

Теперь OnSomeEvent запустит все три события. Система делегатов делает ваш код намного более читабельным, модульным и более легким для отладки, поскольку ваша программа становится больше и сложнее. Вы можете подписывать методы на важные события в вашей игре, вместо того чтобы создавать длинные, трудно читаемые цепочки вызовов методов, которые трудно go вернуть и внести изменения. Как правило, Unity спроектирован так, чтобы быть максимально модульным с его Компонентной системой, а система событий делегатов - это способ сделать вызовы методов модульными. Можно также сказать, что есть дополнительный бонус классов, которым не нужны ссылки на другие классы и разрешения для их методов, когда другие классы подписываются на событие.

Чтобы добавить еще один пример, допустим, вы не использовали система событий и прямо сейчас у вас были разные классы, которые периодически вызывались.

Class1.DoSomething();

Ваш старший разработчик говорит вам, что всякий раз, когда вызывается DoSomething (), необходимо вызывать SomethingMore () и AnotherThing (). Вы можете просмотреть код и попытаться найти все места, где вызывается DoSomething (), и добавить две строки после SomethingMore () и AnotherThing () и убедиться, что вызывающие классы имеют ссылки на Class3 и Class4. Другой вариант - добавить ссылки на эти классы в Class1, а в конце метода DoSomething () добавить SomethingMore () и AnotherThing (). Проблема в том, что если позже ваша команда выяснит, что DoSomething () должен вызываться в некоторых случаях сам по себе без SomethingMore () и AnotherThing (), теперь ваш код начнет становиться уродливым.

Наконец, Допустим, вы создаете экземпляры «Bug» врагов, которые будут Swarm (), когда королева приказывает им. Не существует постоянного количества «баговых» врагов, так как некоторые появляются случайным образом и уничтожаются игроком. В скрипте Bug для каждой ошибки гораздо проще подписаться на событие королевы SwarmCommand, чем в скрипте Queen, когда вызывается SwarmCommand для поиска ссылок на каждую ошибку и вызова ошибки Swarm. () '(Вам нужно было бы вызвать FindObjectsWithTag или сохранить актуальный массив всех объектов Bug GameObject, к которым будут добавлены некоторые расходы).

...