Skip to content
Carmel Eve By Carmel Eve Software Engineer I
Design patterns in C# - The Adapter Pattern

Hello again, in this post I'm continuing my series on design patterns in C#, this time focusing on the adaptor pattern!

The adapter pattern is useful when you want to use a class that does not fit the design of your existing solution. This is often the case when using legacy or external code. The adapter pattern allows you to define a wrapper which executes the desired behaviour, but exposes it through a method which your solution expects.

As always, I think this will become clearer when we delve into our (dinosaur-based) example.

Adapter Pattern Example

So, today we've been transported to a post-meteor world...

And in this world, in the age of mammals, we have a ChildCreator that expects things to work in a certain way:

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns.Adapter
{
    public static class ChildCreator
    {
        public static IChild CreateChild(IMammal mammal)
        {
            return mammal.GiveBirth();
        }
    }
}

Where the IMammal interface looks like this:

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns.Adapter
{
    public interface IMammal
    {
        IChild GiveBirth();
    }
}

The GiveBirth method produces an IChild, which has a single method, Cry (which I'm pretty sure is the main functionality of a new born baby, right?).

namespace DesignPatterns.Adapter
{
    public interface IChild
    {
        void Cry();
    }
}

However, though the world has moved on, we have a few legacy Triceratops hanging around, that are just trying to get along in an unfamiliar place... Unfortunately a Triceratops works somewhat differently to the majority of mammals (being a reptile and all), possessing a single LayEgg method:

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns.Adapter
{
    public class Triceratops
    {
        public TriceratopsEgg LayEgg()
        {
            return new TriceratopsEgg();
        }
    }
}

The TriceratopsEgg produced by this method then has the ability to hatch into a TriceratopsChild:

namespace DesignPatterns.Adapter
{
    public class TriceratopsEgg
    {
        public IChild Hatch()
        {
            return new TriceratopsChild();
        }
    }
}

And here is where our adapter comes in. We need a way that our ChildCreator can work with the Triceratops to produce a child.

Programming C# 10 Book, by Ian Griffiths, published by O'Reilly Media, is now available to buy.

If we define a TriceratopsToMammalAdapter, which implements the IMammal class, and wraps an internal Triceratops:

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns.Adapter
{
    public class TriceratopsToMammalAdapter : IMammal
    {
        private readonly Triceratops triceratops;

        public TriceratopsToMammalAdapter(Triceratops triceratops)
        {
            this.triceratops = triceratops;
        }

        public IChild GiveBirth()
        {
            TriceratopsEgg egg = triceratops.LayEgg();

            IChild child = egg.Hatch();

            return child;
        }
    }
}

Then the GiveBirth method can call the LayEgg method of the internal Triceratops, and then Hatch that egg to produce an IChild. We then return the child, and the Triceratops is able to continue to function in the new mammalian landscape.

If we now use our TriceratopsToMammalAdapter and ChildCreator:

public static void AdapterExample()
{
    var triceratops = new Triceratops();
    var child = ChildCreator.CreateChild(new TriceratopsToMammalAdapter(triceratops));

    child.Cry();
}
The Introduction to Rx.NET 2nd Edition (2024) Book, by Ian Griffiths & Lee Campbell, is now available to download for FREE.

We can produce a healthy, crying, TriceratopsChild, with the output: TRICERATOPS IS CRYING! (Granted, as the lack of modern triceratops indicates, this probably isn't a long term solution and eventually that legacy code will likely still need to be replaced...)

Thanks for reading! Here's a link to the GitHub repository which contains all the code for this blog series. And watch of for my next blog on design patterns in C#!

Carmel Eve

Software Engineer I

Carmel Eve

Carmel is a software engineer, LinkedIn Learning instructor and STEM ambassador.

Over the past four years she has been focused on delivering cloud-first solutions to a variety of problems. These have ranged from highly-performant serverless architectures, to web applications, to reporting and insight pipelines and data analytics engines.

In her time at endjin, she has written many blog posts covering a huge range of topics, including deconstructing Rx operators and mental well-being and managing remote working.

Carmel's first LinkedIn Learning course on how to prepare for the Az-204 exam - developing solutions for Microsoft Azure - was released in April 2021. Over the last couple of years she has also spoken at NDC, APISpecs and SQLBits. These talks covered a range of topics, from reactive big-data processing to secure Azure architectures.

She is also passionate about diversity and inclusivity in tech. She is a STEM ambassador in her local community and is taking part in a local mentorship scheme. Through this work she hopes to be a part of positive change in the industry.

Carmel won "Apprentice Engineer of the Year" at the Computing Rising Star Awards 2019.

Carmel worked at endjin from 2016 to 2021.