class Item
{
//Return either a real string or null
string GetParentName()
{
Item parent = GetParent();
if (parent == null)
{
return null;
}
else
{
return parent.GetName();
}
}
}
void SetupTextBox(Item myItem, TextBox someTextBox)
{
string parentName = myItem.GetParentName();
if (parentName != null)
{
//TextBox::SetText(string) will throw an exception
//if it is passed a null
someTextBox.SetText(parentName);
}
}
A way to fix that is to change the class' interface. Instead of getting values from the class, let's tell the class to tell its information to somebody.
class Item
{
string TellParentNameTo(StringReceiver receiver)
{
Item parent = GetParent();
if (parent != null)
{
receiver.SetString(parent);
}
}
}
void SetupTextBox(Item myItem, TextBox someTextBox)
{
//myItem will do the best that he can do, even if he
//has a null
myItem.TellParentNameTo(someTextBox);
}
The biggest problem with the second example is that you need to have really, REALLY broad interfaces that are used everywhere. In this example, TextBox would need to be a StringReceiver. In fact, anybody that could conceivably get a string from an Item would need to be a StringReceiver. If TextBox were written so that it is a StringReceiver from the beginning, everything works great. However, suppose that StringReceiver was written later than TextBox. Either TextBox will need to get it retrofitted, or an adapter class will need to be written:
class Item
{
string TellParentNameTo(StringReceiver receiver)
{
Item parent = GetParent();
if (parent != null)
{
receiver.SetString(parent);
}
}
}
class TextBoxStringReceiverAdapter
{
TextBoxStringReceiverAdapter(TextBox textBox) {}
void SetString(string str)
{
textBox.SetText(str);
}
}
void SetupTextBox(Item myItem, TextBox someTextBox)
{
//myItem will do the best that he can do, even if he
//has a null
myItem.TellParentNameTo(
new TextBoxStringReceiverAdapter(
someTextBox)
);
}
No comments:
Post a Comment