My struggles in understanding and learning about Object Oriented design, and the tools and knowledge I've taken from them.
Monday, January 3, 2011
SOLID Principles
Martin (affectionately known as "Uncle Bob") wasn't really inventing any new concepts with his articles; rather, he was simply synthesizing information created by others into a paradigm that was appropriate for the time and available technology. But Robert Martin's articles were so successful and widely adopted, that they are still at the core of most object oriented design that is in use today, including later concepts, such as design patterns. Evidently, Martin is still at it, owning a company called "Object Mentor" which does company/enterprise-level coaching of these, and other object oriented design principles. He's also written a number of books on the topic, as well. Today, Martin is considered a legend in the programming world. He even has a blog, which can be found at http://blog.objectmentor.com/articles/category/uncle-bobs-blatherings
I'm about half way through reading this series of articles Martin wrote, and the information I've gleened from them have drastically (or at least, significantly) impacted how I approach design and refactoring (in fact, some of the principles demonstrated in these articles have sparked several refactoring sessions). Martin's SOLID principles are made up of: Single Responsibility Principle, The Open-Closed Principle, The Liskov Substitution Principle, the Interface Segregation Principle, and the Dependency Inversion Principle.
If nothing else my next few blogs will be a way for me to take the information I gathered from the core OOP principles Uncle Bob put forward (hereafter referred to as SOLID principles). And perhaps, someone out there will read them, and be compelled to apply them in their own programming.
Monday, October 25, 2010
Resizable Controls on a .Net desktop form
1. I created a form object called ResizeableForm, which inherits from System.Windows.Forms.
2. I created an AbstractControl object, which Has-A System.Windows.Forms.Control on it
3. I created an AbstractControlCollection object, which inherits from List<AbstractControl>. This simply provides a quicker means to do bulk operations on my collection of AbstractControls.
When the ResizeableForm gets painted, I initialize my AbstractControlCollection (if it is null):
private void onFormPaint(object sender, PaintEventArgs e)
{
if (_controls == null)
_controls = new AbstractControlCollection(this);
}
I also added a Resize event handler to make a call to my AbstractControlCollection.Resize() method:
private void onFormResize(object sender, EventArgs e)
{
if (_controls == null)
return;
_controls.Resize();
}
Obviously, the above code requires that you link up these delegates to the form's event handlers with the following lines:
this.Paint += new PaintEventHandler(onFormPaint);
this.Resize += new EventHandler(onFormResize);
The abstractcontrol object keeps track of ratios that the original control had, in terms of width and height, as well as distance from the top and left of the form. Below is the class:
/// <summary>
/// Stores information about a form, and provides a quick means
/// to resize a control when a form is resized
/// </summary>
public class AbstractControl
{
/// <summary>
/// The real control associated with this control
/// </summary>
Control _associatedControl;
/// <summary>
/// The form associated with the control
/// </summary>
ResizableForm _parentForm;
/// <summary>
/// Original Height ratio
/// </summary>
double _originalHeightRatio;
/// <summary>
/// Original width ratio
/// </summary>
double _originalWidthRatio;
/// <summary>
/// Original X Location of the control
/// </summary>
double _originalXRatio;
/// <summary>
/// Original Y Location of the form
/// </summary>
double _originalYRatio;
/// <summary>
/// The handle associated with the associated control
/// </summary>
IntPtr _handle;
public AbstractControl(Control c, ResizableForm originalForm)
{
_parentForm = originalForm;
_associatedControl = c;
_handle = c.Handle;
_originalHeightRatio = (double)c.Height / (double)originalForm.Height;
_originalWidthRatio = (double)c.Width / (double)originalForm.Width;
_originalXRatio = (double)c.Location.X / (double)originalForm.Width;
_originalYRatio = (double)c.Location.Y / (double)originalForm.Height;
}
/// <summary>
/// Public access to this control's handle
/// </summary>
public IntPtr Handle
{
get { return _handle; }
}
/// <summary>
/// Provides a means to resize the control based on the new form size
/// </summary>
public void Resize()
{
int newWidth = (int)((double)(_parentForm.Width * _originalWidthRatio));
int newHeight = (int)((double)(_parentForm.Height * _originalHeightRatio));
int newX = (int)((double)(_parentForm.Width * _originalXRatio));
int newY = (int)((double)(_parentForm.Height * _originalYRatio));
_associatedControl.Width = newWidth;
_associatedControl.Height = newHeight;
_associatedControl.Location = new System.Drawing.Point(newX, newY);
}
So, the remaining piece of the code is the Abstract Control Collection:
/// <summary>
/// Represents a collection of abstract controls
/// </summary>
public class AbstractControlCollection : List<AbstractControl>
{
/// <summary>
/// Form associated with the control collection
/// </summary>
ResizableForm _originalForm;
/// <summary>
/// Default constructor - adds controls to the collection based on the controls on the form
/// </summary>
/// <param name="originalForm">Form associated with the collection</param>
public AbstractControlCollection(ResizableForm originalForm)
{
_originalForm = originalForm;
addControls(originalForm);
}
/// <summary>
/// Method to add all controls and children controls to the collection
/// </summary>
/// <param name="baseControl">Control to add child controls from</param>
private void addControls(Control baseControl)
{
foreach (Control c in baseControl.Controls)
{
AbstractControl abstractControl = new AbstractControl(c, _originalForm);
if (!this.Contains(abstractControl, true))
this.Add(abstractControl);
addControls(c);
}
}
/// <summary>
/// Quick way to resize all the controls on the form at the same time
/// </summary>
public void Resize()
{
foreach (AbstractControl c in this)
c.Resize();
}
/// <summary>
/// Separate contains function to check to see if the collection contains a control
/// </summary>
/// <param name="control">Control to search for</param>
/// <param name="overrideIndicator">Overload var</param>
/// <returns>True if the collection contains the searched control</returns>
public bool Contains(AbstractControl control, bool overrideIndicator)
{
foreach (AbstractControl c in this)
{
if (control.Handle == c.Handle)
return true;
}
return false;
}
}
Conclusion
To use this code, simply add the files to your solution, and when creating a form, simply have it inhert from ResizeableForm, instead of System.Windows.Forms.Form. Everything else takes care of itself
Wednesday, July 14, 2010
A Thought On Collections
One of the things I often do when creating a collection class is to simply inherit from the List<> class of the type I want to collection-ize.
For instance, suppose I'm writing an application that needs a representation of a library (a book library, not a programmatic library). In the library, there would probably be a class called "Book," that would look something like this:
class Book
{
public string Title
{
///Getter and setter for the title
}
public Author BookAuthor
{
///Getter and setter for the book author
}
public void CheckoutBook()
{
///Perform behavior that checks out a book
}
public void CheckInBook()
{
///Perform behavior that checks in a book
}
}
This library would obviously need a representation for a collection of books. This collection could be manifested in a number of ways. The lazy way would be to simply create member variables within other classes that are of type List<>
class BookCollection : List <Book>
{
///Custom methods and attributes that
}
The reason I would do the above is because, with its own class, I have more flexibility moving forward with the use of a collection of books. One of the flexibility features the above offers is the context a collection of books can exist within; for instance, a collection of books could be any of the following:
1. All of the books in the library
2. All of the books a library visitor has checked out
3. All of the overdue books in the library
4. All of the overdue books a library visitor has checked out
5. All of the books a particular author has written
6. All of the books written in a particular month, year, decade, or century
7. All of the books in a particular genre
8. etc
With the BookCollection class, I have the option of representing any of the above collections as a simple book collection, or by using more inheritance to represent each. For instance:
class LibraryOverdueBooks : BookCollection
{
///particulars of all the library's overdue books
}
class LibraryVisitorOverdueBooks : BookCollection
{
///particulars of a particular visitor's overdue books
}
Because this sort of collection hierarchy is so common in programming, I felt inclined to write about it. Of course, there are lots of ways to represent a collection, especially with the System.Data namespace, or with Linq and its collection of IEnumerable flexibility. As the size of the collection grows, it often makes sense to reevaluate how you are implementing the collection, but in theory, the above is a simple, but effective way to represent collections, and it's pretty common to find code like this in the code I write.