This tutorial aims to introduce you to the concepts of Structural Patterns in C#, specifically focusing on the Adapter and Decorator patterns.
By the end of this tutorial, you will be able to:
Basic understanding of C# programming and Object-Oriented Programming (OOP) concepts is required.
Structural Patterns in programming provide a manner to define relationships between classes or objects so that they can form larger structures. They simplify the structure and promote reusability.
The Adapter pattern is a structural design pattern that allows objects with incompatible interfaces to work together. It wraps itself around an object and exposes a standard interface to interact with that object.
Here's an example of an Adapter pattern:
// the 'Adaptee'
public class OldSystem
{
public string OldRequest()
{
return "Old System";
}
}
// the 'Adapter'
public class Adapter : INewSystem
{
private OldSystem _oldSystem;
public Adapter(OldSystem oldSystem)
{
_oldSystem = oldSystem;
}
public string Request()
{
return $"Adapter: ({_oldSystem.OldRequest()})";
}
}
// the 'Target'
public interface INewSystem
{
string Request();
}
In the above example, Adapter
is making the OldSystem
compatible with INewSystem
.
The Decorator pattern provides a way to add new behavior to an object dynamically, without altering its implementation.
Here's an example of a Decorator pattern:
// 'Component'
public interface IComponent
{
string Operation();
}
// 'ConcreteComponent'
public class Component : IComponent
{
public string Operation()
{
return "ConcreteComponent";
}
}
// 'Decorator'
public class Decorator : IComponent
{
protected IComponent _component;
public Decorator(IComponent component)
{
_component = component;
}
public virtual string Operation()
{
return _component.Operation();
}
}
// 'ConcreteDecoratorA'
public class ConcreteDecoratorA : Decorator
{
public ConcreteDecoratorA(IComponent comp) : base(comp) { }
public override string Operation()
{
return $"ConcreteDecoratorA({base.Operation()})";
}
}
In the above example, ConcreteDecoratorA
is adding additional behavior to Component
.
class Program
{
static void Main(string[] args)
{
OldSystem oldSystem = new OldSystem();
INewSystem adapter = new Adapter(oldSystem);
Console.WriteLine(adapter.Request()); // Output: Adapter: (Old System)
}
}
class Program
{
static void Main(string[] args)
{
IComponent component = new Component();
Console.WriteLine("Without decorator: ");
Console.WriteLine(component.Operation()); // Output: ConcreteComponent
Console.WriteLine("\nWith decorator: ");
IComponent decorator = new ConcreteDecoratorA(component);
Console.WriteLine(decorator.Operation()); // Output: ConcreteDecoratorA(ConcreteComponent)
}
}
In this tutorial, we have learned about the Adapter and Decorator Structural Patterns. We also implemented these patterns in C#. Remember, the Adapter pattern is used to make two incompatible interfaces work together while the Decorator pattern allows adding new behavior to an object dynamically.
Rectangle
and Circle
class work together.Rectangle
class.Remember, the best way to learn is by doing. Try to modify and play with the code examples given above. Happy coding!