As the name suggests, object managers manage objects, but this obvious statement leaves out details that this article endeavors to describe – so what are these details? First, the name object manager isn’t particularly helpful. The name leaves out the specifics regarding what types of objects are managed, how these types are managed, and how one might implement such a manager.
Regarding the types of objects that can be managed, an object manager has no inherent restrictions, but a developer might want to impose some anyway. For example, a developer might consider creating – to limit the types of objects that a manager can manage – an interface (e.g. IManagedObject) that indicates that an object is managed. Moreover, a manager frequently allows coders to find a specific object – so managed objects should also be limited to types that are uniquely identifiable – types that extend a special interface (e.g. IUnique) indicating that an object is unique. Such restrictions are prudent to manage objects effectively.
However, a prudent design of managed objects does not describe how an object manager manages its objects. Fortunately, this ambiguity can be made removed. Put simply, object managers perform only a few simple tasks: addition, removal, search, and retrieval of the collection. Addition adds objects to the manager. Removal removes objects from the manager. Search finds a specific object, if it exists. Retrieval of the collection grabs the collection of managed objects. All of these tasks must be handled by every object manager.
After reading the previous paragraph, however, some coders might ask – “Shouldn’t more functionality be included in a manager?” While quite keen, this question conflates what an object manager does with its uses inside of an application. While a given object manager has many uses, only a few of them are endemic to managing objects. The rest of the uses can be implemented by using the functionality described in the previous paragraph. For example, a manager’s collection can be retrieved and the data from each object can used to search inside of another manager for one of its objects. Such a composite function does not need to be implemented inside either manager – because the standard management functions can be used to implement the composite function.
However, knowing what a manager manages and what a manager does is insufficient to implement an actual manager – a problem that a manager paradigm helps to eliminate. Such a paradigm is detailed, briefly, in the subsequent code. By extending it, one can construct a specific manager.
public interface ICodExploUnique
{
}
public interface ICodExploManagedObject<ObjectType> : ICodExploUnique
where ObjectType : ICodExploManagedObject<ObjectType>
{
ICodExploManager<ObjectType> Manager { get; set; }
}
public interface ICodExploManager<ObjectType>
where ObjectType : ICodExploManagedObject<ObjectType>
{
IList<ObjectType> Objects { get; }
void addObject(ObjectType obj);
void clearObjects();
}
public interface ICodExploKeyed : ICodExploUnique
{
String Key { get; set; }
}
public interface ICodExploKeyedManagedObject<ObjectType> : ICodExploManagedObject<ObjectType>, ICodExploKeyed
where ObjectType : ICodExploKeyedManagedObject<ObjectType>
{
}
public interface ICodExploKeyedManager<ObjectType> : ICodExploManager<ObjectType>
where ObjectType : ICodExploKeyedManagedObject<ObjectType>
{
ObjectType findObject(String key);
void removeObject(String key);
}
public abstract class BaseKeyedManager<ObjectType> : ICodExploKeyedManager<ObjectType>
where ObjectType : ICodExploKeyedManagedObject<ObjectType>
{
#region Data
private IList<ObjectType> objects;
#endregion
#region Constructors
public BaseKeyedManager()
{
Objects = new List<ObjectType>(0);
}
#endregion
#region ICodExploKeyedManager
public ObjectType findObject(string key)
{
if (key == null)
{
throw new CodExploManagerException("An object cannot be found without a key");
}
else { }
ObjectType found = default(ObjectType);
foreach (ObjectType obj in objects)
{
if (obj.Key != null)
{
if (obj.Key == key)
{
found = obj;
break;
}
else { }
}
else { }
}
return found;
}
public void removeObject(string key)
{
ObjectType found = findObject(key);
if (found != null)
{
objects.Remove(found);
found.Manager = null;
if (found is ICodExploDestroyable)
{
((ICodExploDestroyable)found).destroy();
}
else { }
}
else { }
}
public IList<ObjectType> Objects
{
get { return objects; }
private set { objects = value; }
}
public void addObject(ObjectType obj)
{
if (obj == null)
{
throw new CodExploManagerException("A null object cannot be added");
}
else { }
obj.Manager = this;
if (obj is ICodExploInitializeable)
{
((ICodExploInitializeable)obj).init();
}
else { }
objects.Add(obj);
}
public void clearObjects()
{
objects.Clear();
}
#endregion
}