Dofactory.com
Dofactory.com

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
C# Design Patterns

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.

  1. using System;
  2. namespace Adapter.Structural
  3. {
  4. /// <summary>
  5. /// Adapter Design Pattern
  6. /// </summary>
  7. public class Program
  8. {
  9. public static void Main(string[] args)
  10. {
  11. // Create adapter and place a request
  12. Target target = new Adapter();
  13. target.Request();
  14. // Wait for user
  15. Console.ReadKey();
  16. }
  17. }
  18. /// <summary>
  19. /// The 'Target' class
  20. /// </summary>
  21. public class Target
  22. {
  23. public virtual void Request()
  24. {
  25. Console.WriteLine("Called Target Request()");
  26. }
  27. }
  28. /// <summary>
  29. /// The 'Adapter' class
  30. /// </summary>
  31. public class Adapter : Target
  32. {
  33. private Adaptee adaptee = new Adaptee();
  34. public override void Request()
  35. {
  36. // Possibly do some other work
  37. // and then call SpecificRequest
  38. adaptee.SpecificRequest();
  39. }
  40. }
  41. /// <summary>
  42. /// The 'Adaptee' class
  43. /// </summary>
  44. public class Adaptee
  45. {
  46. public void SpecificRequest()
  47. {
  48. Console.WriteLine("Called SpecificRequest()");
  49. }
  50. }
  51. }
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.

  1. using System;
  2. namespace Adapter.RealWorld
  3. {
  4. /// <summary>
  5. /// Adapter Design Pattern
  6. /// </summary>
  7. public class Program
  8. {
  9. public static void Main(string[] args)
  10. {
  11. // Non-adapted chemical compound
  12. Compound unknown = new Compound();
  13. unknown.Display();
  14. // Adapted chemical compounds
  15. Compound water = new RichCompound("Water");
  16. water.Display();
  17. Compound benzene = new RichCompound("Benzene");
  18. benzene.Display();
  19. Compound ethanol = new RichCompound("Ethanol");
  20. ethanol.Display();
  21. // Wait for user
  22. Console.ReadKey();
  23. }
  24. }
  25. /// <summary>
  26. /// The 'Target' class
  27. /// </summary>
  28. public class Compound
  29. {
  30. protected float boilingPoint;
  31. protected float meltingPoint;
  32. protected double molecularWeight;
  33. protected string molecularFormula;
  34. public virtual void Display()
  35. {
  36. Console.WriteLine("\nCompound: Unknown ------ ");
  37. }
  38. }
  39. /// <summary>
  40. /// The 'Adapter' class
  41. /// </summary>
  42. public class RichCompound : Compound
  43. {
  44. private string chemical;
  45. private ChemicalDatabank bank;
  46. // Constructor
  47. public RichCompound(string chemical)
  48. {
  49. this.chemical = chemical;
  50. }
  51. public override void Display()
  52. {
  53. // The Adaptee
  54. bank = new ChemicalDatabank();
  55. boilingPoint = bank.GetCriticalPoint(chemical, "B");
  56. meltingPoint = bank.GetCriticalPoint(chemical, "M");
  57. molecularWeight = bank.GetMolecularWeight(chemical);
  58. molecularFormula = bank.GetMolecularStructure(chemical);
  59. Console.WriteLine("\nCompound: {0} ------ ", chemical);
  60. Console.WriteLine(" Formula: {0}", molecularFormula);
  61. Console.WriteLine(" Weight : {0}", molecularWeight);
  62. Console.WriteLine(" Melting Pt: {0}", meltingPoint);
  63. Console.WriteLine(" Boiling Pt: {0}", boilingPoint);
  64. }
  65. }
  66. /// <summary>
  67. /// The 'Adaptee' class
  68. /// </summary>
  69. public class ChemicalDatabank
  70. {
  71. // The databank 'legacy API'
  72. public float GetCriticalPoint(string compound, string point)
  73. {
  74. // Melting Point
  75. if (point == "M")
  76. {
  77. switch (compound.ToLower())
  78. {
  79. case "water": return 0.0f;
  80. case "benzene": return 5.5f;
  81. case "ethanol": return -114.1f;
  82. default: return 0f;
  83. }
  84. }
  85. // Boiling Point
  86. else
  87. {
  88. switch (compound.ToLower())
  89. {
  90. case "water": return 100.0f;
  91. case "benzene": return 80.1f;
  92. case "ethanol": return 78.3f;
  93. default: return 0f;
  94. }
  95. }
  96. }
  97. public string GetMolecularStructure(string compound)
  98. {
  99. switch (compound.ToLower())
  100. {
  101. case "water": return "H20";
  102. case "benzene": return "C6H6";
  103. case "ethanol": return "C2H5OH";
  104. default: return "";
  105. }
  106. }
  107. public double GetMolecularWeight(string compound)
  108. {
  109. switch (compound.ToLower())
  110. {
  111. case "water": return 18.015;
  112. case "benzene": return 78.1134;
  113. case "ethanol": return 46.0688;
  114. default: return 0d;
  115. }
  116. }
  117. }
  118. }
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.

  1. namespace Adapter.NetOptimized;
  2. using static System.Console;
  3. /// <summary>
  4. /// Adapter Design Pattern
  5. /// </summary>
  6. public class Program
  7. {
  8. public static void Main()
  9. {
  10. // Non-adapted chemical compound
  11. var unknown = new Compound();
  12. unknown.Display();
  13. // Adapted chemical compounds
  14. var water = new RichCompound(Chemical.Water);
  15. water.Display();
  16. var benzene = new RichCompound(Chemical.Benzene);
  17. benzene.Display();
  18. var ethanol = new RichCompound(Chemical.Ethanol);
  19. ethanol.Display();
  20. // Wait for user
  21. ReadKey();
  22. }
  23. }
  24. /// <summary>
  25. /// The 'Target' class
  26. /// </summary>
  27. public class Compound
  28. {
  29. public Chemical Chemical { get; protected set; }
  30. public float BoilingPoint { get; protected set; }
  31. public float MeltingPoint { get; protected set; }
  32. public double MolecularWeight { get; protected set; }
  33. public string? MolecularFormula { get; protected set; }
  34. public virtual void Display()
  35. {
  36. WriteLine("\nCompound: Unknown ------ ");
  37. }
  38. }
  39. /// <summary>
  40. /// The 'Adapter' class
  41. /// </summary>
  42. public class RichCompound : Compound
  43. {
  44. private readonly ChemicalDatabank bank = new();
  45. // Constructor
  46. public RichCompound(Chemical chemical)
  47. {
  48. Chemical = chemical;
  49. }
  50. public override void Display()
  51. {
  52. // Adaptee request methods
  53. BoilingPoint = bank.GetCriticalPoint(Chemical, State.Boiling);
  54. MeltingPoint = bank.GetCriticalPoint(Chemical, State.Melting);
  55. MolecularWeight = bank.GetMolecularWeight(Chemical);
  56. MolecularFormula = bank.GetMolecularStructure(Chemical);
  57. WriteLine($"\nCompound: { Chemical} ------ ");
  58. WriteLine($" Formula: {MolecularFormula}");
  59. WriteLine($" Weight : {MolecularWeight}");
  60. WriteLine($" Melting Pt: {MeltingPoint}");
  61. WriteLine($" Boiling Pt: {BoilingPoint}");
  62. }
  63. }
  64. /// <summary>
  65. /// The 'Adaptee' class
  66. /// </summary>
  67. public class ChemicalDatabank
  68. {
  69. // The databank 'legacy API'
  70. public float GetCriticalPoint(Chemical compound, State point)
  71. {
  72. // Melting Point
  73. if (point == State.Melting)
  74. {
  75. return compound switch
  76. {
  77. Chemical.Water => 0.0f,
  78. Chemical.Benzene => 5.5f,
  79. Chemical.Ethanol => -114.1f,
  80. _ => 0f,
  81. };
  82. }
  83. // Boiling Point
  84. else
  85. {
  86. return compound switch
  87. {
  88. Chemical.Water => 100.0f,
  89. Chemical.Benzene => 80.1f,
  90. Chemical.Ethanol => 78.3f,
  91. _ => 0f,
  92. };
  93. }
  94. }
  95. public string GetMolecularStructure(Chemical compound)
  96. {
  97. return compound switch
  98. {
  99. Chemical.Water => "H20",
  100. Chemical.Benzene => "C6H6",
  101. Chemical.Ethanol => "C2H5OH",
  102. _ => "",
  103. };
  104. }
  105. public double GetMolecularWeight(Chemical compound)
  106. {
  107. return compound switch
  108. {
  109. Chemical.Water => 18.015d,
  110. Chemical.Benzene => 78.1134d,
  111. Chemical.Ethanol => 46.0688d,
  112. _ => 0d
  113. };
  114. }
  115. }
  116. /// <summary>
  117. /// Chemical enumeration
  118. /// </summary>
  119. public enum Chemical
  120. {
  121. Water,
  122. Benzene,
  123. Ethanol
  124. }
  125. /// <summary>
  126. /// State enumeration
  127. /// </summary>
  128. public enum State
  129. {
  130. Boiling,
  131. Melting
  132. }
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.


Guides


vsn 3.2