Trusted answers to developer questions

Junior dev learning: Wrapper classes

Free System Design Interview Course

Many candidates are rejected or down-leveled due to poor performance in their System Design Interview. Stand out in System Design Interviews and get hired in 2024 with this popular free course.

Overview

  • What is a wrapper class?
  • Bare-bones wrapper example
  • Real-world wrapper example

What is a wrapper class?

The main idea of a wrapper class is to mimic the functionality of another class while hiding the mimicked class’s complexity. A wrapper is a class that takes an instance of another class (the class being wrapped) as an argument in its constructor, which makes it a primitive class of the one being wrapped. This means the wrapper has access to the wrapped class’ functionality and is able to expose the desired features or build utility components on top of this wrapped class. In this post, we’ll be using C# for demonstration, but this pattern is viable in all object-oriented languages.

Bare-bones wrapper example

Okay, we understand that a wrapper should “wrap” another class, but what does that structure actually look like?

Well, it’s pretty simple, the wrapper will contain a private class variable(the type of the wrapped class). The wrapper’s constructor will take an instance of the wrapped class, and set the private class variable to this instance. This allows us to add to the wrapped class without actually modifying it.

In this example, there’s a class, CoolPerson, that has FirstName and LastName instance variables. This CoolPerson class has two methods: one to say its first name and another to say its last name. What if we wanted a method that will say both names at the same time? This is where the CoolPersonWrapper class comes into play. This CoolPersonWrapper will add to CoolPerson with a FullName class variable and a method that says the full name.

In the code block below, we see the main program instantiating a CoolPerson, and wrapping that CoolPerson within a CoolPersonWrapper. The wrapper then goes ahead and says its full name with a single method.

namespace WrapperExample
{
class Program
{
static void Main(string[] args)
{
CoolPerson someCoolPerson = new CoolPerson("Cool", "Dude");
CoolPersonWrapper someCoolPersonWrapper = new CoolPersonWrapper(someCoolPerson);
someCoolPersonWrapper.SayFullName();
Console.ReadKey();
}
}
...
}

In the following block, we see the definition of CoolPerson, which has two separate methods for saying its first and last names.

...
public class CoolPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public CoolPerson(string firstName, string lastName)
{
this.FirstName = firstName;
this.LastName = lastName;
}
public void SayFirstName()
{
Console.WriteLine("My first name is " + this.FirstName);
}
public void SayLastName()
{
Console.WriteLine("My last name is " + this.LastName);
}
}
...

In the next block, we see that CoolPersonWrapper takes a CoolPerson in the constructor and uses this CoolPerson to set the FullName variable, which is issued in the single SayFullName() method that is the functionality we’re adding on top of the wrapped class. We can also see that SayFirstName() and SayLastName() are both methods from the wrapped class that we are exposing with public methods.

namespace WrapperExample
{
class Program
{
static void Main(string[] args)
{
CoolPerson someCoolPerson = new CoolPerson("Cool", "Dude");
CoolPersonWrapper someCoolPersonWrapper = new CoolPersonWrapper(someCoolPerson);
someCoolPersonWrapper.SayFullName();
}
}
public class CoolPerson
{
public string FirstName { get; set; }
public string LastName { get; set; }
public CoolPerson(string firstName, string lastName)
{
this.FirstName = firstName;
this.LastName = lastName;
}
public void SayFirstName()
{
System.Console.WriteLine("My first name is " + this.FirstName);
}
public void SayLastName()
{
System.Console.WriteLine("My last name is " + this.LastName);
}
}
public class CoolPersonWrapper
{
private CoolPerson CoolPerson { get; set; }
private string FullName { get; set; }
public CoolPersonWrapper(CoolPerson coolPerson)
{
this.CoolPerson = coolPerson;
this.FullName = coolPerson.FirstName + " " + coolPerson.LastName;
}
public void SayFullName()
{
System.Console.WriteLine("My name is " + this.FullName);
}
public void SayFirstName()
{
this.CoolPerson.SayFirstName();
}
public void SayLastName()
{
this.CoolPerson.SayLastName();
}
}
}

Real-world wrapper example

Why didn’t we just add the SayFullName() method to the CoolPerson class? Well, that would have worked too, but what if the CoolPerson class was part of a third-party library that we did not have access to modify? Changing the functionality of third-party classes is where wrapping is needed.

As an example, we can discuss the case of disposing COM objects. When developing an Excel or Word add-in, developers will be working with COM objects that need some manual memory management. The developer is required to release these objects using a Marshal.ReleaseComObject() method call passing the COM object. On top of that, the code block that uses the COM object must be wrapped in a try/finally and the release method must be called in the finally block. This requires the developer to also declare the COM object outside of the try/finally, which can get ugly. Here is an example:

public void SetApplication()
{
WordInterop.Application application = null; // COM Object
try
{
application = new WordInterop.Application();
}
finally
{
if (application != null)
{
application.Quit();
Marshal.ReleaseComObject(application);
}
}
}

Imagine what it starts to look like when more COM objects are added! What can we do to make this cleaner? Well, we know that C# has an IDisposable object interface that allows us to use a using block for objects that implement this interface, and that it will dispose of the object correctly when the block is finished. We can use a wrapper class to do this!

What we do is wrap WordInterop.Application in new class WordApplicationWrapper. In this new wrapper class, we will also implement IDisposable. To satisfy the requirements of IDisposble, we will implement a method that is called when the wrapped object is being released at the end of the using block. This method is where we’re able to call Marshal.ReleaseComObject(). This allows us to use a using block instead of the try/catch with the declaration outside:

public void SetApplication()
{
using (var application = new WordApplicationWrapper(new WordInterop.Application()))
{
application.Quit();
// When we reach the end of the using block, the wrapped object
// will be disposed of.
}
}

Much cleaner; the wrapper served us well. 😃

You can check out my GitHub tutorials here.

RELATED TAGS

c#
wrapper
Did you find this helpful?