Living in the Tech Avalanche Generation

A practitioner’s introspective on technology

Patterns that cross borders - C# to IronPython

Recent consideration of the Template Method Pattern got me to wondering about how I might achieve a little more dynamism with respect to declaration, definition and instantiation when using the template method pattern. Without delving too deep into the “classical” Template Method Pattern it can be described here in code with the most trivial of examples.

C# Classic Template Method Pattern

abstract class FootballMatch
{
    abstract void StartGame();

    abstract void EndGame();

    public virtual void PlayGame()
    {
        Console.Writeline("Players kick the ball around a field");
    }

    public virtual void CompleteMatch()
    {
        StartGame();
        PlayGame();
        EndGame();
        Console.WriteLine("Match completed thanks for attending!");
    }
}

public class AustralianRulesFootballMatch : FootballMatch
{
    public void StartGame()
    {
        Console.WriteLine("Siren blows to begin game….");
    }

    public void EndGame()
    {
        Console.WriteLine("Siren blows to end game….");
    }
}

public class SoccerFootballMatch : FootballMatch
{
    public void StartGame()
    {
        Console.WriteLine("Referee blows whistle to begin game….");
    }

    public void EndGame()
    {
        Console.WriteLine("Referee blows whistle to end game….");
    }
}

 

What about Functions? And how about runtime implementer?

As described above, the implementing classes are defined at design time as concrete derived classes. Doing this in Languages such as Python and Ruby seems a little more flexible in as much that I don’t really require the derivation through an abstract class.

An IronPython Implementation

class RestuarantEndToEndService:

    def __init__(self, servicename, m1, m2, m3, m4):
        self._serviceName = servicename
        self._greetAndQualifyCustomer = m1
        self._takeCustomerOrder = m2
        self._serveTheCustomerMeal = m3
        self._takePayment = m4

    def prepareTheMeal(self):
        print Chef prepares the meal

    def performService(self):
        print Doing %(svc)s Service % {svc : self._serviceName}
        self._greetAndQualifyCustomer()
        self._takeCustomerOrder()
        self.prepareTheMeal()
        self._serveTheCustomerMeal()
        self._takePayment()

def seatCustomer():
    print Greet and seat the customer at their table

def answerOrdersPhoneLine():
    print Answer the phone and take the customer details

def takeCustomerOrder():
    print Waiter / Waitress takes the customers order

def takeCustomerPhoneOrder():
    print Take the customers order by phone

def serveTheCustomer():
    print Waiter / Waitress serves customer their meal

def deliverTheCustomerPhoneOrder():
    print Driver delivers the customers phone order

def takeCustomerPaymentAtCounter():
    print Cashier takes customer payment

def takeCustomerPaymentOnDelivery():
    print Driver takes customer payment

inhouseService = RestuarantEndToEndService(In House,
                    seatCustomer,
                    takeCustomerOrder,
                    serveTheCustomer,
                    takeCustomerPaymentAtCounter)
deliveryService = RestuarantEndToEndService(Delivered,
                    answerOrdersPhoneLine,
                    takeCustomerPhoneOrder,
                    deliverTheCustomerPhoneOrder,
                    takeCustomerPaymentOnDelivery)

inhouseService.performService()
print ***********************
deliveryService.performService()

The DLR, Interop and shifting the code around

What’s a little more interesting is using this pattern in interop scenarios when the templated class is defined in a statically typed language and the template method is supplied by a dynamic language created for the DLR. This can be demonstrated here with the given abstract class and by using my IronPython WPF interactive console control.

public abstract class TemplateClass
{
    public abstract void Operation1();
    public abstract void Operation2();

    /// <summary>
    /// The Tempate Method
    /// </summary>
    public void TheTemplateMethod()
    {
        Operation1();
        Operation2();
    }
}

ip_swap_abstract_from_csharp

Using the Python Help function we can examine the abstract template class and see how it’s been defined. Looking at the printed help on the class it’s clear that the two abstract methods have ‘tagged along for the ride’ as expected. You wont be able to execute them until you provide an implementation, just as you would expect given it’s an abstract class.

ip_swap_abstract_from_csharp_help

The other scenario involves moving some statically typed code (a method) to the IronPython runtime and using an Action / Delegate to  ‘fill in’ the template algorithm in a dynamically typed class. For example in the EndToEndRestuarantService class defined in Python above, we could push the actions (delegates) over from C# to the IronPython runtime. Given a set of Functions defined in managed C#:

var actions = new Dictionary<string, object>();
actions.Add("seat", seat_customer);
actions.Add("order", take_customerOrder);
actions.Add("serve", serve_the_customer);
actions.Add("pay", take_customer_payment_at_counter);

When you push these functions over the Script Scope running the IronPython code, then you can pass those functions around to any other code running within the same scope. With our Restaurant example we can take our named functions from the C# code at runtime and push them into the constructor of our IronPython class:

ip_swap_abstract_from_csharp_func_constructs

When is this pattern useful?

These patterns can be useful in scenarios where you might be considering scripting your managed C# application and providing DLR supported scripting functionality to the application as well. It can also be quite useful when you want to expose some technology that does not currently support full interop (Entity Framework for example) or perhaps you want to make our application model visible to IronPython or IronRuby. There are of course a plethora of patterns that can be implemented in code that can traverse both environments; its really a matter of what we can devise with some imagination.

Share/Save/Bookmark

2 Comments so far

  1. Michael Chandler January 7th, 2010 6:57 am

    In this case I guess the abstract class offers two things: (inheritance) polymorphism and a “grouping” of behaviours. If you wanted to get away from the abstract class you could always do it fully based on delegates, which I think gives you easier runtime flexibility. Admittedly I haven’t has much of a need for this, but nevertheless…

    public class TemplateExecutor (the class name would be dependent on the context obviously)
    {
    private Action _operation1;
    private Action _operation2;

    public TemplateClass(Action operation1, Action operation2) {
    _operation1 = operation1;
    _operation2 = operation2;
    }

    ///
    /// The Tempate Method
    ///
    public void Execute()
    {
    _operation1();
    _operation2();
    }
    }

    new TemplateExecutor(() => …blow start siren…, () => …blow end siren…).Execute();

    After reading your article again, I believe this is basically what your Python example is doing. Thoughts? A lot of frameworks seem to be going the way of delegate parameters.

    [Reply]

  2. Simon Segal January 7th, 2010 10:03 am

    Michael

    Yes!, the interest in finding the F(unctional) in C# is making that approach very common these days. Passing functions and methods is becoming a standard part of the vernacular it would seem.

    [Reply]

Leave a reply

Creative Commons Attribution-ShareAlike 2.5 Australia
Creative Commons Attribution-ShareAlike 2.5 Australia