In part 2 of our series, I presented a simple example of a traditional unit test. In this article, we’ll discuss a completely different way to use unit tests: Test First Programming.
Test-First Programming
In the book Extreme Programming Explained: Embrace Change published in October 1999, Kent Beck introduced what was at the time a rather foreign concept to software development: Writing unit tests to drive software design. Described as Test-First Programming, the technique involves first writing a test to verify a small increment of desired functionality and then writing code to make the test pass. This process is then repeated until no additional functionality is desired.
Incremental Design
Another practice introduced alongside Test-First Programming was Incremental Design. Incremental design is the process of evolving the design of an application as new functionality is developed and better design approaches are recognized. Due to the fact that software development is an inherently empirical process, following a defined model where the the software is designed up front generally leads to waste and rework. Incremental design postpones design decisions until needed, introducing patterns and frameworks as a byproduct of refactoring as well as eliminating any flexibility that is unused.
Test Driven Development
Later, these ideas were refined into a practice known as Test Driven Development. Test-Driven Development can be described simply as the ideas of Test-First Programming coupled with Incremental Design. In a later book entitled Test-Driven Development By Example published in November of 2002, Beck presents a refined process involving the writing of a failing test, taking the simplest steps possible to make the test pass, and removing any duplication introduced. This process was described succinctly as Red/Green/Refactor, where red and green referred to the colors typically presented by test runners to indicate failing and passing tests respectively.
Behavior-Driven Development
While the practice of Test-Driven Development utilized unit tests primarily for driving application design, its outgrowth from traditional unit testing practices were still evident in its style, language, and supporting frameworks. This presented an obstacle for some in understanding and communicating the concepts behind the practice.
In the course of teaching and practicing TDD, Dan North began encountering various strategies for designing tests in a more intent-revealing way which aided in his understanding and ability to convey the practice to others. As a way to help distinguish the differences between what he saw as an exercise in defining behavior rather than testing, he began describing the practice of Test-Driven Development as Behavior Driven Development. By shifting the language to the discussion about behavior, he found that many of the questions he frequently encountered in presenting TDD concepts became easier to answer. North went on to introduce a framework incorporating this shift in thinking called JBehave. North’s work on JBehave along with his promotion of the ideas behind Behavior-Driven Development served as the inspiration for the creation of many other frameworks including RSpec, Cucumber, NBehave, NSpec, SpecFlow, MSpec and many others.
Behavior-Driven Development Approaches
Two main approaches have emerged from BDD practices which I’ll categorize as the Plain-Text Story approach and the Executable Specification approach.
Plain-Text Stories
With the Plain-Text Story approach, software features are written as a series of plain-text scenarios which the framework associates with executable steps used to drive feature development. This approach is typically associated with a style referred to Given/When/Then (GWT), named after the grammar set forth by Dan North. This style is facilitated by popular BDD frameworks such as Cucumber and JBehave.
The following is an example story using Gherkin grammar, the language used by Cucumber and other Plain-Text Story BDD frameworks:
Feature: Addition
In order to calculate totals
As a user
I want to calculate the sum of multiple numbers
Scenario: Add two numbers
Given I have entered 10 into the calculator
And I have entered 50 into the calculator
When I press add
Then the result should be 60 on the screen
Using Cucumber, the “Given” step in this scenario may then be associated to the following step definition in Ruby:
Given /I have entered (\d+) into the calculator/ do |n| calc = Calculator.new calc.push n.to_i end
Using SpecFlow, the same “Given” step can also be associated to the following step definition in C#:
[Given("I have entered (.*) into the calculator")]
public void GivenIHaveEnteredSomethingIntoTheCalculator(int number)
{
_calculator = new Calculator();
_calculator.Enter(number);
}
Executable Specifications
In contrast to the use of plain-text stories, the Executable Specification approach uses source code as the medium for expressing specifications in the language of the business. Executable Specifications can be written using existing unit-testing frameworks such as JUnit, NUnit, and MSTest, or are written in frameworks designed exclusively to facilitate the Behavior-Driven Development style such as RSpec and MSpec.
One style, referred to as Context/Specification, expresses software features in terms of specifications within a given usage context. In this style, each unique way the software will be used is expressed as a context along with one or more expected outcomes.
While specialized frameworks have been created to support the Context/Specification style, this approach can also be facilitated using existing xUnit frameworks. This is generally accomplished by creating a Context base class which uses the Template Method pattern to facilitate the desired language.
The following example demonstrates this technique using the NUnit framework:
[TestFixture]
public abstract class Context
{
[TestFixtureSetUp]
public void setup()
{
establish_context();
because_of();
}
[TestFixtureTearDown]
public void teardown()
{
cleanup();
}
protected virtual void establish_context()
{
}
protected virtual void because_of()
{
}
protected virtual void cleanup()
{
}
}
In addition to providing a Contact base class, the NUnit framework’s TestAttribute can also be sub-classed to aid in moving toward specification-oriented language:
public class ObservationAttribute : TestAttribute {}
By extending the Context base class, NUnit can then be used to write Context/Specification style BDD specifications:
public class when_adding_two_numbers : Context
{
Calculator _calculator;
protected override void establish_context()
{
_calculator = new Calculator();
_calculator.Enter(2);
_calculator.PressPlus();
_calculator.Enter(2);
}
protected override void because_of()
{
_calculator.PressEnter();
}
[Observation]
public void it_should_return_the_correct_sum()
{
Assert.AreEqual(_calculator.Result, 4);
}
}
Working, Maintainable Software That Matters
The ideas behind Test-First Programming continue to be refined by the software development community and have lead to still other variations in name and style, including Example Driven-Development, Specification-Driven Development, Need-Driven Development, and Story Test-Driven Development. Regardless of its label or flavor, the refinements of Test-First Programming can be distilled down to the following goal: The creation of working, maintainable software that matters. That is to say, the software should be functional, should be easily maintainable and should be relevant to needs of our customers.
Conclusion
This time we discussed Test-First Programming and traced its steps to today’s practice of Behavior-Driven Development. Next time we’ll discuss Test-Driven Development in more detail and walk through a Test First example using the TDD methodology while incorporating some of the Behavior-Driven Development concepts presented here.
In part 1 of our series, I introduced some common types of automated tests: Unit Tests, Integration Tests, and Acceptance Tests. In this article, we’ll take a look at a traditional approach to unit testing and discuss a few practices surrounding good test communication.
First Things First
Before getting started, we obviously need something to test, so let’s create a Calculator class.
public class Calculator
{
bool _isDirty;
string _operation;
decimal _state;
public decimal Display { get; private set; }
public void Enter(decimal number)
{
_state = number;
_isDirty = true;
}
public void PressPlus()
{
_operation = "+";
if (_isDirty) Calculate();
}
public void PressEquals()
{
if (_isDirty) Calculate();
}
void Calculate()
{
switch (_operation)
{
case "+":
Display += _state;
break;
}
_isDirty = false;
}
}
To keep things simple, our Calculator class just adds decimals, but that gives us enough to work with for our discussion.
Anatomy of a Unit Test
Now, let’s create a unit test to validate that our Calculator class behaves properly. I’ll use NUnit for this example:
[TestFixture]
public class CalculatorTests
{
[Test]
public void TestPressEquals()
{
Calculator calculator = new Calculator();
calculator.Enter(2m);
calculator.PressPlus();
calculator.Enter(2m);
calculator.PressEquals();
Assert.AreEqual(4m, calculator.Display);
}
}
So, what’s going on here? Starting at the top, we have a class with a TestFixture attribute. This tells NUnit that this class contains unit tests. We’ve named our test “CalculatorTests” to denote that this class contains the tests for our Calculator class. Pretty descriptive, eh?
Next, we’ve defined a method with a Test attribute. This tells NUnit that this method should be considered a test when it scans our types for tests to execute. We’ve named our method TestPressEquals() to denote that we’re testing the behavior of the PressEquals method.
The use of the prefix “Test” is a common convention which originated from a requirement within earlier versions of JUnit. The first version of NUnit was a direct port of JUnit and therefore shared this requirement until it was rewritten to take advantage of .Net attributes.
Next, we’ve defined an instance of the Calculator class we’re going to be testing. In unit testing parlance, this is generally called the System Under Test, or the SUT.
Next, we make several calls to the calculator object to instruct it to add two numbers and then call the PressEquals() method.
Our final call is to the NUnit Assert.AreEqual() method. This method tests the expected value against the actual value and raises an exception if the values are not equal.
If we run the test at this point, we should see our test pass.
Hooray!
Improving Communication
While our test certainly does the job of validating the Calculator’s behavior, there are a few aspects of our test that we could improve upon. To start, let’s consider what would be displayed should our test actually ever fail. To force it to fail, I’ll comment out the line which increments the Display property. Running the test produces the following:
CalculatorTests.TestPressEquals : Failed Expected: 4m But was: 0m
Ok, so CalculatorTests.TestEquals failed because "expected 4m, but was 0m". Given that we’ve just written this test, this may not seem like much of an issue. The context of how our Calculator class works as well as how our test verifies it behavior is still fresh in our minds. But what if this fails six months from now? Worse, what if it fails and is discovered by someone who wasn’t the author of this test? Without looking at the test code, the most that could be derived from this message is that the Calculator.PressEquals method failed in some way. Let’s see if we can improve upon this.
What would be great is if we could have the test runner print out a descriptive message describing what didn’t work. As it happens, NUnit provides an overload to the TestEquals method which allows us to supply our own message. Let’s change our test to include a custom message:
[Test]
public void TestPressEquals2()
{
var calculator = new Calculator();
calculator.Enter(2);
calculator.PressPlus();
calculator.Enter(2);
calculator.PressEquals();
Assert.AreEqual(4, calculator.Display,
"When adding 2 + 2, expected 4 but found {0}.", calculator.Display);
}
When we run the test again, we get the following:
CalculatorTests.TestPressEquals : Failed When adding 2 + 2, expected 4 but found 0. Expected: 4m But was: 0m
By supplying a custom message, our test now provides some context around why the test failed. As an added benefit, our custom message also adds a bit of description to the purpose of our test when reading the source code.
Unfortunately, these changes have introduced a bit of duplication into our test code. We now have the expected result, the actual result, and the values being added together repeated throughout out test. Also, it seems like a good idea to have the assert message automatically reflect any changes that might be made to the values used by the test. Let’s take a stab at reducing the duplication:
[Test]
public void TestPressEquals2()
{
var value1 = 2m;
var value2 = 2m;
var calculator = new Calculator();
calculator.Enter(value1);
calculator.PressPlus();
calculator.Enter(value2);
calculator.PressEquals();
decimal expected = 4m;
decimal actual = calculator.Display;
Assert.AreEqual(expected, actual,
"When adding {0} + {1}, expected {2} but found {3}.", value1, value2, expected, actual);
}
Now we’ve eliminated the duplication, but the test doesn’t seem as easy to follow. Also, our custom message no longer communicates the purpose of the test clearly. If we revisit this test later, we might as well work through the logic of the test than work through the logic of what this assertion is going to produce. Let’s stick to our principles on keeping our code free of duplication for now, but we’ll revisit this topic later in our series.
Aside from there being nothing about our test that allows us to easily pick up on what’s occurring, our code is also looking a little crowded. We could easily address this by spacing things out a bit and perhaps adding a few comments.
One popular style of organization is a pattern first described by Bill Wake as Arrange, Act, Assert. With this organization, the test is separated into three sections: one which Arranges the objects to be used as part of the test, one which Acts upon the objects, and one which Asserts that the expected outcomes have occurred. Since our test mostly follows this sequence already, let’s just space the sections out a bit and add some comments denoting the Arrange, Act and Assert sections:
[Test]
public void TestPressEquals()
{
// Arrange
decimal value1 = 2m;
decimal value2 = 2m;
decimal expected = 4m;
var calculator = new Calculator();
// Act
calculator.Enter(value1);
calculator.PressPlus();
calculator.Enter(value2);
calculator.PressEquals();
decimal actual = calculator.Display;
// Assert
Assert.AreEqual(expected, actual,
"When adding {0} + {1}, expected {2} but found {3}.", value1, value2, expected, actual);
}
That organizes the flow of the test a bit better, but we’re still missing the clarity that initial custom message was providing. We could communicate this through a comment as well, but another approach would be to just improve upon the actual test name.
One common naming convention is to create a name reflecting the name of the method being tested, the scenario being tested and the expected behavior. Let’s change our test method name to reflect this convention:
[Test]
public void PressEquals_AddingTwoPlusTwo_ReturnsFour()
{
// Arrange
decimal value1 = 2m;
decimal value2 = 2m;
decimal expected = 4m;
var calculator = new Calculator();
// Act
calculator.Enter(value1);
calculator.PressPlus();
calculator.Enter(value2);
calculator.PressEquals();
decimal actual = calculator.Display;
// Assert
Assert.AreEqual(expected, actual,
"When adding {0} + {1}, expected {2} but found {3}.", value1, value2, expected, actual);
}
After we’ve adjusted to reading this naming convention, we can now derive the same information that was communicated in that first message. Someone get a banner printed up, we’re declaring victory!
Conclusion
In this article, we’ve taken a look at a basic approach to writing unit tests and introduced a few techniques for improving unit test communication. While our resulting test correctly validates the behavior of our class, communicates what it does and provides a descriptive error message when it fails, there’s still room for improvement. In our next article, we’ll discuss some alternative approaches that will facilitate these goals as well as help us write working, maintainable software that matters.
This is part 1 of a series discussing topics surrounding effective automated testing. Automated testing can be instrumental to both the short and long-term success of a project. Unfortunately, it is too often overlooked due to either a lack of knowledge of how to incorporate test into an existing process, or a lack of recognition of the deficiencies within an existing process. As with any new pursuit, learning how to use automated testing effectively within a development process can take time. The goal of this series is to help those new to the practice of automated testing by gradually introducing concepts which aid in the creation of working, maintainable software that matters.
This introduction will start things off by discussing some of the fundamental types of automated tests.
Unit Testing
Unit tests are perhaps the most widely recognized form of test automation. A Unit Test is a process which validates behavior within an application in isolation from any of its dependencies. Unit tests are typically written in the same language as the software being tested, take the form of a method or class designed for a particular testing framework (such as JUnit, NUnit, or MSTests) and are generally designed to validate the behavior of individual methods or functions within an application. The behavior of a component being tested can be isolated from the behavior of its dependencies using substitute dependencies known as Test Doubles. By testing each component’s behavior in isolation, failing tests can be used to more readily identify which components are causing a regression in behavior.
The primary goal of traditional unit testing is verification. By establishing a suite of unit tests, the software can be tested each time modifications are made to ensure the software still behaves as expected. To ensure that existing tests are always run when modifications are introduced, the tests can also be run at regular intervals or triggered as part of a check-in policy using a process known as Continuous Integration.
Integration Testing
While unit tests are useful for verifying that the encapsulated behavior of a component works as expected within a known context, they often fall short of anticipating how the component will interact with other components used by the system. Tests which verify that components behave as expected with all, or a subset of their real dependencies are often categorized as Integration Tests. Of particular interest are interactions with third-party libraries and external resources such as file systems, databases, and network services. This is due to the fact that the behavior of such dependencies may not be fully known or controlled by the consuming development team, or may change in unexpected ways when new versions are introduced.
Integration tests often require more setup and/or reliance upon communication with external processes and are therefore usually slower than unit test suites. Due to this fact, separate strategies are often used to ensure regular feedback of integration tests. In some cases, slow-running tests can be mitigated by the use of “almost-real” substitutes such as in memory file systems and databases which are known to adequately represent the functionality expected by the real dependencies.
While the term “integration test” is often applied to any test verifying the behavior of collaborating components, it can be useful for test organization and the development of testing strategies to draw a distinction between tests which verify integration with disparate systems and those that verify that a collection of classes correctly provide a logical service. In the book xUnit Test Patterns: Refactoring Test Code, Gerard Meszaros refers to tests for such collaborating classes as Component Tests. While both test the interaction of multiple components, Component Tests ask the question “Does this logical service perform the expected behavior?” while Integration Tests asks the question “Do these components work together?”.
Acceptance Testing
Acceptance tests, or end-to-end tests, verify that particular use cases of the system work as a whole. Such tests are characterized by a focus on how the system will be used by the customer by exercising as much of the real system as possible. While finer-grained tests such as unit and component tests can help ensure the functional integrity of the individual components, acceptance testing ensures that the components function correctly together.
Although the purpose of acceptance testing is to verify the system works as a whole, it may still be necessary in some cases to substitute portions of the system where full end-to-end testing isn’t cost-effective or practical. For instance, some external services may not provide integration testing environments or may place limits on its use. In other cases, the user interface technology used may not lend itself to test automation in which case tests may be written against a layer just below the user interface layer. This is referred to as Subcutaneous Testing.
Classifications
The terms unit test, integration test and acceptance test classify tests in terms of their utility. Another way to classify tests are in terms of their audience. In Extreme Programming (XP), tests are broken down into the categories of Customer Tests and Programmer Tests. Customer Tests are synonymous with User Acceptance Tests and are focused on the external quality of the system. Programmer Tests are similar to Unit Tests in that they are written by programmers and are generally focused on the internal quality of the system, but they are less prescriptive about their level of test isolation. Programmer Tests will be discussed in more detail later in our series.
Conclusion
This article presents only a brief introduction to some of the classifications of automated tests. We’ll continue to explore these and others throughout the series. Next time, we’ll take a look a traditional approach to writing unit tests.
In the course of doing some reading on Scala and Clojure, I stumbled upon an interesting article by Mogens Heller Grabe entitled C# vs. Clojure vs. Ruby & Scala. In the article, Mogens provides a C# solution to a word frequency counting exercise, originally demonstrated in Ruby & Scala, and later in other languages in attempt to showcase how each measures up.
The problem takes an archive of newsgroup articles and creates one file containing a list of all unique words with their occurrence count sorted by word and another sorted by occurrence.
Here is Mogens’ C# solution:
class Program
{
static void Main()
{
const string dir = @"c:\temp\20_newsgroups";
Stopwatch stopwatch = Stopwatch.StartNew();
var regex = new Regex(@"\w+", RegexOptions.Compiled);
var list = (from filename in Directory.GetFiles(dir, "*.*", SearchOption.AllDirectories)
from match in regex.Matches(File.ReadAllText(filename).ToLower()).Cast<Match>()
let word = match.Value
group word by word
into aggregate
select new
{
Word = aggregate.Key,
Count = aggregate.Count(),
Text = string.Format("{0}\t{1}", aggregate.Key, aggregate.Count())
})
.ToList();
File.WriteAllLines(@"words-by-count.txt", list.OrderBy(c => c.Count).Select(c => c.Text).ToArray());
File.WriteAllLines(@"words-by-word.txt", list.OrderBy(c => c.Word).Select(c => c.Text).ToArray());
Console.WriteLine("Elapsed: {0:0.0} seconds", stopwatch.Elapsed.TotalSeconds);
}
}
While my lack of familiarity with the languages used in the other examples made it a little more difficult to appreciate their strengths, I felt the C# example provided by Mogens was fairly concise and intuitive by comparison. Nevertheless, I couldn’t help wondering if I might be able to improve it in some way, so I set out to see what I could come up with.
Here are the results:
static void Solution2()
{
var regex = new Regex(@"\W+", RegexOptions.Compiled);
var d = new Dictionary<string, int>();
Directory.GetFiles(dir, "*.*", SearchOption.AllDirectories)
.ForEach(file => regex.Split(File.ReadAllText(file).ToLower())
.ForEach(s => d[s] = 1 + (d.ContainsKey(s) ? d[s] : 0)));
File.WriteAllLines(@"words-by-count2.txt", d.OrderBy(p => p.Value).Select(p => string.Format("{0}\t{1}", p.Key, p.Value)));
File.WriteAllLines(@"words-by-word2.txt", d.OrderBy(p => p.Key).Select(p => string.Format("{0}\t{1}", p.Key, p.Value)));
}
The primary differences in this example are the use of a Dictionary to accumulate the frequency count rather than grouping, and the use of the Regex.Split rather than Regex.Match to avoid the need of casting the resulting collection. Based on my measurements, this approach is approximately 36% faster on average than the first solution and is a bit more concise.
Overall, I don’t think this example has a varied enough problem domain to really compare the strengths of different languages as some have done, but I found it a fun exercise to see how I might improve the original C# version nonetheless.
Not too long ago, I ventured into using Rake for my .Net project builds. Given that my shell preference on Windows is Cygwin’s bash port (via the excellent mintty terminal), I tend to prefer installing the Cygwin ruby package rather than using the RubyInstaller for Windows.
One issue I ran into, however, was that the absolute paths generated under rake resolve to /cygdrive/c/ by default. This isn’t an issue when calling applications compiled for Cygwin, but they pose a problem if you need to pass an absolute path as a parameter to commands like MSBuild. One way to resolve this problem is to create an NTFS mount point which mirrors a path that Windows executables can resolve. Here’s how:
Open up the file /etc/fstab which configures the mount table under Cygwin. Add a line similar to the following:
C:/projects /projects ntfs binary,posix=0,user 0 0
This mounts the C:/projects folder (where I do all of my project development) as /projects. Note that the mount point must be named the same as the actual physical NTFS path. After restarting the shell, the new mount point will be available. This can be verified by issuing the mount command:
> mount C:/cygwin/bin on /usr/bin type ntfs (binary,auto) C:/cygwin/lib on /usr/lib type ntfs (binary,auto) C:/projects on /projects type ntfs (binary,posix=0,user) C:/cygwin on / type ntfs (binary,auto) C: on /cygdrive/c type ntfs (binary,posix=0,user,noumount,auto) D: on /cygdrive/d type iso9660 (binary,posix=0,user,noumount,auto) F: on /cygdrive/f type iso9660 (binary,posix=0,user,noumount,auto) G: on /cygdrive/g type ntfs (binary,posix=0,user,noumount,auto) H: on /cygdrive/h type ntfs (binary,posix=0,user,noumount,auto) I: on /cygdrive/i type vfat (binary,posix=0,user,noumount,auto)
Since Windows accepts the forward slash as a directory delimiter and considers drive letters to be optional, expanding a relative path under the NTFS mount point will render a path that can be correctly interpreted by Windows executables.
Overview
The basic rules engine works as follows:- A user invokes some Controller action.
- The Controller takes the action’s parameter and invokes the RulesEngine.Process() method.
- The RulesEngine invokes an injected implementation of IRuleValidator.Validate() on the object.
- The IRulesValidator returns a RuleValidationResult denoting the status of the validation as well as containing any validation error messages.
- The RulesEngine uses the Common Service Locator to find implementations of ICommand<T> where T matches the type of the object.
- The implementations of ICommand<T> are executed and any results accumulated.
- The RulesEngine returns a ProcessResult which contains the process status and any validation messages and return items.
- The Controller uses the status to determine which action to display. In the event of a validation failure, the error messages are added to the ModelState with their associated property names.
[HttpPost]
public ActionResult Create(ProductInput productInput)
{
ProcessResult results = _rulesEngine.Process(productInput);
if (!results.Successful)
{
CopyValidationErrors(results);
return View(productInput);
}
return RedirectToAction("Index");
}
void CopyValidationErrors(ProcessResult results)
{
foreach (RuleValidationFailure failure in results.ValidationFailures)
{
ModelState.AddModelError(failure.PropertyName, failure.Message);
}
}
In an example application I’ve included with the source, I created an implementation of the IRulesValidator which adapts to the Fluent Validation library:
public class FluentValidationRulesValidator : IRulesValidator
{
public RuleValidationResult Validate(object message)
{
var result = new RuleValidationResult();
Type validatorType = typeof (AbstractValidator<>).MakeGenericType(message.GetType());
var validator = (IValidator) ServiceLocator.Current.GetInstance(validatorType);
ValidationResult validationResult = validator.Validate(message);
if (!validationResult.IsValid)
{
foreach (ValidationFailure error in validationResult.Errors)
{
var failure = new RuleValidationFailure(error.ErrorMessage, error.PropertyName);
result.AddValidationFailure(failure);
}
}
return result;
}
}
This uses the Common Service Locator to find types closing the Fluent Validation AbstractValidator generic type, validates the message with the validator, and adds any validation error messages to the RuleValidationResult.
Mapping
I also included the ability to map UI types to domain types using a library such as AutoMapper. To express this as an optional feature, I created a MappingRulesEngine which has a dependency on an IMessageMapper. At first I went back and forth between expressing an IMessageMapper as an optional dependency to the RulesEngine, but I don’t really like property injection and the notion of using constructor injection for optional dependencies was a bit distasteful, so using inheritance felt like the cleanest and most expressive option. The MappingRulesEngine uses the Common Service Locator to find a type closing AssociationConfiguration<T> which provides the type to be converted to as well as configuration used by the MappingRulesEngine to associate validation error messages on the domain type back to the origin properties on the UI type. The following is an example usage:
public class ProductInputAssociationConfiguration : AssociationConfiguration<ProductInput>
{
public ProductInputAssociationConfiguration()
{
ConfigureAssociationsFor<Product>(x =>
{
x.For(output => output.Id).Use(input => input.Id);
x.For(output => output.Description).Use(input => input.Description);
x.For(output => output.Price).Use(input => input.Price);
});
}
}
That’s about it. You can get the source at http://github.com/derekgreer/ncommons.
The Visitor Pattern
The Visitor pattern encapsulates common behavior within a single class which is applied to each of the elements of the object structure. The following diagram depicts the pattern structure:
The Visitor pattern is comprised of three main types of participants: the Visitor, the Element, and the Object Structure. The Visitor encapsulates the common behavior needed across different types of elements. Elements are the types within an object structure for which common behavior is needed. The Object Structure is the element container and may take the form of a collection or composite.
Each visitor defines methods specific to each type of element within the object structure while elements define a method capable of accepting a Visitor. When a client desires to apply the visitor behavior to each of the elements, the object structure is used to orchestrate delivery of the visitor to each element. Upon receiving the visitor, each element calls a corresponding method on the visitor, passing a reference to itself as the method parameter. Once invoked, the visitor’s methods are capable of accessing state or invoking behavior specific to each type of element.
class Program
{
static void Main(string[] args)
{
var thermostat = new Thermostat();
var partsManifestVisitor = new PartsManifestVisitor();
var dangerousGoodsManifestVisitor = new DangerousGoodsManifestVisitor();
thermostat.Accept(partsManifestVisitor);
thermostat.Accept(dangerousGoodsManifestVisitor);
Console.WriteLine("Parts List");
Console.WriteLine("----------");
partsManifestVisitor.PrintManifest(Console.Out);
Console.WriteLine("nDangerous Goods List");
Console.WriteLine("----------");
dangerousGoodsManifestVisitor.PrintManifest(Console.Out);
Console.ReadLine();
}
}
interface IComponentVisitor
{
void Visit(Thermostat thermostat);
void Visit(ThermostatCover thermostatCover);
void Visit(CircutBoard circutBoard);
void Visit(MercurySwitch mercurySwitch);
void Visit(BimetallicStrip bimetallicStrip);
void Visit(HeatAnticipator heatAnticipator);
}
interface IComponentElement
{
void Accept(IComponentVisitor visitor);
}
class Thermostat : IComponentElement
{
readonly IComponentElement[] _elements;
public Thermostat()
{
_elements = new IComponentElement[]
{
new ThermostatCover(),
new CircutBoard(),
new MercurySwitch(),
new BimetallicStrip(),
new HeatAnticipator()
};
}
public void Accept(IComponentVisitor visitor)
{
visitor.Visit(this);
foreach (var element in _elements)
{
element.Accept(visitor);
}
}
}
class ThermostatCover : IComponentElement
{
public void Accept(IComponentVisitor visitor)
{
visitor.Visit(this);
}
}
class CircutBoard : IComponentElement
{
public void Accept(IComponentVisitor visitor)
{
visitor.Visit(this);
}
}
class MercurySwitch : IComponentElement
{
public void Accept(IComponentVisitor visitor)
{
visitor.Visit(this);
}
}
class BimetallicStrip : IComponentElement
{
public void Accept(IComponentVisitor visitor)
{
visitor.Visit(this);
}
}
class HeatAnticipator : IComponentElement
{
public void Accept(IComponentVisitor visitor)
{
visitor.Visit(this);
}
}
class PartsManifestVisitor : IComponentVisitor
{
IList<string> manifest = new List<string>();
public void PrintManifest(TextWriter textWriter)
{
manifest.ToList().ForEach(x => textWriter.WriteLine(x));
}
public void Visit(Thermostat thermostat)
{
manifest.Add("Thermostat");
}
public void Visit(ThermostatCover thermostatCover)
{
manifest.Add("Thermostat cover");
}
public void Visit(CircutBoard circutBoard)
{
manifest.Add("Circut board");
}
public void Visit(MercurySwitch mercurySwitch)
{
manifest.Add("Mercury switch");
}
public void Visit(BimetallicStrip bimetallicStrip)
{
manifest.Add("Bimetallic strip");
}
public void Visit(HeatAnticipator heatAnticipator)
{
manifest.Add("Heat anticipator");
}
}
class DangerousGoodsManifestVisitor : IComponentVisitor
{
IList<string> manifest = new List<string>();
public void PrintManifest(TextWriter textWriter)
{
manifest.ToList().ForEach(x => textWriter.WriteLine(x));
}
public void Visit(Thermostat thermostat)
{
}
public void Visit(ThermostatCover thermostatCover)
{
}
public void Visit(CircutBoard circutBoard)
{
}
public void Visit(MercurySwitch mercurySwitch)
{
manifest.Add("Mercury switch");
}
public void Visit(BimetallicStrip bimetallicStrip)
{
}
public void Visit(HeatAnticipator heatAnticipator)
{
}
}
Running the application produces the following output:
Parts List ---------- Thermostat Thermostat cover Circut board Mercury switch Bimetallic strip Heat anticipator Dangerous Goods List ---------- Mercury switchBy using the Visitor pattern, the application was able to print a parts list and a dangerous goods list without adding any specific logic to the thermostat components. As new cross-cutting operations come up, a new visitor can be created without modification to the components. The down side of this example is that if any new components are added, each of the visitors will need to be updated. This violates the Open/Closed principle. Additionally, depending upon the type of behavior encapsulated by the visitor, the behavior for each element type may change for different reasons. In such cases, this would violate the Single Responsibility principle. What would be nice is to achieve a visitor implementation that satisfied both of these concerns.
An Agile Visitor
What if a visitor allowed us to replace the overloaded methods with strategies? Consider the following example:
class Program
{
static void Main(string[] args)
{
// Declare visitors
var partsManifestVisitor = new Visitor<IVisitable>();
var dangerousGoodsManifestVisitor = new Visitor<IVisitable>();
// Register parts manifest visitor strategies
partsManifestVisitor.RegisterElementVisitor<Thermostat>(x => Console.WriteLine("Thermostat"));
partsManifestVisitor.RegisterElementVisitor<ThermostatCover>(x => Console.WriteLine("Thermostat cover"));
partsManifestVisitor.RegisterElementVisitor<CircutBoard>(x => Console.WriteLine("Circut board"));
partsManifestVisitor.RegisterElementVisitor<MercurySwitch>(x => Console.WriteLine("Mercury switch"));
partsManifestVisitor.RegisterElementVisitor<BimetallicStrip>(x => Console.WriteLine("Bimetallic strip"));
partsManifestVisitor.RegisterElementVisitor<HeatAnticipator>(x => Console.WriteLine("Heat anticipator"));
// Register dangerous goods manifest visitor strategies
partsManifestVisitor.RegisterElementVisitor<MercurySwitch>(x => Console.WriteLine("Mercury switch"));
var thermostat = new Thermostat();
Console.WriteLine("Parts List");
Console.WriteLine("----------");
thermostat.Accept(partsManifestVisitor);
Console.WriteLine("nDangerous Goods List");
Console.WriteLine("----------");
thermostat.Accept(dangerousGoodsManifestVisitor);
Console.ReadLine();
}
}
In this example, the methods normally found on the classic visitor implementation have been replaced with lambda expressions registered for each type to be visited. There are several advantages to this approach:
First, the Visitor type is extensible and thus adheres to the Open/Closed principle.
Second, the Visitor type is generic, thus enabling it to be used for many (all?) types of visitor implementations.
Third, due to the fact that there are no concrete visitors coupled to a given object structure, new elements can be added to a given object structure without requiring that all visitors for that structure be modified to accommodate the new element.
Forth, the behavior associated with each type is encapsulated in a single Visitor strategy, thus adhering to the single responsibility principle.
Fifth, due to the fact that the Visitor isn’t itself coupled to any particular element type, the element types are likewise not coupled to any object structure specific visitor interface. This allows a given element to participate in unrelated object structure/visitor pattern implementations.
There are a couple of drawbacks to this approach however:
First, what happens when the behavior is more complex? For that, we could just add an overloaded RegisterElementVisitor() to accept an IVisitor:
class ThermostatVisitor : IVisitor<Thermostat>
{
public void Visit(Thermostat element)
{
Console.WriteLine("Thermostat");
}
}
class Program
{
static void Main(string[] args)
{
var partsManifestVisitor = new Visitor<IVisitable>();
partsManifestVisitor.RegisterElementVisitor<Thermostat>(new ThermostatVisitor());
// snip
}
}
That addresses the issue of how we might better encapsulate the more complex behaviors, but a second shortcoming is the loss of encapsulated state. One of the good things the classic Visitor pattern gives us is shared state for accumulating the results of our visitations. There are a few ways we could address this however. The first approach would be to just use closures:
// snip
// Register parts manifest visitor strategies
var partsManifest = new List<string>();
partsManifestVisitor.RegisterElementVisitor<Thermostat>(x => partsManifest.Add("Thermostat"));
partsManifestVisitor.RegisterElementVisitor<ThermostatCover>(x => partsManifest.Add("Thermostat cover"));
partsManifestVisitor.RegisterElementVisitor<CircutBoard>(x => partsManifest.Add("Circut board"));
partsManifestVisitor.RegisterElementVisitor<MercurySwitch>(x => partsManifest.Add("Mercury switch"));
partsManifestVisitor.RegisterElementVisitor<BimetallicStrip>(x => partsManifest.Add("Bimetallic strip"));
partsManifestVisitor.RegisterElementVisitor<HeatAnticipator>(x => partsManifest.Add("Heat anticipator"));
var thermostat = new Thermostat();
thermostat.Accept(partsManifestVisitor);
Console.WriteLine("Parts List");
Console.WriteLine("----------");
partsManifest.ToList().ForEach(x => Console.WriteLine(x));
// snip
A second approach would be to inject a state service when registering IVisitor strategies:
class Manifest
{
public IList<string> Parts { get; private set; }
public Manifest()
{
Parts = new List<string>();
}
public void RecordPart(string partName)
{
Parts.Add(partName);
}
}
class ThermostatVisitor : IVisitor<Thermostat>
{
Manifest _manifest;
public ThermostatVisitor(Manifest manifest)
{
_manifest = manifest;
}
public void Visit(Thermostat element)
{
_manifest.RecordPart("Thermostat");
}
}
class Program
{
static void Main(string[] args)
{
// Declare visitors
var partsManifestVisitor = new Visitor<IVisitable>();
// Register parts manifest visitor strategies
var manifest = new Manifest();
partsManifestVisitor.RegisterElementVisitor<Thermostat>(new ThermostatVisitor(manifest));
// other strategies
var thermostat = new Thermostat();
thermostat.Accept(partsManifestVisitor);
Console.WriteLine("Parts List");
Console.WriteLine("----------");
manifest.Parts.ToList().ForEach(x => Console.WriteLine(x));
}
}
Things are starting to get strewn about though. Let’s bundle all of this up into a facade:
class PartsManifestVisitorFacade : IVisitor<IVisitable>
{
Manifest _manifest = new Manifest();
Visitor<IVisitable> partsManifestVisitor = new Visitor<IVisitable>();
public PartsManifestVisitorFacade()
{
partsManifestVisitor.RegisterElementVisitor<Thermostat>(new ThermostatVisitor(_manifest));
// Register other strategies ...
}
public IList<string> Manifest
{
get
{
return _manifest.Parts;
}
}
public void Visit(IVisitable element)
{
partsManifestVisitor.Visit(element);
}
}
class Program
{
static void Main(string[] args)
{
var partsManifestVisitor = new PartsManifestVisitorFacade();
var thermostat = new Thermostat();
thermostat.Accept(partsManifestVisitor);
Console.WriteLine("Parts List");
Console.WriteLine("----------");
partsManifestVisitor.Manifest.ToList().ForEach(x => Console.WriteLine(x));
Console.ReadLine();
}
}
Alternately, we could use some DI registration magic to have an open generic visitor get closed-over, configured, and injected into wherever we are going to use it. Such an example is a tad bit beyond the intended scope of this article, however, so I’ll leave that as an exercise for the reader to explore.
By this point, you may be wondering: “So where’s the actual Visitor code”? While I’m sure a better implementation is possible, here’s my working prototype:
/// <summary>
/// Defines a visitor.
/// </summary>
/// <typeparam name="TElement">the type of element to be visited</typeparam>
interface IVisitor<TElement>
{
void Visit(TElement element);
}
/// <summary>
/// Defines a visitable element.
/// </summary>
interface IVisitable
{
void Accept(IVisitor<IVisitable> visitor);
}
/// <summary>
/// Represents an open/closed visitor.
/// </summary>
/// <typeparam name="T">the type of element to visit</typeparam>
class Visitor<T> : IVisitor<T>
{
readonly IDictionary<Type, IVisitorInfo> _visitorInfoDictionary = new Dictionary<Type, IVisitorInfo>();
/// <summary>
/// Visits the specified element.
/// </summary>
/// <param name="element">element to visit</param>
public void Visit(T element)
{
if (_visitorInfoDictionary.ContainsKey(element.GetType()))
{
IVisitorInfo visitorInfo = _visitorInfoDictionary[element.GetType()];
object visitor = visitorInfo.Visitor;
IVisitorInvoker invoker = visitorInfo.Invoker;
invoker.Invoke(visitor, element);
}
}
/// <summary>
/// Registers an visitor action delegate for a specific type.
/// </summary>
/// <typeparam name="TElement">type of element</typeparam>
/// <param name="action">the visitor action</param>
public void RegisterElementVisitor<TElement>(Action<TElement> action)
{
RegisterElementVisitor(new VisitorAction<TElement>(action));
}
/// <summary>
/// Registers a <see cref="IVisitor{TElement}"/> strategy for a specific type.
/// </summary>
/// <typeparam name="TElement">type of element</typeparam>
/// <param name="visitor">a visitor</param>
public void RegisterElementVisitor<TElement>(IVisitor<TElement> visitor)
{
var visitorInfo = new VisitorInfo<TElement>(
visitor, new DelegateVisitorInvoker<IVisitor<TElement>, TElement>((x, y) => x.Visit(y)));
_visitorInfoDictionary.Add(typeof(TElement), visitorInfo);
}
/// <summary>
/// Nested class used to encapsulate a visitor action.
/// </summary>
/// <typeparam name="TVisitor">the type of visitor action</typeparam>
/// <typeparam name="TElement">the type of element</typeparam>
class DelegateVisitorInvoker<TVisitor, TElement> : IVisitorInvoker
{
readonly Action<TVisitor, TElement> _action;
public DelegateVisitorInvoker(Action<TVisitor, TElement> action)
{
_action = action;
}
public void Invoke(object action, object instance)
{
_action.Invoke((TVisitor)action, (TElement)instance);
}
}
/// <summary>
/// Nested interface used as the key to the internal dictionary for associating
/// visitors with their invokers.
/// </summary>
interface IVisitorInfo
{
IVisitorInvoker Invoker { get; }
object Visitor { get; }
}
/// <summary>
/// Nested interface used to encapsulate a visit action invocation.
/// </summary>
interface IVisitorInvoker
{
void Invoke(object action, object instance);
}
/// <summary>
/// Nested class used to encapsulate visitor actions.
/// </summary>
/// <typeparam name="TElement">the type of element to visit</typeparam>
class VisitorAction<TElement> : IVisitor<TElement>
{
readonly Action<TElement> _action;
public VisitorAction(Action<TElement> action)
{
_action = action;
}
public void Visit(TElement element)
{
_action.Invoke(element);
}
}
/// <summary>
/// Nested class used as the key to the internal dictionary for associating
/// visitors with their invokers.
/// </summary>
/// <typeparam name="TElement">the type of element to be visited</typeparam>
///
/// <remarks>
/// This type is used as the internal dictionary key to associate visitors with
/// a corresponding invoker and enables the specific type information to be
/// maintained for each visitor/element pair.
/// </remarks>
class VisitorInfo<TElement> : IVisitorInfo
{
public VisitorInfo(IVisitor<TElement> visitor, IVisitorInvoker invoker)
{
Visitor = visitor;
Invoker = invoker;
}
public IVisitorInvoker Invoker { get; private set; }
public object Visitor { get; private set; }
}
}
Conclusion
The structure of the classic Visitor pattern seem to reflect the design sensibilities and capabilities of the mainstream programming languages of its day. While the problem it seeks to address remains relevant, it seems prudent to reconsider such patterns from time to time in light of both the ever-evolving capabilities of mainstream development platforms and design principles of today. So, is this a better approach? Let me know what you think.What is Double Dispatch?
Technically, Double Dispatch refers to a technique used in the context of a polymorphic method call for mitigating the lack of multimethod support in programming languages. More simply, Double Dispatch is used to invoke an overloaded method where the parameters vary among an inheritance hierarchy. To explain fully, let’s start with a review of polymorphism.Polymorphism
In the following example, a hierarchy of shapes are defined with each of the derived types overloading a base virtualDraw() method. Next, a console application is used to define a list of each of the shapes and iterate over each shape in the collection calling the Draw() method of each item in the list:
class Shape
{
public virtual void Draw()
{
Console.WriteLine("A shape is drawn.");
}
}
class Polygon : Shape
{
public override void Draw()
{
Console.WriteLine("A polygon is drawn.");
}
}
class Quadrilateral : Polygon
{
public override void Draw()
{
Console.WriteLine("A quadrilateral is drawn.");
}
}
class Parallelogram : Quadrilateral
{
public override void Draw()
{
Console.WriteLine("A parallelogram is drawn.");
}
}
class Rectangle : Parallelogram
{
public override void Draw()
{
Console.WriteLine("A rectangle is drawn.");
}
}
class Program
{
static void Main(string[] args)
{
var shapes = new List<Shape>
{
new Shape(),
new Polygon(),
new Quadrilateral(),
new Parallelogram(),
new Rectangle()
};
foreach (Shape shape in shapes)
{
shape.Draw();
}
Console.ReadLine();
}
}
The following lines are printed to the console upon running the application:
A shape is drawn. A polygon is drawn. A quadrilateral is drawn. A parallelogram is drawn. A rectangle is drawn.
Note that the proper Draw() method is called for each item in the collection. In most object-oriented languages, this polymorphic behavior is achieved through the use of a virtual table consulted at run-time to derive the proper offset address for an object’s method. This behavior is referred to as “Dynamic Dispatch” or “Single Dispatch”. So, how does this relate to Double Dispatch? To answer this question, let’s next review method overloading.
Method Overloading
In the following example, ourShape class is redefined to have two overloaded Draw methods: one with a parameter of type Surface and one with a parameter of type EtchASketch:
class Surface
{
}
class EtchASketch : Surface
{
}
class Shape
{
public void Draw(Surface surface)
{
Console.WriteLine("A shape is drawn on the surface with ink.");
}
public void Draw(EtchASketch etchASketch)
{
Console.WriteLine("The knobs are moved in attempt to draw the shape.");
}
}
class Program
{
static void Main(string[] args)
{
var shape = new Shape();
shape.Draw(new Surface());
shape.Draw(new EtchASketch());
Console.ReadLine();
}
}
When executed, the following lines are printed to the console:
A shape is drawn on the surface with ink. The knobs are moved in attempt to draw the shape.
Note that the parameter type determines which Draw() method is invoked.
But what happens if we change the Main() method to the following?
class Program
{
static void Main(string[] args)
{
var shape = new Shape();
Surface surface = new Surface();
Surface etchASketch = new EtchASketch();
shape.Draw(surface);
shape.Draw(etchASketch);
Console.ReadLine();
}
}
Executing this produces the following:
A shape is drawn on the surface with ink. A shape is drawn on the surface with ink.
What happened? The issue here is that the method to call was determined statically at compile time based upon the reference type, not at run-time based upon the object type. To resolve this issue, another technique is needed … Polymorphic Static Binding.
Polymorphic Static Binding
Polymorphic static binding is a technique where static method invocations are determined at run-time through the use of polymorphism. This can be demonstrated in our example by adding a newDraw(Shape shape) method to the Surface and EtchASketch types which call shape.Draw() with a reference to the current object:
class Surface
{
public virtual void Draw(Shape shape)
{
shape.Draw(this);
}
}
class EtchASketch : Surface
{
public override void Draw(Shape shape)
{
shape.Draw(this);
}
}
To invoke the correct Shape.Draw() method, our console application needs to be modified to call the the method indirectly through a Surface reference:
class Program
{
static void Main(string[] args)
{
var shape = new Shape();
Surface surface = new Surface();
Surface etchASketch = new EtchASketch();
surface.Draw(shape);
etchASketch.Draw(shape);
Console.ReadLine();
}
}
Upon executing the application again, the following lines are now printed:
A shape is drawn on the surface with ink. The knobs are moved in attempt to draw the shape.
This example achieves the desired result by effectively wrapping the static-dispatched method invocation (i.e. Shape.Draw()) within a virtual-dispatch method invocation (i.e. Surface.Draw() and EtchASketch.Draw()). This causes the static Shape.Draw() method invocation to be determined by which virtual Surface.Draw() method invocation is executed.
Although the above example now contains a method invocation using a reference to the current object as the method parameter (often seen with Double Dispatch), it should be noted that Double Dispatch has yet to be demonstrated. Thus far, only one level of virtual dispatching has been used. To demonstrate Double Dispatch, the techniques from both the polymorphism example and the polymorphic static binding example need to be combined as seen in the next section.
Double Dispatch
The following example contains a hierarchy ofSurface types and a hierarchy of Shape types. Each Shape type contains an overloaded virtual Draw() method which contains the logic for how the shape is to be drawn on a particular surface. The example console application uses the polymorphic static binding technique to ensure the proper overload is called for each surface type:
class Surface
{
public virtual void Draw(Shape shape)
{
shape.Draw(this);
}
}
class EtchASketch : Surface
{
public override void Draw(Shape shape)
{
shape.Draw(this);
}
}
class Shape
{
public virtual void Draw(Surface surface)
{
Console.WriteLine("A shape is drawn on the surface with ink.");
}
public virtual void Draw(EtchASketch etchASketch)
{
Console.WriteLine("The knobs are moved in attempt to draw the shape.");
}
}
class Polygon : Shape
{
public override void Draw(Surface surface)
{
Console.WriteLine("A polygon is drawn on the surface with ink.");
}
public override void Draw(EtchASketch etchASketch)
{
Console.WriteLine("The knobs are moved in attempt to draw the polygon.");
}
}
class Quadrilateral : Polygon
{
public override void Draw(Surface surface)
{
Console.WriteLine("A quadrilateral is drawn on the surface with ink.");
}
public override void Draw(EtchASketch etchASketch)
{
Console.WriteLine("The knobs are moved in attempt to draw the quadrilateral.");
}
}
class Parallelogram : Quadrilateral
{
public override void Draw(Surface surface)
{
Console.WriteLine("A parallelogram is drawn on the surface with ink.");
}
public override void Draw(EtchASketch etchASketch)
{
Console.WriteLine("The knobs are moved in attempt to draw the parallelogram.");
}
}
class Rectangle : Parallelogram
{
public override void Draw(Surface surface)
{
Console.WriteLine("A rectangle is drawn on the surface with ink.");
}
public override void Draw(EtchASketch etchASketch)
{
Console.WriteLine("The knobs are moved in attempt to draw the rectangle.");
}
}
class Program
{
static void Main(string[] args)
{
Surface surface = new Surface();
Surface etchASketch = new EtchASketch();
var shapes = new List<Shape>
{
new Shape(),
new Polygon(),
new Quadrilateral(),
new Parallelogram(),
new Rectangle()
};
foreach (Shape shape in shapes)
{
surface.Draw(shape);
etchASketch.Draw(shape);
}
Console.ReadLine();
}
}
Executing this example produces the following:
A shape is drawn on the surface with ink. The knobs are moved in attempt to draw the shape. A polygon is drawn on the surface with ink. The knobs are moved in attempt to draw the polygon. A quadrilateral is drawn on the surface with ink. The knobs are moved in attempt to draw the quadrilateral. A parallelogram is drawn on the surface with ink. The knobs are moved in attempt to draw the parallelogram. A rectangle is drawn on the surface with ink. The knobs are moved in attempt to draw the rectangle.
In the above example, virtual dispatch occurs twice for each call to one of the Surface references: Once when the Surface.Draw() virtual method is called and again when either calls the Shape.Draw() overloaded virtual method. Note again that while the second virtual dispatch is based on the type of Shape instance, the overloaded method called is still determined statically based upon the reference type.
Consequences
So, what’s wrong with Double Dispatch? The problem isn’t so much in the technique, but what design choices might be leading to reliance upon the technique. Consider for instance the hierarchy of shape types in our Double Dispatch example. What happens if we want to add a new surface? In this case, each of the shape types will need to be modified to add knowledge of the new Surface type. This violates the Open/Closed Principle, and in this case in a particularly egregious way (i.e. Its violation is multiplied by the number of shape types we have). Additionally, it violates the Single Responsibility Principle. Changes to how shapes are drawn on a particular surface are likely to differ from surface to surface, thereby leading our shape objects to change for different reasons. The presence of Double Dispatch generally means that each type in a hierarchy has special handling code within another hierarchy of types. This approach to representing variant behavior leads to code that is less resilient to future changes as well as being more difficult to extend.The Matrix: Reloaded
Let’s take another stab at modeling our shape/surface intersection matrix. In the following example, several new concepts have been introduced to facilitate decoupling: line segments, points, and brushes:
interface ISurface
{
void Add(LineSegment segment);
}
class Paper : ISurface
{
readonly IList<LineSegment> _segments = new List<LineSegment>();
public void Add(LineSegment segment)
{
_segments.Add(segment);
}
}
class EtchASketch : ISurface
{
readonly IList<LineSegment> _segments = new List<LineSegment>();
public void Add(LineSegment segment)
{
_segments.Add(segment);
}
}
class Point
{
public Point(int x, int y)
{
X = x;
Y = y;
}
public int X { get; set; }
public int Y { get; set; }
}
class LineSegment
{
public LineSegment(Point point1, Point point2)
{
Point1 = point1;
Point2 = point2;
}
public Point Point1 { get; set; }
public Point Point2 { get; set; }
}
interface IShape
{
IList<LineSegment> GetLineSegments();
}
class Polygon : IShape
{
public IList<LineSegment> GetLineSegments()
{
var segments = new List<LineSegment>();
segments.Add(new LineSegment(new Point(0, 0), new Point(0, 9)));
segments.Add(new LineSegment(new Point(0, 9), new Point(3, 6)));
segments.Add(new LineSegment(new Point(3, 6), new Point(6, 9)));
segments.Add(new LineSegment(new Point(6, 0), new Point(6, 9)));
segments.Add(new LineSegment(new Point(6, 0), new Point(3, 3)));
segments.Add(new LineSegment(new Point(3, 3), new Point(0, 0)));
return segments;
}
}
class Quadrilateral : IShape
{
public IList<LineSegment> GetLineSegments()
{
var segments = new List<LineSegment>();
segments.Add(new LineSegment(new Point(0, 0), new Point(0, 9)));
segments.Add(new LineSegment(new Point(0, 9), new Point(4, 5)));
segments.Add(new LineSegment(new Point(4, 0), new Point(0, 4)));
segments.Add(new LineSegment(new Point(4, 0), new Point(0, 0)));
return segments;
}
}
class Parallelogram : IShape
{
public IList<LineSegment> GetLineSegments()
{
var segments = new List<LineSegment>();
segments.Add(new LineSegment(new Point(0, 4), new Point(0, 9)));
segments.Add(new LineSegment(new Point(0, 9), new Point(4, 5)));
segments.Add(new LineSegment(new Point(4, 0), new Point(4, 5)));
segments.Add(new LineSegment(new Point(4, 0), new Point(0, 4)));
return segments;
}
}
class Rectangle : IShape
{
public IList<LineSegment> GetLineSegments()
{
var segments = new List<LineSegment>();
segments.Add(new LineSegment(new Point(0, 0), new Point(0, 9)));
segments.Add(new LineSegment(new Point(0, 9), new Point(9, 4)));
segments.Add(new LineSegment(new Point(4, 0), new Point(9, 4)));
segments.Add(new LineSegment(new Point(4, 0), new Point(0, 0)));
return segments;
}
}
class Program
{
static readonly IDictionary<Type, IBrush> brushDictionary = new Dictionary<Type, IBrush>();
static Program()
{
brushDictionary.Add(typeof (Paper), new Pencil());
brushDictionary.Add(typeof (EtchASketch), new EtchASketchKnobs());
}
static void Main(string[] args)
{
var surfaces = new List<ISurface>
{
new Paper(),
new EtchASketch()
};
var shapes = new List<IShape>
{
new Polygon(),
new Quadrilateral(),
new Parallelogram(),
new Rectangle()
};
foreach (ISurface surface in surfaces)
foreach (IShape shape in shapes)
{
Console.WriteLine(string.Format("Drawing a {0} on the {1} ...", shape.GetType().Name,
surface.GetType().Name));
brushDictionary[surface.GetType()].Draw(surface, shape.GetLineSegments());
Console.WriteLine(Environment.NewLine);
}
Console.ReadLine();
}
}
interface IBrush
{
void Draw(ISurface surface, IList<LineSegment> segments);
}
class Pencil : IBrush
{
public void Draw(ISurface surface, IList<LineSegment> segments)
{
foreach (LineSegment segment in segments)
{
Console.WriteLine(string.Format("Pencil used to sketch line segment {0},{1} to {2},{3}.",
segment.Point1.X, segment.Point1.Y,
segment.Point2.X, segment.Point2.Y));
}
}
}
class EtchASketchKnobs : IBrush
{
public void Draw(ISurface surface, IList<LineSegment> segments)
{
foreach (LineSegment segment in segments)
{
Console.WriteLine(string.Format("Knobs used to produce line segment {0},{1} to {2},{3}.",
segment.Point1.X, segment.Point1.Y,
segment.Point2.X, segment.Point2.Y));
}
}
}
Executing this example produces the following:
Drawing a Polygon on the Paper ... Pencil used to sketch line segment 0,0 to 0,9. Pencil used to sketch line segment 0,9 to 3,6. Pencil used to sketch line segment 3,6 to 6,9. Pencil used to sketch line segment 6,0 to 6,9. Pencil used to sketch line segment 6,0 to 3,3. Pencil used to sketch line segment 3,3 to 0,0. Drawing a Quadrilateral on the Paper ... Pencil used to sketch line segment 0,0 to 0,9. Pencil used to sketch line segment 0,9 to 4,5. Pencil used to sketch line segment 4,0 to 0,4. Pencil used to sketch line segment 4,0 to 0,0. Drawing a Parallelogram on the Paper ... Pencil used to sketch line segment 0,4 to 0,9. Pencil used to sketch line segment 0,9 to 4,5. Pencil used to sketch line segment 4,0 to 4,5. Pencil used to sketch line segment 4,0 to 0,4. Drawing a Rectangle on the Paper ... Pencil used to sketch line segment 0,0 to 0,9. Pencil used to sketch line segment 0,9 to 9,4. Pencil used to sketch line segment 4,0 to 9,4. Pencil used to sketch line segment 4,0 to 0,0. Drawing a Polygon on the EtchASketch ... Knobs used to produce line segment 0,0 to 0,9. Knobs used to produce line segment 0,9 to 3,6. Knobs used to produce line segment 3,6 to 6,9. Knobs used to produce line segment 6,0 to 6,9. Knobs used to produce line segment 6,0 to 3,3. Knobs used to produce line segment 3,3 to 0,0. Drawing a Quadrilateral on the EtchASketch ... Knobs used to produce line segment 0,0 to 0,9. Knobs used to produce line segment 0,9 to 4,5. Knobs used to produce line segment 4,0 to 0,4. Knobs used to produce line segment 4,0 to 0,0. Drawing a Parallelogram on the EtchASketch ... Knobs used to produce line segment 0,4 to 0,9. Knobs used to produce line segment 0,9 to 4,5. Knobs used to produce line segment 4,0 to 4,5. Knobs used to produce line segment 4,0 to 0,4. Drawing a Rectangle on the EtchASketch ... Knobs used to produce line segment 0,0 to 0,9. Knobs used to produce line segment 0,9 to 9,4. Knobs used to produce line segment 4,0 to 9,4. Knobs used to produce line segment 4,0 to 0,0.
By changing the Shape objects to be defined in terms of line segments, knowledge is removed from the shape concerning how to draw itself on any particular surface. Additionally, the Surface type now encapsulates a collection of line segments to simulate the lines being drawn onto the surface. To handle drawing the line segments onto the surfaces, we’ve introduced a Brush type which “draws” the line segments onto a surface in its own peculiar way. To configure which brushes are to be used with which surface, the console application defines a dictionary matching surfaces to brushes.
In contrast to the Double Dispatch example, none of the existing types need to be modified to add new surfaces, shapes, or brushes.
Conclusion
Since Double Dispatch is a technique for calling virtual overloaded methods based upon parameter types which exist within an inheritance hierarchy, its use may be a symptom that the Open/Closed and/or Single responsibility principles are being violated, or that responsibilities may otherwise be misaligned. This is not to say that every case of Double Dispatch means something is amiss, but only that its use should be a flag to reconsider your design in light of future maintenance needs.With the increasing popularity of the Git version control system, many .Net developers are being introduced for the first time to Unix-like tools for Windows by way of two popular Git client platforms: msysgit and Cygwin. The more substantial of the two, Cygwin is a Linux-like environment for Windows and provides a wide range of useful utilities. The following is a guide for helping newcomers quickly get up and going with the Cygwin environment.
Installation
The first step is to obtain the installer from the Cygwin home page. Upon running the installer, you’ll be presented with a wizard which guides you through the installation process:
Upon arriving at the “Select Packages” dialog, you’ll be presented with all the packages available from the selected mirror site(s):
The installer allows you to install selected packages, or install by category:
At the package level, the rotating arrow icon allows you to cycle through the choices of installing one of the package versions available, skipping the package, or in the event the package is already installed, keeping, reinstalling, uninstalling, or obtaining the source code for the package. At the category level, the rotating arrow icon allows you to cycle through the choices of Default, Install, Reinstall, or Uninstall.
It’s best to only select the packages you really think you’ll want to use or immediately explore. There’s quite a bit of applications available and choosing everything would result in quite a large installation time. The installer can always be run at a later time to pickup up additional packages you want to explore.
By default, Cygwin selects the Base category packages as well as a few other odds & ends. Among the packages skipped by default, you may consider also installing the following:
| Category | Package | Description |
| Admin | cygrunsrv | Utility for easily working with Windows services (adding/removing/starting/stopping). This is beneficial if you’d like to run git daemon or sshd as a windows service for anonymous or authenticated access. |
| Archive | zip, unzip | PKZip compatible zip capabilities. |
| Editors | vim | An enhanced VI editor. |
| Net | openssh | Secure shell client and server programs. |
| Utils | ncurses | Terminal utilities (has a clear command for clearing the screen). |
| Web | curl | Multi-protocol file transfer tool. This tool is useful for scripting HTTP interaction. |
In addition, I personally always install the X11 category packages. While this adds a bit to the download size, it gives you the ability to run your preferred shell (e.g. bash) in an xterm as opposed to the standard terminal window. I’ll cover a bit of X11 installation and customization later in this guide.
When you’re done selecting your packages, click “Next” and the install will begin:
Once complete, click the Finish button and you’re done with the install.
Bash Shell Customization
If you selected the “Add icon to Start Menu” option during the install then you should have a new shortcut entitled “Cygwin Bash Shell” which will start the bash shell as an interactive login shell (i.e. bash –login -i). If not, you can browse to cygwin.bat file located within the chosen installation folder.
When bash runs for the first time, it checks to see if the home directory (denoted in the /etc/passwd file) exists for your account. If not, it creates the directory and copies over some default config files for your shell:
The .bash_profile is used for login shells while the .bashrc file is used for interactive, non-login shells. The default .bash_profile configuration sources the .bashrc file if it exists, so both are sourced for interactive login shells. This effectively allows the .bashrc to serve as the core configuration for both login and non-login shells. The .inputrc file is used to set custom key mappings. Of the three, the .bashrc file will generally be the one you’ll deal with most often.
Go ahead and open up the .bashrc file. (Note: Microsoft Notepad does not display Unix-style line endings correctly. If using a Windows editor, use Wordpad.) After opening the file, you’ll notice that most of the configuration is commented out. The only active configuration are commands to unset the Windows TMP and TEMP variables. You can keep this if you like, but I prefer to keep things a bit more tidy and only have the configuration I actually use. If you want to view the default contents of this file, it can always be viewed from its original source in /etc/skel. The following is a more minimal configuration you might wish to start with:
unset TMP
unset TEMP
PATH=.:~/bin:${PATH}
PATH=${PATH}:c:/Windows/Microsoft.Net/Framework/v3.5/
PATH=${PATH}:c:/Program Files/Reflector/
PATH=${PATH}:c:/Program Files/Microsoft SDKs/Windows/v6.1/Bin/
. ~/.alias
. ~/.functions
In this configuration, several folders have been added to the PATH environment variable. The first places a ~/bin folder before the PATH. This ensures any custom scripts found in the users bin folder occur first in the path allowing commands to be overridden. The remaining three lines are example folders you might want to set if you are doing .Net development related tasks at the bash command line.
The remaining two lines assume the existence of two new files, .alias and .functions. I find storing aliases and functions separately to be a bit more tidy, as well as making it easier to share with others.
Now, let’s take a look at the .bash_profile configuration. By default, the only configuration that exists is the sourcing of the .bashrc file. Again, normally the .bashrc file is only sourced for non-login shells, so this ensures the .bashrc settings are picked up for login shells as well.
In this file, let’s replace the contents with the following:
# source the system wide bashrc if it exists
if [ -e /etc/bash.bashrc ] ; then
source /etc/bash.bashrc
fi
# source the users bashrc if it exists
if [ -e "${HOME}/.bashrc" ] ; then
source "${HOME}/.bashrc"
fi
PS1='[h]: ${PWD##*/} > '
set -o vi
export DISPLAY=127.0.0.1:0.0
In addition to the existing configuration, we’ve added three additional settings. The first customizes how the prompt appears at the command line by setting the PS1 variable. This prompt is a bit plain, but you can spruce it up with a bit of color by replacing it with the following:
PS1=’\[\033]0;\w\007\033[32m\][\h]: \[\033[33m ${PWD##*/}\033[0m\] > ‘Next, I’ve issued: “set -o vi”. This tells bash to use a vi-style command line editing interface which let’s you more efficiently issue and edit commands at the command line. You can delete this if you don’t ever plan on learning vi.
Next, I’ve set an X environment variable named “DISPLAY” to my localhost. This tells the xterm and other X applications where to attempt to display. You can delete this if you don’t plan on running an xterm, but leaving it certainly won’t hurt.
This should get you started. Your config files will likely evolve from here if you find yourself working at the command line often.
Aliases
The next step you may want to take is to define some command aliases. The bash alias command allows you to set up aliases for verbose or otherwise undesirable commands. As indicated, I store all of my aliases in a .alias file in my home directory to segregate them away from the rest of my .bashrc configuration. Here is a subset of my current list of aliases you might find useful:
alias programfiles="cd /cygdrive/c/Program Files"
alias projects="cd /cygdrive/c/projects"
alias spikes="cd /cygdrive/c/projects/spikes"
alias vs='cmd /c *.sln'
alias vs9='/cygdrive/c/Program Files/Microsoft Visual Studio 9.0/Common7/IDE/devenv.exe *.sln&'
alias wordpad='/cygdrive/c//Program Files/Windows NT/Accessories/wordpad.exe'
alias config='cd /cygdrive/c/Windows/Microsoft.NET/Framework/v2.0.50727/CONFIG'
alias mydocs='cd /cygdrive/c/Users/${USER}/Documents'
alias myhome='cd /cygdrive/c/Documents and Settings/${USER}/'
alias fusion='fuslogvw.exe'
You’ll be surprised at how fast you’ll start zipping around the system once you’ve got some good navigation aliases in place.
Functions
I don’t tend to write a lot of bash functions, but I’m including this section here for completeness. Like the aliases, I like to segregate any functions I do write away from my main config file to make things a bit cleaner. As an example of what you can do, here is the contents of an example .functions file which allows you to tweet from the command line:
tweet()
{
read -s -p "Password:" password
curl -u derekgreer:$password -d status="$1" http://twitter.com/statuses/update.xml
}
Basic Commands
If you’re completely new to the Unix shells, the following are some common commands to get you started with navigating around, creating folders, deleting files, etc.:| Command | Description |
| cd | Change to home directory |
| cd [directory name] | Change to a specified directory |
| cd - | Change to the last directory |
| ls | List the contents of the current folder (like dir) |
| ls -la | List the contents of the current folder in long format including all hidden files |
| cat [filename] | Print the context of a file (like DOS type) |
| ![command prefix] | Run the last command starting with the specified prefix. |
| mkdir [directory name] | Make a new directory |
| mkdir -p [directory hierarchy] | Make a all directories listed (e.g. mkdir -p a/b/c/d) |
| rm [filename] | Remove a file |
| rm -rf [filename] | Remove recursively with force |
| find [start folder] -name [regex] -print | Starting at the start folder, find a file matching the given regular expression. |
| grep [regex] [filename] | Display all lines matching the regular expression from the given file. |
Scripts
Once you start getting comfortable with the available commands, you may wish to start writing your own scripts to help with various everyday tasks. While covering the basics of bash shell scripting is beyond the intended scope of this article, you can obtain an archive of some scripts I’ve written for my own purposes from here. Here’s a list of the contained scripts along with a brief description:
| Script | Description |
| clean | Cleans up common temp/generated Visual Studio files. |
| detachfromcvs | Removes CVS folders. |
| detachfromtfs | Removes TFS bindings from source files. |
| diff | Overrides the diff command to call WinMerge |
| git-diff-wrapper.sh | Diff wrapper for use with Git. |
| replaceinfile | Replaces string patterns in a file. |
| replaceinfiles | Wrapper for calling replaceinfile for files matching a given pattern. |
| rgrep | Recursive grep (Also greps from .Net assemblies) |
| unix2dosall | Recursive unix2dos |
X11 – Using an XTerm
The final portion of this guide is intended for those who would like to explore the X Windows system provided by Cygwin. One of the benefits of running an XServer on Windows is the ability to use an XTerm over the standard terminal provided by DOS. XTerm provides more flexibility over the fonts, colors used, and buffers used, provides dynamic resizing, and provides much more intuitive cut-n-paste capabilities (highlight = cut, middle mouse button = paste). It also displays buffered text which comes in handy when you want to use the tail -f command to follow a log file and queue up a bunch of spaces to visually separate new entries.
Assuming you’ve already installed the X11 packages, locate the Cygwin-X folder in your start menu and execute the “XWin Server” shortcut. By default, the XServer starts a plain white terminal:
Since this isn’t likely the style of terminal you’ll want to work with, you can prevent XServer from starting this default xterm by creating an empty .startxwinrc file in your home directory. You can do this by using the touch command:
touch ~/.startxwinrcNext, you can modify the XTerm shortcut that was created in your start menu’s Cygwin-X folder to start a new xterm with no menu, a custom font, colors, a scrollbar, etc. using the following Target value:
C:Cygwinbinrun.exe -p /usr/X11R6/bin xterm -display 127.0.0.1:0.0 -ls -vb -fn 10×20 +tb -bg gray14 -fg ivory -sb -rightbar -sl 400This command will launch an xterm similar to the following:
From here, you may consider adding the XWin Server shortcut to your startup.
That concludes my guide. Enjoy!
Step 2: Create a file named gitd in the /usr/sbin directory with the following content:
#!/bin/bash git daemon --reuseaddr --base-path=/cygdrive/c/Projects
git-daemon-export-ok. If you wish to share all folders under the base path without requiring this file, use the switch --export-all.
This command assumes the base path of all shared git repositories will be /cygdrive/c/Projects/ (i.e. C:Projects under Windows). Change this value if your projects are stored in an alternate location.
If you wish to enable anonymous push access to your repositories (not advisable), you can add the switch --enable=receive-pack.
cygrunsrv command to install the script as a service (Note: This command assumes Cygwin is installed at C:Cygwin):
cygrunsrv --install gitd
--path c:/cygwin/bin/bash.exe
--args c:/cygwin/usr/sbin/gitd
--desc "Git Daemon"
--neverexits
--shutdown
cygrunsrv --start gitd
The gitd service should now be running. To verify that everything is setup properly, here is a quick and dirty script which should establish that the desired repositories are remotely accessible:
#!/bin/bash
BASEDIR=/cygdrive/c/Projects
REPO_NAME=testapp$$
REPO_PATH=${BASEDIR}/${REPO_NAME}
REMOTE_PATH=${BASEDIR}/remote$$/
echo "Creating a local git repo ..."
mkdir -p ${REPO_PATH}
cd ${REPO_PATH}
git init
touch .git/git-daemon-export-ok
echo "Commiting test file ..."
touch testfile
git add -A
git commit -m 'Test message'
echo "Simulate remote clone ..."
mkdir ${REMOTE_PATH}
cd ${REMOTE_PATH}
git clone git://localhost/${REPO_NAME}
echo "Cleaning up test folders ..."
rm -rf ${REPO_PATH}
rm -rf ${REMOTE_PATH}

