C# Adapter Design Pattern
The Adapter design pattern converts the interface of a class into another interface clients expect. This design pattern lets classes work together that couldn‘t otherwise because of incompatible interfaces.
C# code examples of the Adapter design pattern is provided in 3 forms:
Frequency of use:
medium-high
UML class diagram
A visualization of the classes and objects participating in this pattern.
Participants
The classes and objects participating in this pattern include:
-
Target (
ChemicalCompound
)
- defines the domain-specific interface that Client uses.
-
Adapter (
Compound
)
- adapts the interface Adaptee to the Target interface.
-
Adaptee (
ChemicalDatabank
)
- defines an existing interface that needs adapting.
-
Client (
AdapterApp
)
- collaborates with objects conforming to the Target interface.
Structural code in C#
This structural code demonstrates the
Adapter pattern which maps the interface of one class onto another so that
they can work together. These incompatible classes may come from
different libraries or frameworks.
copied to clipboard
using System;
namespace Adapter.Structural
{
/// <summary>
/// Adapter Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
// Create adapter and place a request
Target target = new Adapter();
target.Request();
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Target' class
/// </summary>
public class Target
{
public virtual void Request()
{
Console.WriteLine("Called Target Request()");
}
}
/// <summary>
/// The 'Adapter' class
/// </summary>
public class Adapter : Target
{
private Adaptee adaptee = new Adaptee();
public override void Request()
{
// Possibly do some other work
// and then call SpecificRequest
adaptee.SpecificRequest();
}
}
/// <summary>
/// The 'Adaptee' class
/// </summary>
public class Adaptee
{
public void SpecificRequest()
{
Console.WriteLine("Called SpecificRequest()");
}
}
}
using System;
namespace Adapter.Structural
{
/// <summary>
/// Adapter Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
// Create adapter and place a request
Target target = new Adapter();
target.Request();
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Target' class
/// </summary>
public class Target
{
public virtual void Request()
{
Console.WriteLine("Called Target Request()");
}
}
/// <summary>
/// The 'Adapter' class
/// </summary>
public class Adapter : Target
{
private Adaptee adaptee = new Adaptee();
public override void Request()
{
// Possibly do some other work
// and then call SpecificRequest
adaptee.SpecificRequest();
}
}
/// <summary>
/// The 'Adaptee' class
/// </summary>
public class Adaptee
{
public void SpecificRequest()
{
Console.WriteLine("Called SpecificRequest()");
}
}
}
Output
Called SpecificRequest()
Real-world code in C#
This real-world code demonstrates
the use of a legacy chemical databank. Chemical compound objects access
the databank through an Adapter interface.
copied to clipboard
using System;
namespace Adapter.RealWorld
{
/// <summary>
/// Adapter Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
// Non-adapted chemical compound
Compound unknown = new Compound();
unknown.Display();
// Adapted chemical compounds
Compound water = new RichCompound("Water");
water.Display();
Compound benzene = new RichCompound("Benzene");
benzene.Display();
Compound ethanol = new RichCompound("Ethanol");
ethanol.Display();
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Target' class
/// </summary>
public class Compound
{
protected float boilingPoint;
protected float meltingPoint;
protected double molecularWeight;
protected string molecularFormula;
public virtual void Display()
{
Console.WriteLine("\nCompound: Unknown ------ ");
}
}
/// <summary>
/// The 'Adapter' class
/// </summary>
public class RichCompound : Compound
{
private string chemical;
private ChemicalDatabank bank;
// Constructor
public RichCompound(string chemical)
{
this.chemical = chemical;
}
public override void Display()
{
// The Adaptee
bank = new ChemicalDatabank();
boilingPoint = bank.GetCriticalPoint(chemical, "B");
meltingPoint = bank.GetCriticalPoint(chemical, "M");
molecularWeight = bank.GetMolecularWeight(chemical);
molecularFormula = bank.GetMolecularStructure(chemical);
Console.WriteLine("\nCompound: {0} ------ ", chemical);
Console.WriteLine(" Formula: {0}", molecularFormula);
Console.WriteLine(" Weight : {0}", molecularWeight);
Console.WriteLine(" Melting Pt: {0}", meltingPoint);
Console.WriteLine(" Boiling Pt: {0}", boilingPoint);
}
}
/// <summary>
/// The 'Adaptee' class
/// </summary>
public class ChemicalDatabank
{
// The databank 'legacy API'
public float GetCriticalPoint(string compound, string point)
{
// Melting Point
if (point == "M")
{
switch (compound.ToLower())
{
case "water": return 0.0f;
case "benzene": return 5.5f;
case "ethanol": return -114.1f;
default: return 0f;
}
}
// Boiling Point
else
{
switch (compound.ToLower())
{
case "water": return 100.0f;
case "benzene": return 80.1f;
case "ethanol": return 78.3f;
default: return 0f;
}
}
}
public string GetMolecularStructure(string compound)
{
switch (compound.ToLower())
{
case "water": return "H20";
case "benzene": return "C6H6";
case "ethanol": return "C2H5OH";
default: return "";
}
}
public double GetMolecularWeight(string compound)
{
switch (compound.ToLower())
{
case "water": return 18.015;
case "benzene": return 78.1134;
case "ethanol": return 46.0688;
default: return 0d;
}
}
}
}
using System;
namespace Adapter.RealWorld
{
/// <summary>
/// Adapter Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
// Non-adapted chemical compound
Compound unknown = new Compound();
unknown.Display();
// Adapted chemical compounds
Compound water = new RichCompound("Water");
water.Display();
Compound benzene = new RichCompound("Benzene");
benzene.Display();
Compound ethanol = new RichCompound("Ethanol");
ethanol.Display();
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Target' class
/// </summary>
public class Compound
{
protected float boilingPoint;
protected float meltingPoint;
protected double molecularWeight;
protected string molecularFormula;
public virtual void Display()
{
Console.WriteLine("\nCompound: Unknown ------ ");
}
}
/// <summary>
/// The 'Adapter' class
/// </summary>
public class RichCompound : Compound
{
private string chemical;
private ChemicalDatabank bank;
// Constructor
public RichCompound(string chemical)
{
this.chemical = chemical;
}
public override void Display()
{
// The Adaptee
bank = new ChemicalDatabank();
boilingPoint = bank.GetCriticalPoint(chemical, "B");
meltingPoint = bank.GetCriticalPoint(chemical, "M");
molecularWeight = bank.GetMolecularWeight(chemical);
molecularFormula = bank.GetMolecularStructure(chemical);
Console.WriteLine("\nCompound: {0} ------ ", chemical);
Console.WriteLine(" Formula: {0}", molecularFormula);
Console.WriteLine(" Weight : {0}", molecularWeight);
Console.WriteLine(" Melting Pt: {0}", meltingPoint);
Console.WriteLine(" Boiling Pt: {0}", boilingPoint);
}
}
/// <summary>
/// The 'Adaptee' class
/// </summary>
public class ChemicalDatabank
{
// The databank 'legacy API'
public float GetCriticalPoint(string compound, string point)
{
// Melting Point
if (point == "M")
{
switch (compound.ToLower())
{
case "water": return 0.0f;
case "benzene": return 5.5f;
case "ethanol": return -114.1f;
default: return 0f;
}
}
// Boiling Point
else
{
switch (compound.ToLower())
{
case "water": return 100.0f;
case "benzene": return 80.1f;
case "ethanol": return 78.3f;
default: return 0f;
}
}
}
public string GetMolecularStructure(string compound)
{
switch (compound.ToLower())
{
case "water": return "H20";
case "benzene": return "C6H6";
case "ethanol": return "C2H5OH";
default: return "";
}
}
public double GetMolecularWeight(string compound)
{
switch (compound.ToLower())
{
case "water": return 18.015;
case "benzene": return 78.1134;
case "ethanol": return 46.0688;
default: return 0d;
}
}
}
}
Output
Compound: Unknown ------
Compound: Water ------
Formula: H20
Weight : 18.015
Melting Pt: 0
Boiling Pt: 100
Compound: Benzene ------
Formula: C6H6
Weight : 78.1134
Melting Pt: 5.5
Boiling Pt: 80.1
Compound: Alcohol ------
Formula: C2H6O2
Weight : 46.0688
Melting Pt: -114.1
Boiling Pt: 78.3
.NET Optimized code in C#
The .NET optimized code demonstrates the same code as above but uses
more modern C# and .NET features.
Here is an elegant C# Adapter solution.
copied to clipboard
namespace Adapter.NetOptimized;
using static System.Console;
/// <summary>
/// Adapter Design Pattern
/// </summary>
public class Program
{
public static void Main()
{
// Non-adapted chemical compound
var unknown = new Compound();
unknown.Display();
// Adapted chemical compounds
var water = new RichCompound(Chemical.Water);
water.Display();
var benzene = new RichCompound(Chemical.Benzene);
benzene.Display();
var ethanol = new RichCompound(Chemical.Ethanol);
ethanol.Display();
// Wait for user
ReadKey();
}
}
/// <summary>
/// The 'Target' class
/// </summary>
public class Compound
{
public Chemical Chemical { get; protected set; }
public float BoilingPoint { get; protected set; }
public float MeltingPoint { get; protected set; }
public double MolecularWeight { get; protected set; }
public string? MolecularFormula { get; protected set; }
public virtual void Display()
{
WriteLine("\nCompound: Unknown ------ ");
}
}
/// <summary>
/// The 'Adapter' class
/// </summary>
public class RichCompound : Compound
{
private readonly ChemicalDatabank bank = new();
// Constructor
public RichCompound(Chemical chemical)
{
Chemical = chemical;
}
public override void Display()
{
// Adaptee request methods
BoilingPoint = bank.GetCriticalPoint(Chemical, State.Boiling);
MeltingPoint = bank.GetCriticalPoint(Chemical, State.Melting);
MolecularWeight = bank.GetMolecularWeight(Chemical);
MolecularFormula = bank.GetMolecularStructure(Chemical);
WriteLine($"\nCompound: { Chemical} ------ ");
WriteLine($" Formula: {MolecularFormula}");
WriteLine($" Weight : {MolecularWeight}");
WriteLine($" Melting Pt: {MeltingPoint}");
WriteLine($" Boiling Pt: {BoilingPoint}");
}
}
/// <summary>
/// The 'Adaptee' class
/// </summary>
public class ChemicalDatabank
{
// The databank 'legacy API'
public float GetCriticalPoint(Chemical compound, State point)
{
// Melting Point
if (point == State.Melting)
{
return compound switch
{
Chemical.Water => 0.0f,
Chemical.Benzene => 5.5f,
Chemical.Ethanol => -114.1f,
_ => 0f,
};
}
// Boiling Point
else
{
return compound switch
{
Chemical.Water => 100.0f,
Chemical.Benzene => 80.1f,
Chemical.Ethanol => 78.3f,
_ => 0f,
};
}
}
public string GetMolecularStructure(Chemical compound)
{
return compound switch
{
Chemical.Water => "H20",
Chemical.Benzene => "C6H6",
Chemical.Ethanol => "C2H5OH",
_ => "",
};
}
public double GetMolecularWeight(Chemical compound)
{
return compound switch
{
Chemical.Water => 18.015d,
Chemical.Benzene => 78.1134d,
Chemical.Ethanol => 46.0688d,
_ => 0d
};
}
}
/// <summary>
/// Chemical enumeration
/// </summary>
public enum Chemical
{
Water,
Benzene,
Ethanol
}
/// <summary>
/// State enumeration
/// </summary>
public enum State
{
Boiling,
Melting
}
namespace Adapter.NetOptimized;
using static System.Console;
/// <summary>
/// Adapter Design Pattern
/// </summary>
public class Program
{
public static void Main()
{
// Non-adapted chemical compound
var unknown = new Compound();
unknown.Display();
// Adapted chemical compounds
var water = new RichCompound(Chemical.Water);
water.Display();
var benzene = new RichCompound(Chemical.Benzene);
benzene.Display();
var ethanol = new RichCompound(Chemical.Ethanol);
ethanol.Display();
// Wait for user
ReadKey();
}
}
/// <summary>
/// The 'Target' class
/// </summary>
public class Compound
{
public Chemical Chemical { get; protected set; }
public float BoilingPoint { get; protected set; }
public float MeltingPoint { get; protected set; }
public double MolecularWeight { get; protected set; }
public string? MolecularFormula { get; protected set; }
public virtual void Display()
{
WriteLine("\nCompound: Unknown ------ ");
}
}
/// <summary>
/// The 'Adapter' class
/// </summary>
public class RichCompound : Compound
{
private readonly ChemicalDatabank bank = new();
// Constructor
public RichCompound(Chemical chemical)
{
Chemical = chemical;
}
public override void Display()
{
// Adaptee request methods
BoilingPoint = bank.GetCriticalPoint(Chemical, State.Boiling);
MeltingPoint = bank.GetCriticalPoint(Chemical, State.Melting);
MolecularWeight = bank.GetMolecularWeight(Chemical);
MolecularFormula = bank.GetMolecularStructure(Chemical);
WriteLine($"\nCompound: { Chemical} ------ ");
WriteLine($" Formula: {MolecularFormula}");
WriteLine($" Weight : {MolecularWeight}");
WriteLine($" Melting Pt: {MeltingPoint}");
WriteLine($" Boiling Pt: {BoilingPoint}");
}
}
/// <summary>
/// The 'Adaptee' class
/// </summary>
public class ChemicalDatabank
{
// The databank 'legacy API'
public float GetCriticalPoint(Chemical compound, State point)
{
// Melting Point
if (point == State.Melting)
{
return compound switch
{
Chemical.Water => 0.0f,
Chemical.Benzene => 5.5f,
Chemical.Ethanol => -114.1f,
_ => 0f,
};
}
// Boiling Point
else
{
return compound switch
{
Chemical.Water => 100.0f,
Chemical.Benzene => 80.1f,
Chemical.Ethanol => 78.3f,
_ => 0f,
};
}
}
public string GetMolecularStructure(Chemical compound)
{
return compound switch
{
Chemical.Water => "H20",
Chemical.Benzene => "C6H6",
Chemical.Ethanol => "C2H5OH",
_ => "",
};
}
public double GetMolecularWeight(Chemical compound)
{
return compound switch
{
Chemical.Water => 18.015d,
Chemical.Benzene => 78.1134d,
Chemical.Ethanol => 46.0688d,
_ => 0d
};
}
}
/// <summary>
/// Chemical enumeration
/// </summary>
public enum Chemical
{
Water,
Benzene,
Ethanol
}
/// <summary>
/// State enumeration
/// </summary>
public enum State
{
Boiling,
Melting
}
Output
Compound: Unknown ------
Compound: Water ------
Formula: H20
Weight : 18.015
Melting Pt: 0
Boiling Pt: 100
Compound: Benzene ------
Formula: C6H6
Weight : 78.1134
Melting Pt: 5.5
Boiling Pt: 80.1
Compound: Alcohol ------
Formula: C2H6O2
Weight : 46.0688
Melting Pt: -114.1
Boiling Pt: 78.3
Last updated on Mar 17, 2024
Want to know more?
Learn how to build .NET applications in
33 days
with
design patterns, ultra clean architecture, and more.
Learn more about our
Dofactory .NET developer package.