C# How to implement a main object with additional objects?
I have a main object which has some prop开发者_运维百科erties and methods. This object can have multiple parts. These parts are required. The amount of these parts is variable.
Each part has different properties and is referenced to the main object.
To accomplish this in my GUI I have a tabcontrol. The first tab is the main object. The other tabs describes the main object further. These 'other' tabs are the parts I mentioned above.
I am trying to design an architecture, but I can't figure I hope yoy can help me.
As suggested from the answers, the part-tabs inherit from an interface. But how does the main know about it's parts? The parts can't be hardcoded because it is variable. To hardcode the parts is a violation of the OCP principle.
Also, when loading the main object, again, how does it knows about it parts? I have to 'register' them somewhere, but where?
Create interface for your parts, that can have reference to main object. And main object will contain collection of parts as Collection<IPart>
class MainObject
{
Collection<IPart> Parts {get;set;}
}
interface IPart
{
MainObject MainObject {get;set;}
}
class SomePartImpl : IPart
{
//properties of this IPart implementation
}
This classes is entities. Your data service must implement logic for saving and cascade operations. Sample wcf service(from my project):
[EnableClientAccess]
public class ModelService : LinqToEntitiesDomainService<dpirtEntities>
{
public void InsertZone(Zone zone)
{
if ((zone.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(zone, EntityState.Added);
}
else
{
this.ObjectContext.Zones.AddObject(zone);
}
}
public void UpdateZone(Zone currentZone)
{
Zone originalZone = this.ChangeSet.GetOriginal(currentZone);
if ((currentZone.EntityState == EntityState.Detached))
{
if (originalZone != null)
{
this.ObjectContext.Zones.AttachAsModified(currentZone, originalZone);
}
else
{
this.ObjectContext.Zones.Attach(currentZone);
}
}
foreach (Document doc in this.ChangeSet.GetAssociatedChanges(currentZone, o => o.Documents))
{
ChangeOperation op = this.ChangeSet.GetChangeOperation(doc);
switch (op)
{
case ChangeOperation.Insert:
if ((doc.EntityState != EntityState.Added))
{
if ((doc.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(doc, EntityState.Added);
}
else
{
this.ObjectContext.AddToDocuments(doc);
}
}
break;
case ChangeOperation.Update:
this.ObjectContext.Documents.AttachAsModified(doc, this.ChangeSet.GetOriginal(doc));
break;
case ChangeOperation.Delete:
if (doc.EntityState == EntityState.Detached)
{
this.ObjectContext.Attach(doc);
}
this.ObjectContext.DeleteObject(doc);
break;
case ChangeOperation.None:
break;
default:
break;
}
}
}
public void DeleteZone(Zone zone)
{
if ((zone.EntityState == EntityState.Detached))
{
this.ObjectContext.Zones.Attach(zone);
}
this.ObjectContext.Zones.DeleteObject(zone);
}
}
Have a List
or Dictionary
in your Main
class and store the references to the different objects.
For example:
All the tabs implement an interface called IScreenTab
.
class MainTab : IScreenTab
{
// Store a map of scree name to screen object
// You can also just use a List<IScreenTab>
private Dictionary<string, IScreenTab> m_OtherScreens;
// Your implementation goes here
public MainTab(){ }
public MainTab(List<IScreenTab> screenTabList){ }
public AddTab(string screenName, IScreenTab screenTabObj){ }
}
I've done something similar in the past, and I decoupled my GUI from my domain design by using an IoC container. In my code I used StructureMap, which was very easy to adopt.
I had exactly the same setup in which there was an 'editor' which contained a number of 'tabs'. Each tab could either contain some different view of my 'object' or it could show an item from collections stored within the 'object'. So there were a number of static and variable tabs.
So, I needed two things. 1. A way to create an editor, with the correct number of tabs. 2. A way to create the tab, plus all it's controls.
So, I created an interface for each, which looked loosely like this.
public interface IEditorFactory<TObject>
{
Editor CreateEditor(TObject instance);
}
public interface ITabEditorFactory<TObject>
{
void CreateTab(TObject instance, Editor parent);
}
I'll leave Editor up to your imagination. By in my app it was a custom UserControl, with various features and behaviour.
Next, imagine we had a Person, who had personal info, an Address an multiple contracts.
public class Person
{
public string Title { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public string EmployeeNumber { get; set; }
public string NationalInsuranceNumber { get; set; }
public Address Address { get; set; }
public IEnumerable<Contract> Contracts { get; }
}
My app wanted to display one 'Personal Details' tab, one 'Employment' tab, one 'Address' tab and multiple 'Contract' tabs.
I implemented the following. public class PersonalTab : ITabEditorFactory { ... } public class EmployeeTab : ITabEditorFactory { ... } public class AddressTab : ITabEditorFactory { ... } public class ContractTab : ITabEditorFactory { ... }
Notice how #1 and #2 implement the same ITabEditorFactory. That's because they both display different aspects of the Person.
But before I had implemented those I implemented the PersonEditor public class PersonEditor : IEditorFactory { ... } It was good that I implemented this first, as it forced de-coupling my editor factory from all the tab factories. I wouldn't accidentally slip in any references to concrete classes. My editor factory just knew how to ask for a ITabEditorFactory<> for the Person, Address and Contract classes.
My final solution was a little more complicated than I outlined above, as it also covered Editor re-use for different instances, how to handle multiple (or no) tab editors for any a single class, and being able to define security on a tab-by-tab basis.
The end result was that I had a GUI model that was decoupled from my domain, and was extensible without requiring me to change a single line of existing code.
Lovely jubbly.
精彩评论