What do I lose by not implementing the Component and treating everything as a Composite?
I have given up the implementation for Leaf node:
I.e.
class Component : IComponent
{
/*...*/
}
Now plz take a look at my code.
public interface IComponent
{
int ID { get;set; }
string Name { get;set;}
void Add(IComponent item);
void Remove(IComponent item);
List<IComponent> Items { get; }
void Show();
}
public class Composite : IComponent
{
private int _id;
public int ID
{
get { return _id; }
set { _id = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
public Composite(int id, string name)
{
_id = id;
_name = name;
}
private List<IComponent> _items = new List<IComponent>();
public void Add(IComponent item)
{
_items.Add(item);
}
public void Remove(IComponent item)
{
_items.Remove(item);
}
public List<IComponent> Items
{
get
{
return new List<IComponent>(_items);
}
}
public void Show()
{
Console.WriteLine("ID=" + _id + "; Name=" + _name);
}
}
class Program
{
static void Main(string[] args)
{
IComponent root = new Composite(1, "World");
IComponent asia = new Composite(2, "Asia");
IComponent europe = new Composite(3, "Europe");
root.Add(asia);
root.Add(europe);
asia.Add(new Composite(4, "China"));
asia.Add(new Composite(5, "Japan"));
europe.Add(new Composite(6, "Germany"));
europe.Add(new Composite(7, "Russia"));
root.Show();
Program.Traverse(root.Items);
Console.ReadLine();
}
static void Traverse(List<IComponent> items)
{
foreach (IComponent c in items)
{
c.Show();
Traverse(c.Items);
}
}
}
What is wrong with this approach of Composite Pattern? What kind of problem can I face with this type of design?
You're giving up any chance to subclass the "Leaf", if it turns out you have different types of "nodes" you'll probably end up polluting the structure in one way or another. And you're violating the single responsipbility priciple too. It is very easy to get pollution of all sorts with the composite pattern, and I think it always pays off to do it cleanly.
If I understand correctly, there is not a concept of leaf node, in composite pattern.
Any node which doesn't have a child is automatically a leaf node.
Looking at your code, this is not needed
private List<IComponent> _items = new List<IComponent>();
public void Add(IComponent item)
{
_items.Add(item);
}
public void Remove(IComponent item)
{
_items.Remove(item);
}
public List<IComponent> Items
{
get
{
return new List<IComponent>(_items);
}
}
I am looking at ControlCollection class, which is a property of Control class.
Though not exactly composite pattern, every Control knows of who it is child of, which is missing from your code.
My understanding could be totally off. Experts can correct me :)
EDIT: I looked at the dofactory reference, which seems to have a concept of leaf class in composite pattern. My mistake of totally not understanding it.
But I would suggest you look at the way .net implements kind of composite pattern by having Control, ControlCollection & related classes.
EDIT2: If the code above is to be removed, you will have another class which is a collection of IComponent which you can expose by using a property IList<IComponent>, which in turn will have methods to add/remove.
EDIT3: .net doesn't restrict the user from adding child controls in the above class hierarchy. You could use the dofactory way of design, if you want to restrict the ability for someone to define a leaf node (one that doesn't have any child node).
EDIT4: The way dofactory code shows, you will have to define a leaf node, which will throw NotImplementedException for Add/`Remove'.
Related
Is there an elegant (or any) way to achieve following in C#?
Let's have a class ItemBase (further derivable to Item1, Item2...), which does not allow direct instantiation (non-public construction) - to prevent user to create any 'untracked' instance of Item*.
Let's have a non-static class Manager, whose instances (multiple ones allowed) only can create and provide instances of Item* (because they keep track of produced instances and do some additional work).
Let's have an optional requirement: The Manager instances would like to manipulate non-public members of the managed Item instances (similar like the Manager would be a friend of Item*).
It would be nice if the Manager is not forced to be derivation of Item*.
It would be nice if there is as little reflection as possible.
Notes:
If possible, please consider this as a question raising from process of thinking how to implement particular problem solution in a best and elegant way. I would like it to be general and no, I don't have sources and yes, I have already tried some variants, but none of them satisfied my needs. Thank you.
As far as I know, there is no acceptable friend alternative (any of internal and InternalsVisibleToAttribute seems to be good), so the ItemBase just provides the 'special' (but public) modification methods and the user must be aware, these methods are not for him :o(
I like this solution, but I'm not able to invent, how to allow multiple Manager instances using it.
I think this might answer your problem :
public class ItemBase
{
protected ItemBase()
{
}
public void PublicMethod() { }
public int PublicProperty { get; set; }
}
public class Factory
{
private class PrivateItemBase : ItemBase
{
public void PrivateMethod() { }
public int PrivateProperty { get; set; }
}
public Factory(int id)
{
}
public IEnumerable<ItemBase> Items { get; private set; }
public ItemBase CreateItem()
{
PrivateItemBase rValue = new PrivateItemBase();
rValue.PrivateMethod();
rValue.PrivateProperty = 4;
return rValue;
}
}
Ok, giving up. If this might help to fully understand the purpose, there is the less bad solution I've (currently) ended up. Passing the creation functions is done via static constructors (which are not accessible by the users), unfortunately the ugly thing is their invocation...
Any idea how to make it better?
The item definitions:
namespace SpecialFactory
{
public enum ItemType
{
Item1,
Item2,
// ... Anyone deriving the Item* should add an item here
}
public abstract class ItemBase
{
public abstract ItemType Id {get;}
public static void RegisterAllCreators()
{
// Force static constructors invocation
var it = Item1.ClassId | Item2.ClassId; // Anyone deriving the Item* should ensure invocation of Manager.RegisterCreator
}
}
public class Item1 : ItemBase
{
static Item1()
{
Manager.RegisterCreator(ItemType.Item1, () => new Item1());
}
protected Item1()
{
}
public static ItemType ClassId => ItemType.Item1;
public override ItemType Id => ClassId;
}
public class Item2 : ItemBase
{
static Item2()
{
Manager.RegisterCreator(ItemType.Item2, () => new Item2());
}
protected Item2()
{
}
public static ItemType ClassId => ItemType.Item2;
public override ItemType Id => ClassId;
}
}
The manager:
namespace SpecialFactory
{
public class Manager
{
static Manager()
{
ItemBase.RegisterAllCreators();
}
protected static Dictionary<ItemType, Func<ItemBase>> creators = new Dictionary<ItemType, Func<ItemBase>>();
protected readonly List<ItemBase> managedItems = new List<ItemBase>();
protected ItemBase CreateItem(ItemType type)
{
ItemBase item = null;
if (creators.ContainsKey(type))
{
if ((item = creators[type]()) != null)
managedItems.Add(item);
}
return item;
}
public static void RegisterCreator(ItemType type, Func<ItemBase> creator)
{
if (!creators.ContainsKey(type))
creators[type] = creator;
}
public Manager()
{
}
public ItemBase Test(ItemType type)
{
// var notAllowed = new Item1();
var allowed = CreateItem(type);
return allowed;
}
}
}
The test:
namespace SpecialFactory
{
class Program
{
static void Main(string[] args)
{
var m1 = new Manager();
var m2 = new Manager();
var i1 = m1.Test(ItemType.Item1);
var i2 = m2.Test(ItemType.Item2);
}
}
}
I created a base class ("Element") and a base list class ("Elements") as generic class.
The generic list class should only be able to contain classes, which are of Type "Element" of derived from "Element".
The "Element" class should own a "ParentRoot" property, which should contain the base list class ("Elements")!
public class Element
{
public Elements<Element> ParentRoot { get; set; }
}
public class Elements<T> : List<T> where T : Element
{
}
Now i create two classes and two list classes which are derived form the classes above. But i'm failing on setting the "ParentRoot" property:
public class Ceiling : Element
{
public Ceiling(Ceilings parent)
{
Parent = parent;
ParentRoot = parent;
}
public Ceilings Parent { get; set; }
}
public class Ceilings : Elements<Ceiling>
{
}
public class Wall : Element
{
public Wall(Walls parent)
{
Parent = parent;
ParentRoot = parent;
}
public Walls Parent { get; set; }
}
public class Walls : Elements<Wall>
{
}
I get two errors at:
ParentRoot = parent;
Cannot implicitly convert type "Ceilings" to "Elements"
Cannot implicitly convert type "Walls" to "Elements"
Is there a solution for this problem?
Thanks for any help!
EDIT:
OK, i have to be a bit more specific.
I expanded the code a bit:
public class Room
{
public Room(Rooms parent)
{
Parent = parent;
}
public Rooms Parent { get; set; }
}
public class Rooms : List<Room>
{
}
public class Element
{
public Elements<Element> ParentRoot { get; set; }
public Rooms FindRoomsToElement()
{
Rooms rooms = new Rooms();
foreach (Room room in ParentRoot.Parent.Parent)
{
// Do stuff here
// if i rename the "ParentRoot" property to "Parent" and make it "virtual",
// and the other properties overwrite it with the "new" key, then this will
// get a null exception!
// i haven't testet it, but i think abstrakt will bring the same/similar result
// if i make the "ParentRoot" property IEnumerable, then there will no
// ParentRoot.Parent be available
}
return rooms;
}
}
public class Elements<T> : List<T> where T : Element
{
public Elements(Room parent)
{
Parent = parent;
}
public Room Parent { get; set; }
}
public class Ceiling : Element
{
public Ceiling(Ceilings parent)
{
Parent = parent;
//ParentRoot = parent;
}
public Ceilings Parent { get; set; }
}
public class Ceilings : Elements<Ceiling>
{
public Ceilings(Room parent) : base(parent)
{
}
}
public class Wall : Element
{
public Wall(Walls parent)
{
Parent = parent;
//ParentRoot = parent;
}
public Walls Parent { get; set; }
}
public class Walls : Elements<Wall>
{
public Walls(Room parent) : base(parent)
{
}
}
I hope this makes it more precise.
You aren't allowed to do this because if you could, you could put the wrong kind of elements into a List.
Elements<Ceilings> ceilings = someCeilings;
Elements<Element> parentRoot = ceilings; // Not allowed; imagine it is though.
Wall wall = someWall;
parentRoot.Add(wall); // Oops - we just added a wall to someCeilings!
If you can just treat the walls and/or ceilings as a sequence, you can do use IEnumerable<Element> instead (which works because IEnumerable<T> is "covariant"):
IEnumerable<Element> parentRoot = ceilings; // OK
This is OK because IEnumerable<Element> has no way to modify the original collection.
The problem is that, given a Generic<T> and a Child : Base, the type Generic<Base> is not a base of Generic<Child>. Generics are not base classes for their concrete implementations - they are templates out of which concrete implementations can be created and, in turn, the concrete implementations don't have a hierarchical relationship with each other. Consider the following snippet to understand why this is so:
var bananas = List<Banana>();
var fruits = (List<Fruit>)bananas; // If this was valid
fruits.Add(new Orange()); // Then this would be valid
// So we'd have an Orange to a list of runtime type List<Banana>
Therefore, your Elements<Element>, which is a case of the Generic<Base> I described above, cannot work as a base for the others. Your Ceilings and Walls are neither implicitly nor explicitly convertible to Elements<Element>.
A possible workaround would be to make ParentRoot a virtual or better yet an abstract property (if Element can be abstract) and override it in every subclass of Element to manually convert the Parent property to the Elements<Element> type.
For example, you could change your base and your generic like this:
public abstract class Element
{
public abstract Elements<Element> ParentRoot { get; }
}
public class Elements<T> : List<T> where T : Element
{
public Elements<T>() : base()
{
}
public Elements<T>(ICollection<T> collection) : base(collection)
{
}
}
Then, for every subclass, do the following:
public class Wall : Element
{
public Wall(Walls parent)
{
Parent = parent;
}
public Walls Parent { get; set; }
public override Elements<Element> ParentRoot
{
get
{
return new Elements<Element>(Parent);
}
}
}
Of course, modifications to the object returned by ParentRoot will not affect Parent. But this is okay semantically, because (as I described with the bananas and the oranges), you wouldn't want to accidentally add a Ceiling to a Walls just because it looks like an Elements<Element> at some point in the code.
Instead of this:
Parent = parent;
ParentRoot = parent;
try this
Parent = parent;
ParentRoot = new Elements<Element>();
ParentRoot.AddRange(parent);
My answer is based on seeing your code and think that you are trying to build a room with n elements.Using composition "has-a" or "is-part-of" and a freely take on factory pattern i think you can achieve this.In my code i based in a "room" "has" elements,if you think "elements" "is-a" "room"?...so elements is part of the room,and those elements in your case are ceiling and wall,now wall "is-a" element and ceiling "is-a" element of room,then naturaly i derived those from element but keeping a "reference" in room for element.About having a list of rooms i nested a private class,since there is no need(in my opinion) for wall or ceiling to have access to available rooms so in room class you do all the work.In room class i derived interface IRoomBuilder with proper methods,the ones uncommented are the ones you should use for creating for example a wall with some specifications and add to room,the commented ones are just for example purposes.I placed some user-side code for you to test.
public interface IRooms
{
List<Room> AvailableRooms();
}
public interface IRoomBuilder
{
//void MakeWall();
//void MakeWalls(int NumWalls);
//void MakeCeiling();
//void MakeCeilings(int NumCeilings);
void MakeElement(Element el);
void MakeElements(List<Element> elmts);
}
public class Room:IRoomBuilder
{
private List<Element> roomelements;
private readonly Rooms ShowRooms;
public List<Element> RoomElements
{
get { return roomelements; }
set { RoomElements.AddRange(value); }
}
public Room()
{
roomelements = new List<Element>();
ShowRooms = new Rooms();
}
public void MakeElement(Element el)
{
RoomElements.Add(el);
}
public void MakeElements(List<Element> elmts)
{
RoomElements.AddRange(elmts);
}
//public void MakeWall()
//{
// RoomElements.Add(Element.MakeElement(typeof(Wall).Name));
//}
//public void MakeWalls(int NumWalls)
//{
// for (int i = 0; i < NumWalls; i++)
// {
// RoomElements.Add(Element.MakeElement(typeof(Wall).Name));
// }
//}
//public void MakeCeiling()
//{
// RoomElements.Add(Element.MakeElement(typeof(Ceiling).Name));
//}
//public void MakeCeilings(int NumCeilings)
//{
// for (int i = 0; i < NumCeilings; i++)
// {
// RoomElements.Add(Element.MakeElement(typeof(Ceiling).Name));
// };
//}
public void AddRoom()
{
ShowRooms.Add(this);
}
public List<Room> GetAllRooms()
{
IRooms r = (IRooms)ShowRooms;
return r.AvailableRooms();
}
public override string ToString()
{
return "I am a room with " + RoomElements.Count.ToString() + " Elements";
}
private class Rooms : List<Room>,IRooms
{
List<Room> IRooms.AvailableRooms()
{
return this;
}
}
}
public abstract class Element
{
//this method is used for the commented methods
public static Element MakeElement(string name)
{
if (name == typeof(Ceiling).Name)
return new Ceiling() as Element;
else if (name == typeof(Wall).Name)
return new Wall() as Element;
else
throw new ArgumentException("Parameter not valid");
}
}
public class Ceiling : Element
{
//your implementation.
public override string ToString()
{
return "I am a ceiling";
}
}
public class Wall : Element
{
//your implementation.
public override string ToString()
{
return "I am a wall!";
}
}
Client-side code example:
Wall w = new Wall();
Ceiling c = new Ceiling();
Room r = new Room();
r.MakeElement(w);
r.MakeElement(c);
List<Element> NewElements = new List<Element>{ new Wall(), new Ceiling() };
r.MakeElements(NewElements);
//r.MakeWalls(5);
//r.MakeCeilings(6);
r.AddRoom();
foreach (Room room in r.GetAllRooms())
{
MessageBox.Show(room.ToString());
foreach (Element el in room.RoomElements)
{
MessageBox.Show(el.ToString());
}
}
Hope this helps.
language specific (however, if you need a language please use C++/C# or Javascript). I trying to figure out how I would go about doing this, and how I would access the child objects from a parent object.
Say I have the following classes, and these are not written properly etc... :
Class: roomContainer (container of objects)
Class: Table (base class for a table, contains property of maximum-seats, current-number-of-seats, array of seats )
Class: Desk (extends Table, contains property for maximum draws, array of draws )
Class: seat (base class for seats, contains property of maximum-legs, arm-rest, back-rest)
Class: couch (extends seat, adds property maximum seats)
If I create an instance of roomContainer, and add within it's container a table, couch. Within the table I create multiple seats (or chairs), and a desk.
How would I be able to access the property of child objects property, when the parent has a container of different objects. I.e the roomContainer Container of objects, one of them is a table, and a desk - where the desk has different properties and an array of draws etc.. ?
You're looking for something called the Composite Design Pattern. This allows you to nest objects (as you described), and hold references to both the parent and the children (though some implementations do no maintain a parent reference - this is optional).
Here is an example implementation using your schema:
public static class Program // the supporting class definitions are below
{
public static void Main()
{
// create a root container
var room = new RoomContainer();
// create a child
var table = new Table(room, 4);
// put the table in the room
room.Add(table);
MakeMess(room);
}
// to show you how to access the properties
// if you don't already have a reference:
public static void MakeMess(RoomContainer room)
{
if(room == null)
{
throw new ArgumentNullException("room");
}
var seats = room.GetChildren<Table>().First().Seats.ToArray();
for (int index = 0; index < seats.Length; index++)
{
Console.WriteLine("You have kicked over Seat #{0}",(index+1).ToString());
}
}
}
// This is the base class of the components and provides the core functionality.
// You will want to make this object's interface minimal, so that the logic
// is consistent with all its children (without knowing what they might be in advance)
public abstract class Component
{
private readonly IList<Component> _children;
private readonly Component _container;
protected Component(Component container)
{
_container = container;
_children = new Component[] { };
}
public bool IsRoot { get { return _container == null; } }
public abstract bool IsContainer { get; }
public virtual void Add(Component component)
{
if (component == null)
{
throw new ArgumentNullException("component");
}
if (!IsContainer)
{
throw new NotSupportedException("Add is not supported by leaf components");
}
_children.Add(component);
}
public IEnumerable<T> GetChildren<T>()
where T: Component
{
if (!IsContainer)
{
throw new NotSupportedException("Only containers have children");
}
return _children.OfType<T>();
}
public IEnumerable<Component> Children
{
get
{
if (!IsContainer)
{
throw new NotSupportedException("Only containers have children");
}
return _children;
}
}
}
public class RoomContainer : Component
{
public RoomContainer() : base(null)
{
}
public override bool IsContainer { get { return true; } }
}
public class Table : Component
{
private readonly int _maximumSeatCount;
public Table(Component container, int maximumSeatCount) : base(container)
{
_maximumSeatCount = maximumSeatCount;
}
public override bool IsContainer { get { return true; } }
protected virtual bool CanAdd(Component component)
{
return component is Seat && MaximumSeatCount > CurrentSeatCount;
}
public override void Add(Component component){
if(CanAdd(component)){
base.Add(component);
}
else
{
throw new NotSupportedException("The component was an invalid child of Table and could not be added.");
}
}
public int MaximumSeatCount { get { return _maximumSeatCount; } }
public int CurrentSeatCount { get { return Seats.Count(); } }
public IEnumerable<Seat> Seats { get { return Children.OfType<Seat>(); } }
}
public class Seat : Component
{
// you can restrict the constructor to only accept a valid parent
public Seat(Table table) : base(table)
{
}
public override bool IsContainer
{
get { return false; }
}
}
If the all share common methods, for example Render(), Update(), SaveDetails(int Id), LoadDetails(int Id) then you could make them all inherit from a base class, or all impliment a common interface. This would remove the need for casting (below) when calling a common method (or accessing a common property).
To access properties unique to the derived class you would check the type of the child object, then cast the child object to access the property.
EDIT: Example:
foreach(Object obj in Room.ChildObjects)
{
if(obj is Desk)
{
Desk DeskObj = obj as Desk; // Cast the object reference as a desk.
DeskObj.MaxDraws = 50; // It's a big desk!
DestObj.Draws[1] = new Draw(); // ......
}
}
Something like this:
IEnumerable<Desk> desks = roomContainer.OfType<Desk>();
//Iterate and do stuff.
IEnumerable<Table> tables = roomContainer.OfType<Table>();
//Iterate and do stuff.
Is there any issues in using version 2,to get the same results as version 1.
Or is this just bad coding.
Any Ideas
public class Customer
{
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
int Age { get; set; }
}
public interface ICustomer
{
void AddNewCustomer(Customer Customer);
void AddNewCustomer(string EmailAddress, int Age);
void RemoveCustomer(Customer Customer);
}
public class BALCustomer
{
private readonly ICustomer dalCustomer;
public BALCustomer(ICustomer dalCustomer)
{
this.dalCustomer = dalCustomer;
}
public void Add_A_New_Customer(Customer Customer)
{
dalCustomer.AddNewCustomer(Customer);
}
public void Remove_A_Existing_Customer(Customer Customer)
{
dalCustomer.RemoveCustomer(Customer);
}
}
public class CustomerDataAccess : ICustomer
{
public void AddNewCustomer(Customer Customer)
{
// MAKE DB CONNECTION AND EXECUTE
throw new NotImplementedException();
}
public void AddNewCustomer(string EmailAddress, int Age)
{
// MAKE DB CONNECTION AND EXECUTE
throw new NotImplementedException();
}
public void RemoveCustomer(Customer Customer)
{
// MAKE DB CONNECTION AND EXECUTE
throw new NotImplementedException();
}
}
// VERSION 2
public class Customer_New : DataRespository<CustomerDataAccess>
{
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
public int Age { get; set; }
}
public class DataRespository<T>
where T:class,new()
{
private T item = new T();
public T Execute { get { return item; } set { item = value; } }
public void Update()
{
//TO BE CODED
}
public void Save()
{
//TO BE CODED
}
public void Remove()
{
//TO BE CODED
}
}
class Program
{
static void Main(string[] args)
{
Customer_New cus = new Customer_New()
{
Age = 10,
EmailAddress = "this#demo.com"
};
cus.Save();
cus.Execute.RemoveCustomer(new Customer());
// Repository Version
Customer customer = new Customer()
{
EmailAddress = "new#demo.com",
CustomerID = 10
};
BALCustomer bal = new BALCustomer(new CustomerDataAccess());
bal.Add_A_New_Customer(customer);
}
}
You have a lot of things going on that aren't making a lot of sense.
First of all, the names of properties should always be a noun (singular or plural) or a "being" verb like Is* or Has*. These are properties of an object, and should be similar to what you would say in response to a question like "Would you please describe your desk?" Execute is an operation, and should therefore be a method. Likewise, your naming conventions in Version 1 should be PascalCased which means no underscores and the first letter of all words should be capitalized. These aren't die-hard truths, but they are considered OOP common C# coding standards.
Secondly, the code in your main method isn't actually implementing anything in your generic class. The only thing your class is actually doing is creating an instance of CustomerDataAccess. The Save() method won't do anything, unless you specifically are able to call item.Save() In order to use your Save, Update, Delete functionality on your generic class, your CustomerDataAccess class will have to implement an interface expected by your generic class. For instance:
public interface IDataAccess<T> : where T : YourBaseObject {
public void Update(T item);
public void Save(T item);
public void Remove(T item);
}
public class Customer : YourBaseObject {
public int CustomerID { get; set; }
public string EmailAddress { get; set; }
public int Age { get; set; }
}
public class CustomerDataAccess :
DataRespository<IDataAccess<Customer>> {
public void PerformCustomerOnlyAction(Customer customer) {
/* do stuff */
}
}
Now, you can create a generic class that handles basic CRUD functionality, and all other functionality is accessible through the BaseRepository property.
/* e.g. T = IDataAccess<Customer>, K = Customer */
public class DataRespository<T>
where T : IDataAccess<K>, new()
where K : YourBaseObject, new()
{
private T _base;
public T BaseRepository {
get {
if(_base == null)
_base = Activator.CreateInstance<T>();
return _base;
}
}
public void Update(K item) { /* functionality for YourBaseObject */ }
public void Save(K item) { /* functionality for YourBaseObject */ }
public void Remove(K item) { /* functionality for YourBaseObject */ }
}
class Program
{
static void Main(string[] args)
{
var repository = new CustomerDataAccess();
Customer c = new Customer {
Age = 10,
EmailAddress = "this#demo.com"
};
repository.Save(c);
// This pass-through is no longer needed, but shown as example
// repository.BaseRepository.PerformCustomerOnlyAction(c);
repository.PerformCustomerOnlyAction(c);
}
}
NOTE I did the above code from scratch/memory. The generic type constraints may not work exactly as I have them.
ASP.NET 3.5 Unleashed by Stephen Walther has a couple of chapters on creating a repository pattern which is setup similarly to what you're trying to accomplish in Version 2. He also splits processing up between a business logic layer and a data access layer. Although the book is huge (nearly 2000 pages) and many of the code examples are redundant or better left as part of the CD, he goes pretty in-depth for beginner-to-intermediate range. It's available used on Amazon for around $25.
I think while implementing object model of your application you just have to ask yourself a number of questions as though you are make object design review of your collegue code.
Why CustomerAccessLayer implements interface? Is there will be a number of layers implementing this Interface. Or maybe you are expecting any polymorph behaviour from classes implements this interface? Or maybe you will separate interface to standalone module and will provide its functionality though any kind of service?
Why do you need BALCustomer class? Why you could not make calls directly to CustomerAccesLayer? And, have i already spoke about codesyle? :)
If DataRepository have a generic behaviour and will provide a number of AccessLayers throw Execute property why it is have its own methods?
I think could be continued... I hope you've catch my point?
Suppose I have a base class named Visitor, and it has 2 subclass Subscriber and NonSubscriber.
At first a visitor is start off from a NonSubscriber, i.e.
NonSubscriber mary = new NonSubscriber();
Then later on this "mary" subscribed to some services, and I want to change the type of "mary" to Subscriber.
What is the conventional way to do that?
can't do that. sorry. C# is not a dynamic language.
You will have to create a new mary = new Subscriber(); and copy all relevant properties.
But a better approach might be to model it differently: Give Visitor a list of subscriptions. An empty list means a NonSubscriber.
You cant do this type of conversion.
What you should do is treat mary as a visitor, and when time arrives, create a new instance of "subscriber":
Visitor mary = new NonSubscriber();
// Do some Visitor operations
...
// Now mary is a Subscriber
mary = new Subscriber();
You could use the GOF design patterns State or Strategy to model such an behaviour. Using these patterns, it seems during runtime as if the class of the objects has been changed.
It seems that you have some design problems. I think that it would be better to redesign your code like:
class Visitor
{
private bool isSubscriber = false;
public bool IsSubscriber
{
get { return isSubscriber; }
}
public void Subscribe()
{
// do some subscribing stuff
isSubscriber = true;
}
public void Unsubscribe()
{
// do some unsubscribing stuff
isSubscriber = false;
}
}
You cannot change the type of a variable at runtime. You need to create a new instance.
mary = new Subscriber();
Create a Subscriber constructor that takes a NonSubscriber object as a parameter, or create a method on the NonSubscriber object that returns a Subscriber to save you having to writer the mappping code in multiple places.
It seems like you are encoding information incorrectly into your class hierarchy. It would make more sense to use a different pattern than sub classing here. For example, use only one class (visitor, or perhaps you could name it potential subscriber, whatever seems appropriate) and encode information on the services the object is subscribed to, moving the dynamically changing behavior behind a "Strategy" pattern or some such. There's very little detail in your example, but one thing you could do in C# is to make a "subscriber" property which would change the behavior of the object when the state of the property was changed.
Here's a contrived somewhat related example:
class Price
{
private int priceInCents;
private bool displayCents;
private Func<string> displayFunction;
public Price(int dollars, int cents)
{
priceInCents = dollars*100 + cents;
DisplayCents = true;
}
public bool DisplayCents
{
get { return displayCents; }
set
{
displayCents = value;
if (displayCents)
{
this.displayFunction = () => String.Format("{0}.{1}", priceInCents / 100, priceInCents % 100);
}
else
{
this.displayFunction = () => (priceInCents / 100).ToString();
}
}
}
public string ToString()
{
return this.displayFunction();
}
}
public class User
{
public Subscription Subscription { get; set; }
public void HandleSubscription()
{
Subscription.Method();
}
}
public abstract class SubscriptionType
{
public abstract void Method();
}
public class NoSubscription : SubscriptionType
{
public override void Method()
{
// Do stuff for non subscribers
}
}
public class ServiceSubscription : SubscriptionType
{
public override void Method()
{
// Do stuff for service subscribers
}
}
public class Service2Subscription : SubscriptionType
{
public override void Method()
{
// Do stuff for service2 subscribers
}
}
Think the code explains my answer :)
Adding to the other answers and your comment, you indeed can use the state pattern for your purpose, it would go something like this:
public class MyProgram
{
public void Run()
{
Visitor v = new Visitor("Mary");
Debug.Assert(v.SubscriptionLinkText == "Join now");
v.IsSubscribed = true;
Debug.Assert(v.SubscriptionLinkText == "Today's special");
v.IsSubscribed = false;
Debug.Assert(v.SubscriptionLinkText == "Join now");
}
}
public class Visitor
{
public string Name { get; set; }
private bool _isSubscribed;
public bool IsSubscribed
{
get { return this._isSubscribed; }
set
{
if (value != this._isSubscribed)
{
this._isSubscribed = value;
this.OnSubscriptionChanged();
}
}
}
private SubscriptionBase _subscription;
public string SubscriptionLinkText
{
get { return this._subscription.LinkText; }
}
public Visitor(string name)
{
this.Name = name;
this._isSubscribed = false;
this.OnSubscriptionChanged();
}
private void OnSubscriptionChanged()
{
// Consider also defining an event and raising it here
this._subscription =
SubscriptionBase.GetSubscription(this.IsSubscribed);
}
}
abstract public class SubscriptionBase
{
// Factory method to get instance
static public SubscriptionBase GetSubscription(bool isSubscribed)
{
return isSubscribed ?
new Subscription() as SubscriptionBase
: new NoSubscription() as SubscriptionBase;
}
abstract public string LinkText { get; }
}
public class Subscription : SubscriptionBase
{
public override string LinkText
{
get { return "Today's Special"; }
}
}
public class NoSubscription : SubscriptionBase
{
public override string LinkText
{
get { return "Join now"; }
}
}