- Home /
Singleton class or delegate?
Which is the best approach to call a function. Lets take an example of a car game. Singleton class
GameManager is a singleton class and I have one more class called PlayerCar.
public class GameManager : MonoBehaviour {
private static GameManager _instance;
public CameraManager camera;
public SoundManager sound;
public UIManager ui;
public static GameManager instance{
get{
if(_instance == null){
_instance = GameObject.FindObjectOfType<GameManager>();
}
return _instance;
}
}
public void CarDamage(){
camera.Shake();
sound.PlayDamage();
ui.ShowDamageText();
}
}
public class PlayerCar{
private void OnDamageRecieved(){
GameManager.instance.CarDamage();
}
}
Now whenever playercar recieves damage OnDamageRecieved is called which in turn calls Gamemanagers CarDamage function.
Now let's us take another method which is delegate and events
public class PlayerCar{
public delegate void Damage();
public static event Damage ShakeCamera;
public static event Damage PlayDamageSound;
public static event Damage ShowDamageText;
private void OnDamageRecieved(){
ShakeCamera();
PlayDamageSound();
ShowDamageText();
}
}
public class CameraManager : MonoBehaviour{
void OnEnable(){
PlayerCar.ShakeCamera += Shake;
}
void OnDisable(){
PlayerCar.ShakeCamera -= Shake;
}
private void Shake(){}
}
public class SoundManager : MonoBehaviour{
void OnEnable(){
PlayerCar.PlayDamageSound += PlayDamage;
}
void OnDisable(){
PlayerCar.PlayDamageSound -= PlayDamage;
}
private void PlayDamage(){}
}
public class UIManager : MonoBehaviour{
void OnEnable(){
PlayerCar.ShowDamageText += ShowDamageText;
}
void OnDisable(){
PlayerCar.ShowDamageText -= ShowDamageText;
}
private void ShowDamageText(){}
}
So which is the best approach of calling a function which is in some other class.
Answer by Paulius-Liekis · Feb 10, 2016 at 10:05 AM
First option is better, because you have less static stuff and there is just a single class that knows about a structure of these relationships.
What you want to build in the end is something that is easy to modify. Statics are not that. They couple your code. Imagine you need to add an extra car (without camera shake) or add an extra effect. Which way is it easier to do?
Statics aren't so bad with coupling as to always shun them. in fact the very idea of Singletons violate the idea of coupling, its just that they have benefits that make them worth to be used.
Yes, you generally want decoupled systems so that your projects can scale. however Statics have their own advantages that will sometimes outweigh the desire to go completely decoupled. Also there's a limit to how decoupled you should go. if you wanted to go full decoupled then you wouldn't even be allowed to use most of the Unity Engine namespaces
As for the OP's question I would semi lean to the second option, just not as static events. think of static events as car takes damage. which might make sense for the sound manager, but the camera should only shake for the car its locked to. perhaps he just has a single nonstatic event "OnDamaged" for the camera and Ui to listen for when the player's car takes damage, and then a static event "OnAnyCarDamaged" for the sound manager to attach to, with an internal handler for OnDamaged that will also invoke OnAnyCarDamaged.
$$anonymous$$y favorite way of setting up global events is using the an Event$$anonymous$$anager like what has been shown in the Event Live session tutorial. everything that wants to invoke or listen to a global unity event does so through the Event $$anonymous$$anager. This comes with a number of benefits: - Classes decouple themselves from the other classes (Event$$anonymous$$anager itself becomes tightly coupled, but all the other classes are completely decoupled which is a worthwhile trade). - Neither the Invokers nor the listeners have to be instantiated in the proper order. - Adding new types of events is extremely quick to do by simply assigning a unique string name
and if I want to apply events locked to a specific instance, I can simply wrap a UnityEvent inside an interface (usually as a property) to maintain decoupling