- Home /
Instantiating an object from its interface
I have created a generic object pooling script which I intend to reuse. From a design standpoint, I thought it would be best to go with a Pool class, which can be inherited from, and an IPoolable interface, which specifies the contract that poolable objects would have to fulfill. Here are the relevant parts:
public interface IPoolable {
bool IsIncarnate();
void Incarnate(Vector3 position, Quaternion rotation, Vector3 scale); //Called when the object is checked out from the pool
void Relinquish(); //Called to return the object to the pool.
}
and
public class Pool : MonoBehaviour {
public int count = 256;
public IPoolable pooledObj;
public List<IPoolable> allObj;
//snip some irrelevant stuff
protected virtual void Start() {
allObj = new List<IPoolable>(count);
InstantiatePool();
}
protected virtual void InstantiatePool() {
for (int i = 0; i < count; i++) {
allObj.Add((IPoolable)Instantiate(pooledObj));
allObj[i].Relinquish();
}
}
public IPoolable GetNext() {
IPoolable next = allObj.Find(x => !x.IsIncarnate());
//snip behavior of what to do when full
return next;
}
}
The issue I was having was with this line:
allObj.Add((IPoolable)Instantiate(pooledObj));
The problem is that Instantiate requires a UnityEngine.Object. IPoolable is an interface, so it seems that, even though it is always attached to an Object, which can be instantiated, the compiler doesn't know that.
I did come up with a solution, which was to change IPoolable from an interface into an abstract class, called Poolable:
public abstract class Poolable : MonoBehaviour {
public virtual bool IsIncarnate { get { return gameObject.activeInHierarchy; } }
public abstract void Incarnate(Vector3 position, Quaternion rotation, Vector3 scale); //Called when the object is checked out from the pool
public virtual void Relinquish() { //Called to return the object to the pool.
gameObject.SetActive(false);
}
}
Because this class inherits from MonoBehavior, it fulfills the condition that Instantiate must accept an Object argument. However, from a design perspective this feels wrong - it seems to me that I really only want to specify a contract in Poolable, so I should be using an interface. What would happen, for example, if I need an object to be both poolable and inherit from another MonoBehavior? This solution would make that impossible, because only one class can be inherited from - although multiple interfaces can be implemented.
So my question - is there a way to make that problem line work? A way that I can instantiate the object even though I have a handle on it by the IPoolable interface?
Answer by FortisVenaliter · May 04, 2016 at 06:43 PM
This is not a clean solution, but if you can be 100% sure that every IPoolable will be derived from MonoBehaviour in some way, you can use it:
allObj.Add((IPoolable)Instantiate((UnityEngine.Object)((object)pooledObj)));
It's basically operating on that assumption to cast spoof the instantiator.
Answer by NoseKills · May 04, 2016 at 07:11 PM
It's a matter of taste but... Your interface acts as a contract to guarantee its implementations are suitable for pooling. However the interface can not guarantee that the implementing class can be instantiated. If it really is a requirement that IPoolables have to be Instantiate()d, it would maybe make sense to make it a part of the contract: i.e. add a function UnityEngine.Object GetObjectToInstantiate();
or such to you interface and most of the time make its implementations return this
.
Answer by JoshuaMcKenzie · May 21, 2016 at 04:51 AM
There's actually a very cool way of doing it. It keeps things super decoupled (which is surprising given with what singletons are), take a look at the thread i made on the forums
Code Design: Abstracting Singletons
it's a little secret, but you can actually make extension methods for interfaces!
which is super cool cause you can do something like make a singleton class and have your entire project use it without ever calling the concrete class.
Your answer
Follow this Question
Related Questions
An OS design issue: File types associated with their appropriate programs 1 Answer
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
How to choose base class to make Inherit C# 2 Answers
C# inheritance advice 2 Answers