If you want to see what the next generation of UI might look like, take a look at this concept.
Thursday, October 15, 2009
Wednesday, September 30, 2009
Using Decorator (or Wrapper) Design Patterns to add Validation to an object
Context
In most cases when someone write about the Decorator pattern it is usually related to UI stuff. The most common example is adding “decoration” to a control, for example a scroll bar. But in my humble opinion, this is not the most useful usage of Decorator. The purpose this pattern is:
“Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to sub classing for extending functionality”
Gang of Four
If you think about it, Validation is a responsibility and so it can be added by this pattern. Of course we can add the validation to the class itself or in its base class, but how would you reuse this validation across many unrelated objects and what if you object must derive from another base class?
Solution
The solution is the Decorator pattern. With this pattern we can add new responsibility to an object without changing its internals.
For simplicity purpose we will take a simple sample that anyone can understand but the concept shown here can apply to much more complex object.
Four our sample we will take a bank account. On this account we should be able to to money deposit and withdraw. The class diagram on the right illustrate this design.
Let’s start by defining our IAccount interface
namespace Model
{
public interface IAccount {
string AccountNumber { get; }
decimal Balance { get; }
bool Active { get; }
void Deposit(decimal amount);
void Withdraw(decimal amount);
void Close();
}
}
This simple interface will be the central abstraction of the system. The goal is to never depends on concrete class and this interface in enough to add a lot of functionality around an account.
Now here the interface implementation as an Account:
using System.Diagnostics;
namespace Model
{
[DebuggerDisplay("Account = {_accountNumber}, Balance = {_balance}")]
public class Account : IAccount
{
public string AccountNumber { get; private set; }
public decimal Balance { get; private set; }
public bool Active { get; set; }
internal Account(string accountNumber, decimal balance)
{
AccountNumber = accountNumber;
Balance = balance;
Active = true;
}
public void Deposit(decimal amount)
{
if (OnBeforeDeposit())
Balance += amount;
OnAfterDeposit();
}
protected virtual bool OnBeforeDeposit()
{
return true;
}
protected virtual void OnAfterDeposit() { }
public void Withdraw(decimal amount)
{
if (OnBeforeWithdraw())
Balance -= amount;
OnAfterWithdraw();
}
protected virtual bool OnBeforeWithdraw()
{
return true;
}
protected virtual void OnAfterWithdraw() { }
public void Close()
{
if (OnBeforeClose())
Active = false;
OnAfterClose();
}
protected virtual bool OnBeforeClose()
{
return true;
}
protected virtual void OnAfterClose() { }
}
}
If you expand the previous block of code you will see that the implementation of IAccount is only doing business stuff. There is no other responsibility in this class than the one that is meant for. We can clearly see “Template Method” design pattern here. All “OnSomething()” method are protected and any derided class can add implementation around the process. All “Before” method can cancel the process if the return value is false. This allow extension classes to add some specific behaviour.
But one of the main thing missing in this class is “validation”. We will use the decorator pattern to do that. A decorator class is a class thst implement all the member of an abstraction and forward all the calls to an internal instance of a real implementation that abstraction. In our case the abstraction is “IAccount” so we have to make a decorator that implement that interface.
namespace Model.Decorator
{
public abstract class AccountDecorator : IAccount
{
private readonly IAccount _account;
protected IAccount Account
{
get { return _account; }
}
protected AccountDecorator(IAccount account)
{
_account = account;
}
public string AccountNumber
{
get { return Account.AccountNumber; }
}
public decimal Balance
{
get { return Account.Balance; }
}
public bool Active
{
get { return Account.Active; }
}
public virtual void Deposit(decimal amount)
{
Account.Deposit(amount);
}
public virtual void Withdraw(decimal amount)
{
Account.Withdraw(amount);
}
public virtual void Close()
{
Account.Close();
}
}
}
As you can see the constructor of the decorator takes an instance of “IAccount”. All method forward their call to that instance. This base class simplifies the process of creating concrete decorator by allowing other decorator to implement some but not all members of the interface.
Now is the time to start implementing our validation class structure. For that purpose we will create a base validation class that will be responsible of applying the validation the IAccount instance.
using System.Collections.Generic;
using Model.Decorator;
namespace Model.Validator
{
public abstract class AccountValidatorBase : AccountDecorator
{
protected abstract IEnumerable<IValidation> GetValidations(decimal amount);
protected AccountValidatorBase(IAccount account) : base(account) {}
protected void Validate(decimal amount)
{
foreach (var validation in GetValidations(amount))
if (!validation.IsValid)
throw validation.Exception;
}
}
}
This simple base class define a “GetValidations” method that all derived class must override to add a list of validation to perform on method call.
Now to implement the “Deposit” validation we have to create this class:
using System.Collections.Generic;
using Model.Validation;
namespace Model.Validator
{
public class AccountDepositValidator : AccountValidatorBase
{
public AccountDepositValidator(IAccount account) : base(account) {}
protected override IEnumerable<IValidation> GetValidations(decimal amount)
{
return new List<IValidation>
{
new AmountGreaterThanZeroValidation(amount),
new AmountShouldHaveOnlyTwoDecimals(amount),
new AccountMustBeActiveValidation(Account),
new DepositAmountNotExceedMaxValidation(Account, amount)
};
}
public override void Deposit(decimal amount)
{
Validate(amount);
Account.Deposit(amount);
}
}
}
This class is responsible for creating all validation instances. The “Deposit” method is overridden to call the base “Validate” method before doing the actual deposit.
To implement those validation we need to define the “IValidation” interface.
using System;
namespace Model.Validator
{
public interface IValidation
{
bool IsValid { get; }
Exception Exception { get; }
}
}
Here is a sample implementation:
using System;
using Model.Validator;
namespace Model.Validation
{
public class AmountGreaterThanZeroValidation : IValidation
{
public AmountGreaterThanZeroValidation(decimal amount)
{
Amount = amount;
}
public decimal Amount { get; set; }
public bool IsValid
{
get { return Amount > 0; }
}
public Exception Exception
{
get { return new ArgumentOutOfRangeException("amount", Amount, "Deposit amount should be greater than 0."); }
}
}
}
All other validations used in “AccountDepositValidator” can be described the same way.
The last step is to create an actual “IAccount” that will implement all this stuff. To do that we will need a Bank class. A bank is responsible of creating account. It will also be responsible of decorating it with all necessary decorators.
using System;
using System.Collections.Generic;
using Model.Logging;
using Model.Validator;
namespace Model
{
public static class Bank
{
static readonly SortedDictionary<string, IAccount> _accounts = new SortedDictionary<string, IAccount>();
private static int _accountSequence = 1;
public static IAccount CreateAccount(decimal balance)
{
string accountNumber = String.Format("A{0:0000}", _accountSequence++);
IAccount account = new Account(accountNumber, balance);
account = new AccountDepositValidator(account);
_accounts[account.AccountNumber] = account;
return account;
}
}
}
To illustrate this process in action here is a sequence diagram:
- Call Bank.CreateAccount.
- The Bank instantiate an Account class.
- The Bank create an AccountDepositValidator and wrap Account with it
- The Bank return an instance of IAccount.
- Deposit is called on IAccount which is an instance of AccountDepositValidator
- AccountDepositValidator call Validate
- AccountDepositValidator call GetValidations to retrieve the list of validation to evaluate
- An AmountGreaterThaZeroValidation is created
- IsValid returns true
- AccountDepositValidator call base Deposit method
- Balance value is updated
Next
With all this in place the only thing left to do is to implement all the other validators for all method of “IAccount”.
@ 9/30/2009 09:26:00 PM 7 commentaires
Label: Architecture, C#, Design, OOP
Friday, September 4, 2009
Coder une application d'affaire avec Silverlight (Montreal event)
La Communauté .NET de Montréal organise une journée de formation Silverlight samedi le 24 octobre prochain. Pour plus d'information et pour vous enregistrer, veuillez consulter le site suivant:
Windows 7 Launch Parties!
Be Part of Windows History, Host a Windows 7 Launch Party!
Windows 7 Launch party sign-ups are now open across the world! Chosen hosts will receive a free, signature edition of Windows 7 Ultimate!
Host slots are limited – so sign up early!
Go here to sign up: http://www.houseparty.com/windows7
If you are an MVP and plan to host your own Windows 7 party. Please don't forget to upload your pictures and videos to the MVP Award Program page on Facebook. We would love to see your launch party!
Are you Twitter user? Use #win7meetup when you Tweet about it!
Monday, August 24, 2009
Friday, July 31, 2009
TechDays 2009 Sessions Announced, and Other News
Developer Sessions at TechDays
The sessions for TechDays 2009, Microsoft's cross-Canada conference taking place in seven cities this fall, have been posted on the TechDays site. You can go there to see the full set of sessions, or you can check the table below to look at the sessions for the tracks related to software development.
I'm the lead for the Developing for the Microsoft-Based Platform track and John Bristowe is lead for the Developer Fundamentals and Best Practices track. John and I picked the best developer-focused sessions from this year's TechEd conference and put them into our tracks. We've also chosen speakers for each session in each of TechDays' seven cities, going for local developers wherever possible. TechDays features international conference material and local speakers, right near where you live. We're not just expanding your knowledge, we're stretching your dollar, too!
And now, the developer sessions…
Track: Developing for the Microsoft-Based Platform | Track: Developer Fundamentals and Best Practices |
| Learning key skills to develop rich client and web-based applications on the Microsoft-based platform is what this track is all about. In this track you will learn how to develop rich, interactive and interoperable applications for both the client and the web using our newest tools and frameworks. You'll learn how to build software that helps to give your users the best experience possible, whether it's a program running on Windows 7, a website built on ASP.NET MVC or a Silverlight-based rich internet application. You'll also learn how to build services that can deliver data to almost any platform and internet-enabled device. And finally, you'll learn how to build these software and services in ways that are modular and maintainable. | This track is all about taking your skills up a notch while at the same time ensuring effective and efficient interaction with all members of the development team from IT architect, to developer, to tester. You will learn about the importance of Application Lifecycle Management (ALM) and how to leverage the Visual Studio development platform to streamline your efforts. You will learn some best practices from industry professionals while building upon your technical foundation. |
Day One: Front End - User Interface and Experience | Day One: Core Fundamentals and Best Practices |
| Day 1, Session 1: | Day 1, Session 1: |
| Day 1, Session 2: | Day 1, Session 2: |
| Day 1, Session 3: | Day 1, Session 3: |
| Day 1, Session 4: | Day 1, Session 4: |
Day Two - Back End: Programming Frameworks and Principles | Day Two - Team System Fundamentals and Best Practices |
| Day 2, Session 1: | Day 2, Session 1: |
| Day 2, Session 2: | Day 2, Session 2: |
| Day 2, Session 3: | Day 2, Session 3: |
| Day 2, Session 4: | Day 2, Session 4: |
Free TechNet Plus Subscription for TechDays Attendees
Your admission to TechDays gets you more than just two days' worth of conference and networking. We're also putting together a package of goodies that you can use long after we've turned out the lights at the last TechDays venue.
One such goodie is a full year's subscription to TechNet Plus, the Microsoft IT pro resource that gives you, among other things, full, non-time-limited versions of operating systems, servers and Office System software for evaluation (non-production) use. It also gives you access to pre-release versions, a full technical infromation library, two free tech support calls, and more, It's a US$349 value that you get for free if you attend TechDays.
More Than Just a Conference
In addition to coming to a city near you to hold TechDays, we're planning activities for each city in our tour – things like user group events, academic events, Coffee and Code and more! Watch this blog for announcements for your city.
We also have some surprises in store, and we'll announce them…soon.
Register at the Early Bird Price
You could pay the full price of CDN$599 if you really wanted to. We think that you'd rather save a whole $300 and pay just CDN$299. The early bird price for any of the TechDays cities is available only until 6 weeks before that city's conference, and the Vancouver and Toronto conferences are happening in September. Procrastinate at your peril – register now!
Wednesday, July 29, 2009
Thursday, July 23, 2009
Type-safe INotifyPropertyChanged and derived classes
Some of you who read my previous blog post notice that this technique doesn't allow to raise “PropertyChanged” event from a derived class. This is because you can only call method of “PropertyChangedEventHandler” from the class where it is defined. Anywhere else you can only assign (+=) and unassign (-=) event handler.
One way to work around this is to add a method in your base model class that will forward the call to “PropertyChangedEventHandler”.
Here is a modified copy of the class from my previous post:
public class Model : INotifyPropertyChanged
{
private string _data;
public string Data
{
get { return _data; }
set
{
if (_data == value)
return;
_data = value;
// Type safe raise from base method
RaisePropertyChanged(() => Data);
}
}
protected void RaisePropertyChanged(Expression<Func<object>> expression)
{
PropertyChanged.Raise(expression);
}
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = null;
#endregion
}
Now you can define a derived class and use the same method to raise a PropertyChanged event.
public class DerivedModel : Model
{
private string _moreData;
public string MoreData
{
get { return _moreData; }
set
{
if (_moreData == value)
return;
_moreData = value;
RaisePropertyChanged(() => MoreData);
}
}
}
Now with very little effort you can build a type-safe and bindable data model.
It is also useful to be able to raise many property at once. For example if have calculated properties that depends on others like in this sample class:
public class User : INotifyPropertyChanged
{
private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
if (_lastName == value)
return;
_lastName = value;
RaisePropertyChanged(()=>LastName, ()=>FullName);
}
}
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
if (_firstName == value)
return;
_firstName = value;
RaisePropertyChanged(() => FirstName, () => FullName);
}
}
public string FullName
{
get { return String.Format("{0} {1}", _firstName, _lastName); }
}
public void RaisePropertyChanged(params Expression<Func<object>>[] expression)
{
PropertyChanged.Raise(expression);
}
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = null;
#endregion
}
Because a change to either “FirstName” or “LastName” should trigger a change to “FullName” you have to raise both changes from both properties. Of course you can call “RaisePropertyChanged” many times but with a simple overload you can do this. All you have to do is add this to your extensions class.
public static void Raise(this PropertyChangedEventHandler handler, params Expression<Func<object>>[] proppertyExpressions)
{
foreach (var expression in proppertyExpressions)
Raise(handler, expression);
}
Aside from beeing type safe, this method will give you intellisense support while you type your “RaiePropertyChanged” calls. You still have to type the right property though.
Wednesday, July 22, 2009
How to use INotifyPropertyChanged, the type-safe way (no magic string)
Implementation of the INotifyPropertyChanged interface is quite simple. There is only one event to implement. Take for example the following simple model class:
public class Model : INotifyPropertyChanged
{
private string _data;
public string Data
{
get { return _data; }
set
{
if (_data == value)
return;
_data = value;
// Type un-safe PropertyChanged raise
PropertyChanged(this, new PropertyChangedEventArgs("Data"));
}
}
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = null;
#endregion
}
This is a pretty standard way to implement a bindable property. The problem here is the “Data” string to specify which property changed. If someone change the name of the property without changing the content of the string, the code will compile fine but won’t work. In a big application with may properties it can be hard to detect and find the problem.
The best solution is to rely on the compiler to warn us. But because the property name is a string it can’t. So let’s change that line with a type-safe one.
public class Model : INotifyPropertyChanged
{
private string _data;
public string Data
{
get { return _data; }
set
{
if (_data == value)
return;
_data = value;
// Type safe PropertyChanged raise
PropertyChanged.Raise(() => Data);
}
}
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = null;
#endregion
}
What is the trick? Raise is an extension method that takes a lambda expression to specify the name of the property in a type safe way. The Raise method resolve this expression to extract the name of the property and pass it to the PropertyChanged event.
public static class PropertyChangedExtensions
{
public static void Raise(this PropertyChangedEventHandler handler, Expression<Func<object>> propertyExpression)
{
if (handler != null)
{
// Retreive lambda body
var body = propertyExpression.Body as MemberExpression;
if (body == null)
throw new ArgumentException("'propertyExpression' should be a member expression");
// Extract the right part (after "=>")
var vmExpression = body.Expression as ConstantExpression;
if (vmExpression == null)
throw new ArgumentException("'propertyExpression' body should be a constant expression");
// Create a reference to the calling object to pass it as the sender
LambdaExpression vmlambda = Expression.Lambda(vmExpression);
Delegate vmFunc = vmlambda.Compile();
object vm = vmFunc.DynamicInvoke();
// Extract the name of the property to raise a change on
string propertyName = body.Member.Name;
var e = new PropertyChangedEventArgs(propertyName);
handler(vm, e);
}
}
}
All you have to do is to put this extension method in your code and the jib is done. Of course at the end a string will be used to raise the PropertyChanged event but because you don’t have to type it, you don’t have to maintain it.
Tuesday, July 21, 2009
How to use INotifyPropertyChanged, the type-safe way (no magic string)
Implementation of the INotifyPropertyChanged interface is quite simple. There is only one event to implement. Take for example the following simple model class:
public class Model : INotifyPropertyChanged
{
private string _data;
public string Data
{
get { return _data; }
set
{
if (_data == value)
return;
_data = value;
// Type un-safe PropertyChanged raise
PropertyChanged(this, new PropertyChangedEventArgs("Data"));
}
}
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = null;
#endregion
}
This is a pretty standard way to implement a bindable property. The problem here is the “Data” string to specify which property changed. If someone change the name of the property without changing the content of the string, the code will compile fine but won’t work. In a big application with may properties it can be hard to detect and find the problem.
The best solution is to rely on the compiler to warn us. But because the property name is a string it can’t. So let’s change that line with a type-safe one.
public class Model : INotifyPropertyChanged
{
private string _data;
public string Data
{
get { return _data; }
set
{
if (_data == value)
return;
_data = value;
// Type safe PropertyChanged raise
PropertyChanged.Raise(() => Data);
}
}
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged = null;
#endregion
}
What is the trick? Raise is an extension method that takes a lambda expression to specify the name of the property in a type safe way. The Raise method resolve this expression to extract the name of the property and pass it to the PropertyChanged event.
public static class PropertyChangedExtensions
{
public static void Raise(this PropertyChangedEventHandler handler, Expression<Func<object>> propertyExpression)
{
if (handler != null)
{
// Retreive lambda body
var body = propertyExpression.Body as MemberExpression;
if (body == null)
throw new ArgumentException("'propertyExpression' should be a member expression");
// Extract the right part (after "=>")
var vmExpression = body.Expression as ConstantExpression;
if (vmExpression == null)
throw new ArgumentException("'propertyExpression' body should be a constant expression");
// Create a reference to the calling object to pass it as the sender
LambdaExpression vmlambda = Expression.Lambda(vmExpression);
Delegate vmFunc = vmlambda.Compile();
object vm = vmFunc.DynamicInvoke();
// Extract the name of the property to raise a change on
string propertyName = body.Member.Name;
var e = new PropertyChangedEventArgs(propertyName);
handler(vm, e);
}
}
}
All you have to do is to put this extension method in your code and the jib is done. Of course at the end a string will be used to raise the PropertyChanged event but because you don’t have to type it, you don’t have to maintain it.