 |
Exercise 3
using System; using System.Collections.Generic; using System.Text;
namespace Plato.Core { /// <summary> /// The set of entities. /// </summary> public class Brain { // The set of entities. private Dictionary<string, Entity> entities;
public Brain() { entities = new Dictionary<string, Entity>(); }
/// <summary> /// Create/add a new entity. /// </summary> /// <param name="id">The entity's internal ID.</param> /// <returns>The new entity.</returns> public IEntity CreateEntity(string id) { if (entities.ContainsKey(id)) { throw new Exception(String.Format("Entity [{0}] already exists.", id)); }
Entity newEntity = new Entity(id); entities.Add(id, newEntity);
return newEntity; }
/// <summary> /// Returns an entity given its ID. /// </summary> /// <param name="id">The entity's internal ID.</param> /// <returns>The entity.</returns> public IEntity Get(string id) { if (!entities.ContainsKey(id)) { throw new Exception(String.Format("Entity [{0}] doesn't exist.", id)); }
return entities[id]; }
/// <summary> /// Create/add a new relationship. /// </summary> /// <param name="entity1">The first entity.</param> /// <param name="entity2">The second entity.</param> /// <param name="relation">Defines how the entities are related.</param> /// <param name="args">Optional argument entities.</param> /// <param name="directed">Whether or not the relationship is directed.</param> /// <returns>The new relationship.</returns> public IRelationship CreateRelationship(IEntity entity1, IEntity relation, IEntity entity2, IEntity[] args, bool directed) { Relationship newRelationship = new Relationship(entity1, relation, entity2, args, directed); entity1.AddRelationship(newRelationship); return newRelationship; }
public IRelationship CreateRelationship(IEntity entity1, IEntity relation, IEntity entity2, bool directed) { return CreateRelationship(entity1, relation, entity2, null, directed); }
public IRelationship CreateRelationship(IEntity entity1, IEntity relation, IEntity entity2) { return CreateRelationship(entity1, relation, entity2, null, true); }
public IRelationship CreateRelationship(IEntity entity1, IEntity relation, IEntity entity2, IEntity[] args) { return CreateRelationship(entity1, relation, entity2, args, true); } }
/// <summary> /// An entity. /// </summary> internal class Entity : IEntity { private string id;
// Relationships, organized by target entity. private Dictionary<string, List<IRelationship>> relatedEntities;
// Relationships, organized by relation type. private Dictionary<string, List<IRelationship>> relationTypes;
// Values which have been assigned to properties private Dictionary<string, List<IEntity>> values;
public Entity(string id) { this.id = id; this.values = new Dictionary<string, List<IEntity>>(); this.relatedEntities = new Dictionary<string, List<IRelationship>>(); this.relationTypes = new Dictionary<string, List<IRelationship>>(); }
/// <summary> /// The ID by which the entity is internally referenced. /// </summary> public string Id { get { return id; } set { id = value; } }
/// <summary> /// Add a relationship between this entity and another entity. /// </summary> /// <param name="relationship">The relationship.</param> public void AddRelationship(IRelationship relationship) { if (relationship.Entity1.Id != this.id) { throw new ArgumentException("The relationship's source entity " "doesn't match this entity."); }
List<IRelationship> list; string entity2 = relationship.Entity2.Id; string relationType = relationship.Relation.Id;
// Update relationships, ordered by target entity and // relation type.
if (relatedEntities.ContainsKey(entity2)) { // One or more relationships already exist with this // entity. Add the new relationship. relatedEntities[entity2].Add(relationship); } else { // No relationships yet exist with this entity. // Add this first relationship. list = new List<IRelationship>(); list.Add(relationship); relatedEntities[entity2] = list; }
if (relationTypes.ContainsKey(relationType)) { // One or more relationships already exist for this // relation type. Add the new relationship. relationTypes[relationType].Add(relationship); } else { // No relationships yet exist for this relation type. // Add this first relationship. list = new List<IRelationship>(); list.Add(relationship); relationTypes[relationType] = list; } }
/// <summary> /// Assign a value to a property. /// </summary> /// <param name="property">The property.</param> /// <param name="value">The value.</param> public void Set(IEntity property, IEntity value) { if (!HasA(property)) { throw new PropertyNotFoundException( String.Format("Entity [{0}] does not have property [{1}].", Id, property.Id), this, property); }
List<IEntity> list = new List<IEntity>(); list.Add(value);
// Overwrite any existing value values[property.Id] = list; }
/// <summary> /// Get a property's value. /// </summary> /// <param name="property">The property.</param> /// <returns>The value if set, or null otherwise.</returns> public IEntity Get(IEntity property) { if (!HasA(property)) { throw new PropertyNotFoundException( String.Format("Entity [{0}] does not have property [{1}].", Id, property.Id), this, property); }
if (values.ContainsKey(property.Id)) { return values[property.Id][0]; } else { return null; } }
/// <summary> /// Perform a depth-first search on is_a relationships to determine whether /// an entity has a direct or indirect is_a relationship with another entity. /// </summary> /// <param name="type">The type.</param> /// <returns>True if the relationship exists.</returns> public bool IsA(IEntity type) { if (Id == type.Id) { return true; } else { // Depth-first, recursive search foreach (List<IRelationship> relationshipList in relatedEntities.Values) { foreach (IRelationship relationship in relationshipList) { if (relationship.Relation.Id == "is_a") { if (relationship.Entity2.IsA(type)) { return true; } } } } }
return false; }
/// <summary> /// Perform a depth-first search on the is_a relationship followed by /// a depth of one search of the has_a relationship. /// </summary> /// <param name="type">The property.</param> /// <returns>True if the relationship exists.</returns> public bool HasA(IEntity property) { // If an immediate relationship does not exist, consider // the has_a relationships of is_a relatives. if (ImmediateHasA(property)) { return true; }
// Otherwise, consider has_a relationships of is_a // relatives.
// Depth-first, recursive search foreach (List<IRelationship> relationshipList in relatedEntities.Values) { foreach (IRelationship relationship in relationshipList) { if (relationship.Relation.Id == "is_a") { if (relationship.Entity2.ImmediateHasA(property)) { return true; } } } }
return false; }
/// <summary> /// Examine this entity's immediate has_a relationships. /// </summary> /// <param name="entity">The entity.</param> /// <returns>True if the relationship exists.</returns> public bool ImmediateHasA(IEntity property) { if (relationTypes.ContainsKey("has_a")) { List<IRelationship> relationshipList = relationTypes["has_a"];
foreach (IRelationship relationship in relationshipList) { if (relationship.Entity2.Id == property.Id) { return true; } } }
return false; } }
/// <summary> /// A relationship. /// </summary> internal class Relationship : Entity, IRelationship { // The 'source' entity private IEntity entity1;
// The target entity private IEntity entity2;
private IEntity relation; private IEntity[] args; private bool directed;
public Relationship(IEntity entity1, IEntity relation, IEntity entity2, IEntity[] args) : base(null) { if (entity1 == null) { throw new ArgumentNullException("entity1"); } if (entity2 == null) { throw new ArgumentNullException("entity2"); } if (relation == null) { throw new ArgumentNullException("relation"); }
this.entity1 = entity1; this.entity2 = entity2; this.relation = relation; this.args = args; directed = true;
// Create a reference from the first entity // to this relationship. entity1.AddRelationship(this);
}
public Relationship(IEntity entity1, IEntity relation, IEntity entity2, IEntity[] args, bool directed) : this(entity1, relation, entity2, args) { this.directed = directed; }
/// <summary> /// The first entity of the relationship. /// </summary> public IEntity Entity1 { get { return entity1; } }
/// <summary> /// The second Entity of the relationship. /// </summary> public IEntity Entity2 { get { return entity2; } }
/// <summary> /// The relation defines how the two entities relate. /// </summary> public IEntity Relation { get { return relation; } }
/// <summary> /// Optional entity arguments. /// </summary> public IEntity[] Args { get { return args; } }
/// <summary> /// Is the relationship directed? /// </summary> public bool Directed { get { return directed; } } }
public class PropertyNotFoundException : Exception { private IEntity entity; private IEntity property;
public PropertyNotFoundException(string message, IEntity entity, IEntity property) :base(message) { this.entity = entity; this.property = property; }
/// <summary> /// The entity to which the property was said to belong. /// </summary> public IEntity Entity { get { return entity; } }
/// <summary> /// The property. /// </summary> public IEntity Property { get { return property; } } }
}
|
|
|
|
 |