Logo

Főoldal

Blog

Elmélet

3D Studio

Adatvédelmi nyilatkozat

GY.I.K.

Házirend

Szerző: Marosi Csaba / marosi.csaba@3d-studio.hu

DiscordGitHubLinkedIn
Developedia
Developedia
/Elmélet
Elmélet
/Önregisztráció
Önregisztráció
Önregisztráció

Önregisztráció

Ha egy darab létezik egy komponensből, akkor az elérhető a FindObjectOfType() metódussal.

Ennél jóval gyorsabb megoldást ad a Singleton vagy a ServiceLocator pattern: Látsd: Singleton és Service LocatorSingleton és Service Locator

Ehhez hasonlóan egy sok példányban létező komponens tömbjét megkaphatjuk a FindObjectsOfType() lekérdezni, de tudjuk ezt a lekérdezést jóval gyorsabbá is tenni saját kóddal.

‣

Ehhez egy adott típushoz létre kell hoznunk egy statikus listát és gondoskodnunk róla, hogy az egyes objektumok létrejöttükkor és megszűnésük idejében regisztrálják majd töröljék magukat ebből a listából.

Erre használható az Awake() és az OnDestroy() MonoBehaviour üzenetmetódusok.

Ha csak az aktív objektumokat szeretnénk számon tartani, akkor pedig az OnEnable() és az OnDisable() eljárások használatosak.

Példakód:

class TestComponent : MonoBehaviour 
{
	static readonly List<TestComponent> activeTestComponents = new();
	public static IReadOnlyList<TestComponent> AllActives => activeTestComponents;

	void OnEnable()
	{
		activeTestComponents.Add(this);
	}
		void OnDisable()
	{
		activeTestComponents.Remove(this);
	}
}
// Példa a használatára: Végigiterálás az összes aktív TestComponent-en

foreach(TestComponent testComponent in TestComponent.AllActives)
{
	//...
}

A lekérdezéshez használtam a IReadOnlyList interface-et, ami a listának csak lekérdező metódusait tartalmazza. Segítségével elérhető, hogy kívülről semmiképp ne lehessen módosítani a listát.

Object Finder

A Singleton-t leválthattuk egy Service Locator-ral annak érdekében, hogy támogatni tudjuk az absztrakciót (interface-eket és absztrakt osztályokat).

Ennek mintájára a több számban létező objektumokra is létrehozhatunk egy ObjectFinder-t, ami hasonló módon működik majd, mint a Service Locator, de ahelyett, hogy minden típusból egyet tárolnánk el, egy egész listát fogunk.

Mindezt egy statikus Dictionary-val végezzük, amiben egy-egy típushoz társítunk egy listát az adott típus elemeiből a következőképp:

Használat:

// Típus definíciók és regisztráció a ComponentLocator-ba:

interface IExampleInterface { /* ... */ }

class TestComponent : MonoBehaviour, IExampleInterface
{
	void Awake()
	{
		ObjectFinder.Add<IExampleInterface>(this); 
	}

	void OnDestroy()
	{
		ObjectFinder.Remove<IExampleInterface>(this); 
	}
}
//Lekérdezés:

IReadOnlyList<IExampleInterface> all = ObjectFinder.GetAll<IExampleInterface>();

Ahogy a saját Sercice Locator a FindObjectOfType-ot tudja jóval optimálisabban leváltani, úgy az imént megírt megoldás gyakorlatilag a FindObjectsOfType metódust helyettesíti.

Az ObjectFinder előnyei a FindObjectsOfType -hoz képest:

  • Képes abstrakció (interface és absztrakt osztály)alapján keresni
  • Nem termel memóriaszemetet
  • Futása összehasonlíthatatlanul gyorsabb

Alább egy kísérlet eredménye látható, ahol 5000 objektumot kerestem meg 5000-szer a FindObjectsOfType valamint a fenti saját ObjectFinder segítségével:

image

Az ObjectFinder hátránya a FindObjectsOfType -hoz képest:

  • A regisztrációt és unregisztrációt manuálisan kell végezni.
static class ObjectFinder
{
	static readonly Dictionary<Type, List<object>> instances = new();

	public static void Add<T>(T component)
	{
			Type type = typeof(T);
			if (!instances.TryGetValue(type, out List<object> list))
			{
				list = new List<object>();
				instances.Add(type, list);
			}
	
			list.Add(instance);
	}

	public static void Remove<T>(ComponentExample component)
	{
			Type type = typeof(T);
			if (components.TryGetValue(type, out List<object> list))
				list.Remove(component);
	}
	
	public static IReadOnlyList<T> GetAll<T>()
	{
			if (!instances.TryGetValue(typeof(T), out List<object> list))
			{
				list = new List<object>();
				instances.Add(typeof(T), list);
			}
			return list as IReadOnlyList<T>;
	}
}