Refactoring DBObject, Part 2

Note: I really shouldn’t call this refactoring because it’s an api change.

My SetProperty() and GetProperty() methods are really just my weak attempt to add KVC (Key Value Coding) to the DBObject. This is something built in to objective-c. So I want to rename these methods to reflect their true nature. (The word Property was confusing anyway.) It would also be nice if we could get the values via the object indexer. Although we don’t want to rely on this because the child class might wish to override it.

So SetProperty(string property, object value); will become setValueForKey(string key, object value);

and GetProperty(string property, object default); will now become valueforKey(string key);

and the overrideable valueForUndefinedKey(string key); which will be called when they key doesn’t exist.

Although there is the slight caveat that I’m not so sure that valueForUndefinedKey(string key); is better than the way GetProperty works by allowing you to pass a default value. I rather like being able to pass a default value. I guess I’ll try it out for a while and if I liked the default value better, I’ll just put it back in.

/// <summary>
/// Get the value for a specified key.
/// If key doesn't exist, valueForUndefinedKey(string key) will be called instead.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public object valueForKey(string key)
{
	if (_properties.ContainsKey(key))
	{
		return _properties[key];
	}
	return valueForUndefinedKey(key);
}
/// <summary>
/// Called when a key doesn't exist.
/// Override to impliment your own error handling.
/// </summary>
/// <param name="key"></param>
/// <returns>null</returns>
public object valueForUndefinedKey(string key)
{
	return null;
}
/// <summary>
/// Set a value for the key
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void setValueForKey(string key, object value)
{
	_properties[key] = value;
}

Something KVC in objective-c also gives us is the ability to listen for changes (Key Value Observing or KVO.) Let’s add that too.

Since I don’t know of any predefined delegates for this job, we will have to make our own.

public delegate void observeValueForKey(string forKey, DBObject forObject, object oldValue, object newValue);

Then we need something to hold these observers and a way for them to register for keys. I’m using a Dictionary to hold the events.
I’ve also changed the default constructor slightly so it’s easier for child classes set the table,index column, and connection string.

protected DBObject(string table_name, string index_column, string connection_string)
{
	_properties = new Hashtable();
	_kvo = new Dictionary<string, observeValueForKey>();
	this.TableName = table_name;
	this.IndexColumn = index_column;
	this.ConnectionString = connection_string;
}

/// <summary>
/// Add an observer for when the Key changes.
/// </summary>
/// <param name="key">The key you want to watch</param>
/// <param name="observer">delegate observeValueForKey</param>
public void addObserverForKey(string key, observeValueForKey observer)
{
	if (!_kvo.ContainsKey(key))
	{
		_kvo.Add(key, observer);
	}
	else
	{
		//Add the observer
		_kvo[key] += observer;
	}
}
/// <summary>
/// Remove an observer from the Key changes.
/// </summary>
/// <param name="key"></param>
/// <param name="observer"></param>
public void removeObserverForKey(string key, observeValueForKey observer)
{
	if (_kvo.ContainsKey(key))
	{
		_kvo[key] -= observer;
	}
}

 /// <summary>
/// Set a value for the key
/// </summary>
/// <param name="key"></param>
/// <param name="value"></param>
public void setValueForKey(string key, object value)
{
	//Save the old value
	object oldValue = _properties.ContainsKey(key) ? _properties[key] : null;
	//Change it
	_properties[key] = value;
	//Inform everyone of the change.
	if (_kvo.ContainsKey(key) && _kvo[key] != null) { ((observeValueForKey)_kvo[key])(key, this, oldValue, value); }
}

Now you can easily be informed when a key changes.
One thing still missing is KeyPath. Key let’s us get just the value stored by the object. For example User.valueForKey("column_id") But what if the value is a list of objects? It would be nice to do something like User.valueForKeyPath("tags.column_id") (Objective-C does this.) Maybe I’ll implement something like that later.

Continue to Part 3
or
Go back to Part 1

Share

You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

1 Comment »

 
  • We’re a group of volunteers and starting a new scheme in our community. Your web site offered us with valuable information to work on. You have done an impressive process and our whole community will be thankful to you.

 

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

CommentLuv Enabled