I have the structure Corporation / Company / Facility / Storage and only Storage could be part of Facility and Facility could be part of Company and Company part of Corporation. My main problem is that the code I need to add the corporation to itself works.
public class BusinessEntityData
{
public Guid ID { get; set; }
public Guid ParentID { get; set; }
public string Title { get; set; }
public string Number { get; set; }
public int Type { get; set; }
}
public static class Context
{
public static List BusinessEntityList { get; set; } = new List();
}
This is what the data entity looks like and the context is for the static list that I use for testing.
public interface IBusinessEntity
{
string Title { get; set; }
string Number { get; set; }
int Type { get; set; }
List GetChildren(string number);
void AddBusinessEntity(IBusinessEntity entity);
void Remove(IBusinessEntity entity);
void Validate(IParentValidationVisitor visitor, BusinessEntityData data);
}
public interface IValidationVisitor
{
void VisitCompany(BusinessEntityData data);
void VisitFacility(BusinessEntityData data);
void VisitCorporation(BusinessEntityData data);
void VisitStorage(BusinessEntityData data);
}
These are both interfaces that I use for the VisitorPattern and Composite.
Here I implement the interface. Suppose that the numbers between all objects are unique.
public abstract class AbstractBusinessEntity : IBusinessEntity
{
public string Title { get; set; }
public string Number { get; set; }
public int Type { get; set; }
public AbstractBusinessEntity(string number, string title)
{
Title = title;
Number = number;
}
public void AddBusinessEntity(IBusinessEntity entity)
{
var currentElement = Context.BusinessEntityList.FirstOrDefault(x => x.Number == this.Number);
var visitor = new ParentValidationVisitor();
var data = new BusinessEntityData()
{
ID = Guid.NewGuid(),
Title = entity.Title,
Number = entity.Number,
Type = entity.Type,
ParentID = currentElement == null ? Guid.Empty : currentElement.ID
};
Validate(visitor, data);
Context.BusinessEntityList.Add(data);
}
public List GetChildren(string number = null)
{
if (number == null)
number = this.Number;
List list = new List();
var currentElement = Context.BusinessEntityList.FirstOrDefault(x => x.Number == number);
if (currentElement == null)
return new List();
var children = Context.BusinessEntityList.Where(x => x.ParentID == currentElement.ID);
foreach(var item in children)
{
list.Add(item);
list.AddRange(GetChildren(item.Number));
}
return list;
}
public void Remove(IBusinessEntity entity)
{
var result = Context.BusinessEntityList.FirstOrDefault(x => x.Number == entity.Number);
if (result == null)
return;
Context.BusinessEntityList.Remove(result);
}
public abstract void Validate(IValidationVisitor visitor, BusinessEntityData data);
}
My classes Facility
. Corporation
. Company
and Storage
inherit this AbstractBusinessEntity
and implement only the Validate method, where I call a separate visitor method.
This is what the visitor looks like:
public class ValidationVisitor : IValidationVisitor
{
public void VisitCorporation(BusinessEntityData data)
{
if (data.Type == (int)Helper.BusinessEntityType.Corporation)
return;
if (data.Type == (int)Helper.BusinessEntityType.Company)
return;
throw new BusinessEntityValidationException("You can add only Companies to Corporation");
}
public void VisitCompany(BusinessEntityData data)
{
if (data.Type == (int)Helper.BusinessEntityType.Facility)
return;
throw new BusinessEntityValidationException("You can add only Facility to Companies");
}
public void VisitFacility(BusinessEntityData data)
{
if (data.Type == (int)Helper.BusinessEntityType.Storage)
return;
throw new BusinessEntityValidationException("You can add only Storage to Facility");
}
public void VisitStorage(BusinessEntityData data)
{
throw new BusinessEntityValidationException("You can't add any business entity to Storage");
}
}
Should the confirmation be in the visitor's pattern?
What's really strange to me is that when I start the program for this code to work properly, I need to add corporation to itself to add the first element in the collection.
Corporation corporation = new Corporation("Corporation", "Corporation TEst");
corporation.AddBusinessEntity(corporation);
var company1 = new Company("Company1", "Company1");
var company2 = new Company("Company2", "Company2");
var company3 = new Company("Company3", "Company3");
corporation.AddBusinessEntity(company1);
corporation.AddBusinessEntity(company2);
corporation.AddBusinessEntity(company3);
I am not sure if this is the right way. Another possibility is that the company is out of the tree, but I am not sure if this is correct as business logic. What could be a better approach?
Here's github demo for the full code of the example.
Here's DotNetFiddle for the full example. (not really readable)