Refactoring Properties into Classes
-
Say you have an interface:
public interface IWidget
{
// Methods...// Properties... int Count { get; set; }
}
Let's pretend that a lot of classes will implement this interface. As a result, each class will have to implement the
Count
property. The implementation code in each class will be the same, more or less. So it's tempting to do this:public abstract Widget : IWidget
{
private int count = 0;public int Count { get { return count; } set { count = value; } }
}
Now instead of implementing the
IWidget
interface directly, classes derive from the abstractWidget
base class. Let's say, however, that derived classes need to know whenCount
changes; they may need to do some house keeping. We could makeCount
virtual so that derived classes could do this:public class MyWidget : Widget
{
public override int Count
{
get
{
return base.Count;
}
set
{
base.Count = value;// Do stuff based on new count value... } }
}
I've posted about this in the past. I don't like this approach because it seems to introduces an ambiguity. When overriding a virtual method or property, when should you call the base class version? And should the call be at the beginning or at the end of the virtual method or property? But I'm not really interested in delving into this issue again, though feel free to comment. The next step is to factor out the
Count
property into its own class:public class Counter
{
private int count = 0;public event EventHandler CountChanged; // ... public int Count { get { return count; } set { if(count < 0) { throw new ArgumentOutOfRange("Count"); } count = value; OnCountChanged(EventArgs.Empty); } }
}
Instead of
Count
being a property of theIWidget
interface, it becomes an object that is passed to instances ofIWidget
derived classes. Derived classes hook up to theCountChanged
event and do whatever house keeping is necessary when the event i -
Say you have an interface:
public interface IWidget
{
// Methods...// Properties... int Count { get; set; }
}
Let's pretend that a lot of classes will implement this interface. As a result, each class will have to implement the
Count
property. The implementation code in each class will be the same, more or less. So it's tempting to do this:public abstract Widget : IWidget
{
private int count = 0;public int Count { get { return count; } set { count = value; } }
}
Now instead of implementing the
IWidget
interface directly, classes derive from the abstractWidget
base class. Let's say, however, that derived classes need to know whenCount
changes; they may need to do some house keeping. We could makeCount
virtual so that derived classes could do this:public class MyWidget : Widget
{
public override int Count
{
get
{
return base.Count;
}
set
{
base.Count = value;// Do stuff based on new count value... } }
}
I've posted about this in the past. I don't like this approach because it seems to introduces an ambiguity. When overriding a virtual method or property, when should you call the base class version? And should the call be at the beginning or at the end of the virtual method or property? But I'm not really interested in delving into this issue again, though feel free to comment. The next step is to factor out the
Count
property into its own class:public class Counter
{
private int count = 0;public event EventHandler CountChanged; // ... public int Count { get { return count; } set { if(count < 0) { throw new ArgumentOutOfRange("Count"); } count = value; OnCountChanged(EventArgs.Empty); } }
}
Instead of
Count
being a property of theIWidget
interface, it becomes an object that is passed to instances ofIWidget
derived classes. Derived classes hook up to theCountChanged
event and do whatever house keeping is necessary when the event iHi Leslie, I did not completely follow the story here. Count first was a property, I am not sure what it is intended for. If it counts the number of IWidgets, I guess you would like to have a private static count variable, and a public static property; but then interfaces don't allow for static things. And you would not need a setter, the constructor should be the only one modifying it. Now if you attempt to solve the static issue by making an explicit Counter class and object, that's fine except it de-encapsulates things: you are now responsible for passing the right counter to each of the Widget constructors. You could solve that by adding another class I think. But maybe I misunderstood you and you want something completely different... :)
Luc Pattyn [Forum Guidelines] [My Articles]
this weeks tips: - make Visual display line numbers: Tools/Options/TextEditor/... - show exceptions with ToString() to see all information - before you ask a question here, search CodeProject, then Google
-
Hi Leslie, I did not completely follow the story here. Count first was a property, I am not sure what it is intended for. If it counts the number of IWidgets, I guess you would like to have a private static count variable, and a public static property; but then interfaces don't allow for static things. And you would not need a setter, the constructor should be the only one modifying it. Now if you attempt to solve the static issue by making an explicit Counter class and object, that's fine except it de-encapsulates things: you are now responsible for passing the right counter to each of the Widget constructors. You could solve that by adding another class I think. But maybe I misunderstood you and you want something completely different... :)
Luc Pattyn [Forum Guidelines] [My Articles]
this weeks tips: - make Visual display line numbers: Tools/Options/TextEditor/... - show exceptions with ToString() to see all information - before you ask a question here, search CodeProject, then Google
Luc Pattyn wrote:
I did not completely follow the story here. Count first was a property, I am not sure what it is intended for.
Erm, count was a bad example, I guess. It's not intended to mean anything other than demonstrating the example. It could have easily been called foo or whatever. I ran into this situation with my synth toolkit. I had a collection of synth components that shared the same sample rate. At first, I made sample rate a property in an interface that's implemented by synth component classes. I noticed a lot of code duplication, so I factored sample rate into a property in an abstract base class. Some derived classes need to know when the sample rate changes, so I made it a virtual property. Derived classes then have the option to override the property so that when it's set to a new value, they can react. This lead to the ambiguity I described in my post about when/where/if to call base class members. Finally, I factored sample rate out into a class of its own. This allowed components to share the same sample rate object. It also allowed me to change the sample rate from a single point. Components sharing the same sample rate object would then be updated automatically. I was trying to describe all of this in my post by using a generic "Widget" class and "Count" property. I should have been more concrete.
-
Luc Pattyn wrote:
I did not completely follow the story here. Count first was a property, I am not sure what it is intended for.
Erm, count was a bad example, I guess. It's not intended to mean anything other than demonstrating the example. It could have easily been called foo or whatever. I ran into this situation with my synth toolkit. I had a collection of synth components that shared the same sample rate. At first, I made sample rate a property in an interface that's implemented by synth component classes. I noticed a lot of code duplication, so I factored sample rate into a property in an abstract base class. Some derived classes need to know when the sample rate changes, so I made it a virtual property. Derived classes then have the option to override the property so that when it's set to a new value, they can react. This lead to the ambiguity I described in my post about when/where/if to call base class members. Finally, I factored sample rate out into a class of its own. This allowed components to share the same sample rate object. It also allowed me to change the sample rate from a single point. Components sharing the same sample rate object would then be updated automatically. I was trying to describe all of this in my post by using a generic "Widget" class and "Count" property. I should have been more concrete.
Hi Leslie, if you moved out the Counter/SampleRate stuff away from IWidget/ISynth and into a separate class, basically making it (almost) global, I see no objection. I first was under the impression you were somehow aggregating interfaces, i.e. defining an interface in an hierarchical way, with Counter somehow inside it. And that would open some new doors, if it were possible, but in the end I understood the Counter/SampleRate stuff is orthogonal to the IWidget/ISynth stuff, you just took it out completely. :)
Luc Pattyn [Forum Guidelines] [My Articles]
this weeks tips: - make Visual display line numbers: Tools/Options/TextEditor/... - show exceptions with ToString() to see all information - before you ask a question here, search CodeProject, then Google
-
Say you have an interface:
public interface IWidget
{
// Methods...// Properties... int Count { get; set; }
}
Let's pretend that a lot of classes will implement this interface. As a result, each class will have to implement the
Count
property. The implementation code in each class will be the same, more or less. So it's tempting to do this:public abstract Widget : IWidget
{
private int count = 0;public int Count { get { return count; } set { count = value; } }
}
Now instead of implementing the
IWidget
interface directly, classes derive from the abstractWidget
base class. Let's say, however, that derived classes need to know whenCount
changes; they may need to do some house keeping. We could makeCount
virtual so that derived classes could do this:public class MyWidget : Widget
{
public override int Count
{
get
{
return base.Count;
}
set
{
base.Count = value;// Do stuff based on new count value... } }
}
I've posted about this in the past. I don't like this approach because it seems to introduces an ambiguity. When overriding a virtual method or property, when should you call the base class version? And should the call be at the beginning or at the end of the virtual method or property? But I'm not really interested in delving into this issue again, though feel free to comment. The next step is to factor out the
Count
property into its own class:public class Counter
{
private int count = 0;public event EventHandler CountChanged; // ... public int Count { get { return count; } set { if(count < 0) { throw new ArgumentOutOfRange("Count"); } count = value; OnCountChanged(EventArgs.Empty); } }
}
Instead of
Count
being a property of theIWidget
interface, it becomes an object that is passed to instances ofIWidget
derived classes. Derived classes hook up to theCountChanged
event and do whatever house keeping is necessary when the event iWhat you have just described is known as composition, and it is perfectly valid. It is one of the most frequently overlooked areas of aggregation in OOP, and is seriously underused. To my mind, composition is as important as inheritance in OO.
Deja View - the feeling that you've seen this post before.
-
Say you have an interface:
public interface IWidget
{
// Methods...// Properties... int Count { get; set; }
}
Let's pretend that a lot of classes will implement this interface. As a result, each class will have to implement the
Count
property. The implementation code in each class will be the same, more or less. So it's tempting to do this:public abstract Widget : IWidget
{
private int count = 0;public int Count { get { return count; } set { count = value; } }
}
Now instead of implementing the
IWidget
interface directly, classes derive from the abstractWidget
base class. Let's say, however, that derived classes need to know whenCount
changes; they may need to do some house keeping. We could makeCount
virtual so that derived classes could do this:public class MyWidget : Widget
{
public override int Count
{
get
{
return base.Count;
}
set
{
base.Count = value;// Do stuff based on new count value... } }
}
I've posted about this in the past. I don't like this approach because it seems to introduces an ambiguity. When overriding a virtual method or property, when should you call the base class version? And should the call be at the beginning or at the end of the virtual method or property? But I'm not really interested in delving into this issue again, though feel free to comment. The next step is to factor out the
Count
property into its own class:public class Counter
{
private int count = 0;public event EventHandler CountChanged; // ... public int Count { get { return count; } set { if(count < 0) { throw new ArgumentOutOfRange("Count"); } count = value; OnCountChanged(EventArgs.Empty); } }
}
Instead of
Count
being a property of theIWidget
interface, it becomes an object that is passed to instances ofIWidget
derived classes. Derived classes hook up to theCountChanged
event and do whatever house keeping is necessary when the event iLeslie Sanford wrote:
I've posted about this in the past. I don't like this approach because it seems to introduces an ambiguity. When overriding a virtual method or property, when should you call the base class version? And should the call be at the beginning or at the end of the virtual method or property? But I'm not really interested in delving into this issue again, though feel free to comment.
hehe I know it's not the main issue but since you invited comments ... it's not ambiguous it's flexable. You should know (either because you wrote it or because the documentation tells you) exactly what happens in the base. You then have a choice of wether you want that functionality to happen before your code, after your code or not at all.
-
What you have just described is known as composition, and it is perfectly valid. It is one of the most frequently overlooked areas of aggregation in OOP, and is seriously underused. To my mind, composition is as important as inheritance in OO.
Deja View - the feeling that you've seen this post before.
It looks like a composition, but I'm my opinion, he's implementing the Observer Design Pattern. I think in his project (as in many others), a property from an object is more than a property -- since it's shared among many members, it could be seen as an object itself. So, you create and object and delegate to punch when the state changes. I think many people tend to believe since "it's just an int" or "it's just a string" it's not a object.