mercredi 13 août 2008

Design patterns in C# - Decorator

Role

The role of the Decorator pattern is to provide a way of attaching new state and

behavior to an object dynamically. The object does not know it is being "decorated,"

which makes this a useful pattern for evolving systems. A key implementation

point in the Decorator pattern is that decorators both inherit the original class

and contain an instantiation of it.

Illustration

As its name suggests, the Decorator pattern takes an existing object and adds to it. As

an example, consider a photo that is displayed on a screen. There are many ways to

add to the photo, such as putting a border around it or specifying tags related to the

content. Such additions can be displayed on top of the photo.
 

The beauty of this pattern is that:

• The original object is unaware of any decorations.

• There is no one big feature-laden class with all the options in it.

• The decorations are independent of each other.

• The decorations can be composed together in a mix-and-match fashion.

Design

Now, we can specify the players in the Decorator pattern in a UML diagram, shown

in Figure 2-2. Because this is the first pattern we are describing in UML, we'll take it

slowly. (The UML that we need for patterns in this book is covered in Chapter 1 and

summarized in Table 1-1.) The essential players in this UML diagram are:

Component

An original class of objects that can have operations added or modified (there

may be more than one such class)

Operation

An operation in

IComponent objects that can be replaced (there may be several

operations)

IComponent

The interface that identifies the classes of objects that can be decorated

(

Component is one of these)

Decorator

A class that conforms to the

IComponent interface and adds state and/or behavior

(there may be more than one such class)

 

The center of the UML diagram is the

Decorator class. It includes two types of relationships

with the

IComponent interface:

Is-a

The is-a relationshipis shown by a dotted arrow from the

Decorator to

IComponent

, indicating that Decorator realizes the IComponent interface. The fact

that

Decorator inherits from IComponent means that Decorator objects can be

used wherever

IComponent objects are expected. The Component class is also in an

is-a relationshipwith

IComponent, and therefore the client can use Component and

Decorator

objects interchangeably—the heart of the Decorator pattern.

Has-a

The has-a relationshipis shown by an open diamond on the

Decorator, linked to

IComponent

. This indicates that the Decorator instantiates one or more

IComponent

objects and that decorated objects can outlive the originals. The

Decorator

uses the component attribute (of type IComponent) to invoke any

replacement

Operation it might wish to override. This is the way the Decorator

pattern achieves its objective.

The

addedBehavior operation and the addedState attribute in the Decorator class are

other optional ways of extending what is in the original

Component objects. We'll look

at some examples momentarily.



--
Alain Lompo
Excelta - Conseils et services informatiques
MCT
MCSD For Microsoft .Net
MVP Windows Systems Server / Biztalk Server
Certifié ITIL et Microsoft Biztalk Server

Overview of Test Driven Development

Test-Driven Development arose out of early literature around XP and other agile methods and was put forth, first and foremost, as a way to support refactoring. The idea was that writing your tests first forced you into thinking about tests, which in turn encouraged you to write more. The more tests you had, the easier it was to practice refactoring, or the art of making small incremental changes to your code to improve its structure.

Proper refactoring involves making very small organizational changes to your code, then making sure that your tests still pass. Without proper test coverage, refactoring is much more difficult.

The process of TDD is often described, in abbreviated form, as ‘‘Red, Green, Refactor,’’ meaning that first you write tests so that the tests fail (causing a ‘‘red light’’ in most testing GUIs), then you write code to make the tests pass (causing the ‘‘light’’ to turn green), and then you are free to refactor or improve the structure of your code, safe in the knowledge that the tests still pass. Once the refactoring is complete, the cycle begins again:

❑ Write tests that fail.
❑ Write code to make the tests pass.
❑ Refactor your code to improve its structure.
❑ Repeat

tests. It is always tempting to ‘‘just write a little code’’ before you start writing the tests for it. You see a problem, and you want to code your way out of it. It can be very difficult to stick to writing tests first, then writing code to make them pass. However, there are a number of compelling reasons for writing the tests first:

1. If you wait, you won’t really write the tests. This is just human nature. In almost every software development shop, the most important metric is success, which means that as soon as
your code works, you’ve accomplished your primary goal, and the organization will reward
moving on to write more code above going back to write unit tests.

2. Writing the tests first forces you, as the developer, to think about your interfaces. It is very easy to write an interface in a vacuum and then discover that it doesn’t work when someone tries to consume your interface. If you write the tests first, you are both consumer and producer, and that leads to much better design. Tests help to define your contract.

3. Tests can provide documentation that is often more accessible to other developers than
written documentation would be. Unit tests reflect the way the developer who wrote
those tests thought about how the code was designed to be used. Tests define our expectations.
If the same developer writes both the unit tests and the code to make those tests pass,
then the tests reflect the intent of that developer. Writing the tests first expresses that intent more clearly than writing tests later to fit the code you have already written

TDD can also be very useful when doing pair programming. The most effective way to use TDD to pair is for one person to write the test that expresses his or her intent and for the other person to write the code that makes that test pass. This can be done at a very physical level, passing the keyboard back and forth.

First one developer writes the test and then passes the keyboard to the second developer, who then must make the test pass. The pair then jointly decides if any refactoring needs to be done, and the cycle begins again. This time the developers switch roles, trading test writing for implementation tasks. This method is not only fun, but also leads to a very high level of productivity and very consistent interface design, because two pairs of eyes have been on the code, and two developers are forced to agree on the intent of their interface.

Test-Driven Development applies to your whole software development lifecycle, not just to the beginning of the process. Tests define the requirements of your system as understood at the time the tests were written. In fact, in some agile projects, tests might be the only concrete representation of the project’s requirements, if the developers have direct access to their customer and the customer doesn’t provide written requirements beyond story cards.

One of the most important ways to use TDD may come after the release of your project. Every time a defect in your code is reported, the first thing you should do is write a test that exposes the defect. If you get a bug report and immediately create a test that causes the bug to happen, then you can be secure in the knowledge that when your tests pass, the defect is resolved. This provides a great way to ensure success in fixing the bug, and the test remains as part of the total unit test corpus, providing regression testing so that you know the bug won’t reoccur due to future changes. Those new tests may represent aspects of the system that were never properly tested before (this is why code coverage metrics are important; more on that later), or it might mean that the developer who wrote the initial code had an incorrect or
incomplete understanding of the requirements.

Le blog d'Ekuality

Bonjour à tous,

Nous utiliserons ce blog pour publier des tutoriels simples sur .Net et tout ce qui va autour dans le cadre du projet Ekuality.

L'idée est de développer des leçons graduelles les unes à la suite des autres et d'essayer de valider les acquis pour que le projet en bénéficie

Blessings