Fluent Interface for System.Identity – Kind Command-Query API

Part 1 of this series functioned as an introduction to the motivations for creating a fluent interface for Oslo’s System.Identity. Part 1 also covered a number of architectural and design specifications that will be followed in the shaping of the interface’s code. In this post I’ll continue the crafting of the fluent interface by exploring an implementation of the Kind command-query API.

 

Refactoring the Base

Before I tackle the Kind class, I need to spend a little bit of time refactoring the SystemIdentityBase class that I developed in Part 1. Specifically, the class needs to be changed to more accurately reflect it’s use as a base class for command-query API child classes in the fluent interface. The code snippet below illustrates the latest rev of the SystemIdentityBase class:

    1: public abstract class SystemIdentityBase
    2: {
    3:     protected Int64 Id { get; private set; }
    4:     protected int Folder { get; private set; }
    5:  
    6:     public SystemIdentityBase ()
    7:     {
    8:         MoveToFolder ( 100 );
    9:     }
   10:  
   11:     public SystemIdentityBase ( int folder )
   12:     {
   13:         MoveToFolder ( folder );
   14:     }
   15:  
   16:     public bool IsInFolder ( int folder )
   17:     {
   18:         return Folder == folder;
   19:     }
   20:  
   21:     public void MoveToFolder ( int folder )
   22:     {
   23:         Folder = folder;
   24:     }

As the snippet above illustrates, the SystemIdentityBase class’ properties have been refactored to allow child classes access to the ‘get’ properties. As we will see later in the series, direct access to these properties will make future code much cleaner without fracturing the OO design. The code snippet also illustrates the refactoring of the class constructors to use the MoveToFolder () method. This refactoring centralizes the ‘set’ functionality in a single location, thereby allowing future logic to reside in a single place – not rocket science to be sure, but nice nevertheless.

 

Breaking “Tell, Don’t Ask”

Now that we have our base class refactored, we can take a stab at the Kind class. The very first thing that we’ll do with the Kind class is break “Tell, Don’t Ask”:

    1: public class Kind : SystemIdentityBase
    2: {
    3:     public string Name { get; private set; }
    4:     public string DescriptiveInformation { get; private set; }
    5: }

Hopefully what the code snippet above illustrates is that there are times when it is appropriate from an OO design perspective to allow clients to ask an object about the object’s state. I would argue that line #3 in the snippet reflects very much the way things work in the real world and, therefore, is good OO design.

Think about the legal system here in the US. When in a court of law a witness is not asked a series of questions (e.g., “Is your name John?”, “Is your name David?”) to establish the witness’ identity – the witness states their name for the record. Additionally, changing one’s legal name in the US is not a trivial affair – there is a process involved that sometimes rejects the name change (although my understanding is that this is rare).

These concepts are modeled in the code snippet above by allowing public read access to the Name property, but making changes to Name private.

The same real-world experience is applied to a Kind’s DescriptiveInformation. In the real world no one is asked “Are you male?” or “Is your weight 187 pounds?”. As with names, descriptive information is directly solicited in the real world. As those of us who have tried to lose weight know, it is often a nontrivial effort to change our descriptive information as well :-).

The remaining two properties of the Kind class don’t fall into the same category as Name and DescriptiveInformation so I’ll make them private:

    1: public class Kind : SystemIdentityBase
    2: {
    3:     public string Name { get; private set; }
    4:     public string DescriptiveInformation { get; private set; }
    5:     private string Keywords { get; set; }
    6:     private Party Owner { get; set; }
    7: }

 

Back to “Tell, Don’t Ask”

In accordance with the “Tell, Don’t Ask” architectural specification, I’ll add some methods to the Kind class’ interface:

    1: public void ChangeName ( string name )
    2: {
    3:     Name = name;
    4: }
    5:  
    6: public void ChangeDescription ( string descriptiveInformation )
    7: {
    8:     DescriptiveInformation = descriptiveInformation;
    9: }
   10:  
   11: public void ChangeKeywords ( string keywords )
   12: {
   13:     Keywords = keywords;
   14: }

The ChangeName(), ChangeDescription(), and ChangeKeyword() methods are straightforward, so I won’t belabor them. The following methods that I’ll add are far more interesting:

    1: public bool MatchesKeywords ( Func<string, bool> matchingSpecification )
    2: {
    3:     return matchingSpecification ( Keywords );
    4: }
    5:  
    6: public bool MatchesKeyword ( string keyword, KeywordComparisonType comparisonType )
    7: {
    8:     switch ( comparisonType )
    9:     {
   10:         case KeywordComparisonType.CaseSensitive:
   11:             return Keywords.Contains ( keyword );
   12:         case KeywordComparisonType.CaseInsensitive:
   13:             return Keywords.ToLower ().Contains ( keyword.ToLower () );
   14:         default:
   15:             throw new ArgumentOutOfRangeException ();
   16:     }
   17: }

The MatchesKeywords() method, arguably, is the epitome of “Tell, Don’t Ask” – it allows a client to provide the exact means of deciding a keyword match through the use of a delegate. By way of comparison, the MatchesKeyword() method doesn’t use a lot of “tech” to get the job done. For those that are curious about the implementation of the switch statement in the snippet above, I would refer you to “Effective C#”, Item #8 for more info.

The following snippet finishes up this rev of the Kind class by addressing the Owner functionality:

    1: public void ChangeOwner ( Party owner )
    2: {
    3:     Owner = owner;
    4: }
    5:  
    6: public bool IsOwnedBy ( Party owner )
    7: {
    8:     if ( Owner == null || owner == null )
    9:     {
   10:         return false;
   11:     }
   12:     else
   13:     {
   14:         return Owner.Equals ( owner );
   15:     }
   16: }

Generally speaking, there’s not much in the snippet above that we haven’t seen already. The one exception to this is line #14 – the call to the Equals() method of the Owner object (which is an instance of the Party class). While this line of code appears trivial, it does in fact have some very interesting ramifications to the fluent interface implementation.

These ramifications are born of the fact that System.Identity is shipped as part of the latest Oslo CTP’s Repository – which means that the fluent interface must also address concerns related to persistence.

 

Next Time

For the next post in the series I’ll address some of the ORM considerations that arise from Oslo’s use of SQL Server as the System.Identity persistence mechanism.

Stay tuned!