Object Oriented Programming Nth Child - c#

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.

Related

How to delete object?

I need to create a method of class that delete the instance.
public class Car
{
private string m_Color;
public string Color
{
get { return m_Color; }
set { m_Color = value; }
}
public Car()
{
}
public void Delete()
{
/*This method will delete the instance,
so any references to this instance will be now null*/
}
}
class Program
{
static void Main( string[] args )
{
Car car = new Car();
car.Delete();
if(car==null)
Console.WriteLine("It works.");
else
Console.WriteLine("It doesn't work.")
}
}
I want to know if there is any possible solution (even if it is not recommended) how to do this.
Instance of this class will be stored in hundreds of different class. I will try to describe this, for example there will be these classes:
public class CarKey
{
private Car m_Car;
public Car Car
{
get { return m_Car; }
}
public bool CarExist{ get{ return m_Car != null; } }
public CarKey( Car car )
{
m_Car = car;
}
}
public class Garages
{
private List<Car> m_Collection = new List<Car>();
private int m_Size;
public int Size{ get{ return m_Size; } }
public Garages( int size )
{
for(int i=0;i<size;i++)
m_Collection.Add(null);
}
public bool IsEmpty( int garage )
{
return m_Collection[garage] == null;
}
public void InsertCar( Car car, int garage )
{
if( m_Collection[garage] != null )
throw new Exception("This garage is full.");
m_Collection[garage] = car;
}
public Car GetCar( int garage )
{
if( m_Collection[garage] == null )
throw new Exception("There is no car, maybe it was deleted.");
return m_Collection[garage];
}
}
From any class you can't set its value to null. This is not allowed and doesn't make sense also -
public void Delete()
{
this = null; <-- NOT ALLOWED
}
You need an instance of class to call Delete() method so why not set that instance to null itself once you are done with it.
Car car = new Car();
// Use car objects and once done set back to null
car = null;
Anyhow what you are trying to achieve is not possible in C#. I suspect
from your question that you want this because there are memory leaks
present in your current design which doesn't let the Car instance to
go away. I would suggest you better profile your application and
identify the areas which is stopping GC to collect car instance and
work on improving that area.
I would suggest , to use .Net's IDisposable interface if your are thinking of to release instance after its usage.
See a sample implementation below.
public class Car : IDisposable
{
public void Dispose()
{
Dispose(true);
// any other managed resource cleanups you can do here
Gc.SuppressFinalize(this);
}
~Car() // finalizer
{
Dispose(false);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
if (_stream != null) _stream.Dispose(); // say you have to dispose a stream
}
_stream = null;
_disposed = true;
}
}
}
Now in your code:
void main()
{
using(var car = new Car())
{
// do something with car
} // here dispose will automtically get called.
}
It sounds like you need to create a wrapper around an instance you can invalidate:
public class Ref<T> where T : class
{
private T instance;
public Ref(T instance)
{
this.instance = instance;
}
public static implicit operator Ref<T>(T inner)
{
return new Ref<T>(inner);
}
public void Delete()
{
this.instance = null;
}
public T Instance
{
get { return this.instance; }
}
}
and you can use it like:
Ref<Car> carRef = new Car();
carRef.Delete();
var car = carRef.Instance; //car is null
Be aware however that if any code saves the inner value in a variable, this will not be invalidated by calling Delete.
What you're asking is not possible. There is no mechanism in .Net that would set all references to some object to null.
And I think that the fact that you're trying to do this indicates some sort of design problem. You should probably think about the underlying problem and solve it in another way (the other answers here suggest some options).
You can proxyfy references to your object with, for example, dictionary singleton. You may store not object, but its ID or hash and access it trought the dictionary. Then when you need to remove the object you set value for its key to null.
You cannot delete an managed object in C# . That's why is called MANAGED language. So you don't have to troble yourself with delete (just like in c++).
It is true that you can set it's instance to null. But that is not going to help you that much because you have no control of your GC (Garbage collector) to delete some objects apart from Collect. And this is not what you want because this will delete all your collection from a generation.
So how is it done then ? So : GC searches periodically objects that are not used anymore and it deletes the object with an internal mechanism that should not concern you.
When you set an instance to null you just notify that your object has no referene anymore ant that could help CG to collect it faster !!!
Use a collection that is a static property of your Car class.
Every time you create a new instance of a Car, store the reference in this collection.
To destroy all Cars, just set all items to null.
FLCL's idea is very correct, I show you in a code:
public class O1<T> where T: class
{
public Guid Id { get; }
public O1(Guid id)
{
Id = id;
}
public bool IsNull => !GlobalHolder.Holder.ContainsKey(Id);
public T Val => GlobalHolder.Holder.ContainsKey(Id) ? (T)GlobalHolder.Holder[Id] : null;
}
public class GlobalHolder
{
public static readonly Dictionary<Guid, object> Holder = new Dictionary<Guid, object>();
public static O1<T> Instantiate<T>() where T: class, new()
{
var a = new T();
var nguid = Guid.NewGuid();
var b = new O1<T>(nguid);
Holder[nguid] = a;
return b;
}
public static void Destroy<T>(O1<T> obj) where T: class
{
Holder.Remove(obj.Id);
}
}
public class Animal
{
}
public class AnimalTest
{
public static void Test()
{
var tom = GlobalHolder.Instantiate<Animal>();
var duplicateTomReference = tom;
GlobalHolder.Destroy(tom);
Console.WriteLine($"{duplicateTomReference.IsNull}");
// prints true
}
}
Note: In this code sample, my naming convention comes from Unity.
You can use extension methods to achive this.
public static ObjRemoverExtension {
public static void DeleteObj<T>(this T obj) where T: new()
{
obj = null;
}
}
And then you just import it in a desired source file and use on any object. GC will collect it. Like this:Car.DeleteObj()
EDIT
Sorry didn't notice the method of class/all references part, but i'll leave it anyway.

How do i convert a class (which is derived from a generic "base" class) to that generic "base" class

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.

Recursive Lookup of generic List C# using LINQ

I have generic list of a custom class which has 2 properties. These properties store the raltionship between on form and another form. The list is structured as a hierachical list (parent / child ) relationship. What I want to be able to do is get a list of all forms based on a parent form reference which will be passed to a function. I am thinking the best way to go about this is with a LINQ query using a recursive approach. I am sure someone can point me in the right direction
This is the class used in the list
class FormStack {
#region Declares
private Form _form;
private Form _parent;
#endregion
#region Constructor
static FormStack()
{
}
#endregion
public Form Form
{
get { return _form; }
set { _form = value; }
}
public Form Parent
{
get { return _parent; }
set { _parent = value; }
}
}
So I would like to be able to Call a method and pass a form reference to the function and get all the children form related to this parent.
This is some of the code I have been stumbling with
// create a lookup list
var list = formStack.ToLookup( p => object.ReferenceEquals( p.Parent, parent ) );
// create a function
Func<IEnumerable<Form>, IEnumerable<Form>> recurse = null;
recurse = qs =>
{
return
qs
.Concat(
from q in qs
from q2 in recurse( list[] )
select q2 );
};
// filter the list
var children = recurse( list[parent] ).ToList();
I have a winform application which has standard CRUD functionality. Lets say there is a list of customers and each customer can have multiple address and each one of these addresses have multiple buildings, the way I have structured the forms is there is a list of customers, from this list you can open a detail form for a particular customer. This form has the details of the customer and all the addresses in a list. This list allows the user to now selected an address in the list and open the address details form which has a list of buildings and so on.... My problem is I want to close the customer detail and all the related forms for this customer. My idea was to keep of the relationship between the forms, but maybe I there is a better way???
here is what I made up:
Create a base Form for all your Forms:
public class MyFormBase : Form
{
public MyFormBase()
{
FormRepository.RegisterForm(this);
}
public MyFormBase(MyFormBase parent)
: this()
{
Parent = parent;
}
public MyFormBase Parent { get; set; }
}
Each Form can only have one Parent that is passed in the constuctor.
Create a Repository (or something simiar) to store your forms -> I do not want to store all children in the Form itself
//infrastructure - simulated with a static class
public static class FormRepository
{
private static List<MyFormBase> _allForms = new List<MyFormBase>();
public static void RegisterForm(MyFormBase form)
{
_allForms.Add(form);
}
public static void CloseFormAndChildren(MyFormBase form)
{
_allForms.Where(x => x.Parent.Equals(form)).ToList().ForEach(x => CloseFormAndChildren(x));
form.Close();
}
}
Call CloseFormAndChildren on any form you want to close (including the children). This could be called in the closing event...
Okay, it sounds to me like you have two issues. One is a syntax error (recurse(list[]) is wrong), but the other is that your FormStack isn't really a stack. It's just two forms, with no way to create a recursive chain. I think you want this:
public class FormStack : IEnumerable<Form> // or just implement SelectMany
{
public Form Form { get; set; }
public FormStack Parent { get; set; }
//implement IEnumerable<Form> or the SelectMany method
}
Then I think you can just do this, but it seems like an awkward thing to do:
Func<FormStack, IEnumerable<Form>> recurse = qs =>
{
return from q in qs
select (new[] { qs.Form }).Concat(recurse(qs.Parent));
};
var list = recurse(formStack).ToList();
That's if you're insisting on the query syntax.
If I were you, though, I'd forget all that and implement an IEnumerator<Form> to do it all for you:
public class FormStack : IEnumerable<Form>
{
public Form Form { get; set; }
public FormStack Parent { get; set; }
public IEnumerator IEnumerable:GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
public IEnumerator<Form> GetEnumerator()
{
return new FormStackEnumerator(this);
}
}
public class FormStackEnumerator : IEnumerator<Form>
{
private FormStack _stack;
private FormStack _first;
public Form Current { get { return _stack.Form; } }
object IEnumerator.Current { get { return Current; } }
public FormStackEnumerator(FormStack stack)
{
_stack = stack;
_first = stack;
}
public bool MoveNext()
{
if (_stack.Parent == null)
{
return false;
}
_stack = _stack.Parent;
return true;
}
public void Reset() { _stack = _first; }
void IDisposable.Dispose() { }
}
Then all you'd need to do in your main code is this:
var list = new List<Form>();
foreach (var node in formStack)
{
list.Add(node.Form);
}
By the way, I just looked up the Form class (I'm not a WinForms developer) and the Forms themselves have a Parent member. So you don't really need to wrap them in a node-type construct; they're already nodes! That makes everything easy:
var list = new List<Form>();
Action<Control> recurse = target =>
{
var form = target as Form;
if (form != null)
{
list.Add(form);
recurse(target.Parent);
}
}

How to change the class of an object dynamically in C#?

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"; }
}
}

Composite Pattern Simplified

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'.

Categories

Resources