Take advantage of the flyweight design pattern to reduce memory consumption when working with many similar objects. Credit: thinkstock Design patterns help us solve design problems often encountered in software development and reduce the complexities in our code. The Gang of Four design patterns fall into three categories: creational, structural, and behavioral. The flyweight design pattern falls in the structural category. The flyweight pattern helps reduce memory consumption when working with many similar objects at the same time. This article examines how we can work with the flyweight design pattern in C#. To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here. Create a console application project in Visual Studio First off, let’s create a .NET Core Console Application project in Visual Studio. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new .NET Core Console Application project in Visual Studio. Launch the Visual Studio IDE. Click on “Create new project.” In the “Create new project” window, select “Console App (.NET Core)” from the list of templates displayed. Click Next. In the “Configure your new project” window, specify the name and location for the new project. Click Create. You should now have a new .NET Core console application project ready to go in Visual Studio 2019. We’ll use this project in the subsequent sections of this article. The flyweight design pattern and its usage The flyweight design pattern reduces the amount of memory required to create a number of large objects of the identical type in an application. The flyweight is an object that reduces memory pressure by sharing data with similar objects. Thus a new object is created only if needed, i.e., if no matching object is available. By reducing the memory intake, the flyweight pattern improves performance. A typical use case for the flyweight pattern is when you need to create large objects of the same type. The Gang of Four description: “Use sharing to support large numbers of fine-grained objects efficiently.” A flyweight object can have either of the following states: Intrinsic state — the data is state-independent and is typically stored inside the flyweight object and can be shared Extrinsic state — the data is state-dependent and hence it cannot be shared The participants in the flyweight design pattern include the following: Flyweight — this is typically an interface for the flyweight objects ConcreteFlyweight — this is a class that implements the Flyweight interface FlyweightFactory — this is a factory class used to create concrete objects of the ConcreteFlyweight type Client — this stores references to the flyweight instances Implement Flyweight abstract class and method in C# To implement the flyweight design pattern in C#, let’s start by defining the abstract base class named Flyweight. This class will contain the declaration of an abstract method named Display. The following code snippet illustrates the Flyweight abstract class. public abstract class Flyweight { public abstract void Display(); } The ConcreteFlyweight class extends the Flyweight class and implements the abstract method. The following code listing shows the ConcreteFlyweight class. public class ConcreteFlyweight : Flyweight { private readonly string _key = null; public ConcreteFlyweight(string key) { _key = key; } public override void Display() { Console.WriteLine("The Key is: "+ _key); } } Implement the FlyweightFactory class in C# The FlyweightFactory class creates and stores flyweight instances in an instance of Dictionary. This class contains the GetFlyweight() method that returns a ConcreteFlyweight instance based on a given key. If the instance is present in the Dictionary then it is returned, else a new instance of ConcreteFlyweight is created and returned. The following code listing illustrates the FlyweightFactory class. public class FlyweightFactory { private Dictionary<string, Flyweight> flyweights = new Dictionary<string, Flyweight>(); public Flyweight GetFlyweight(string key) { Flyweight flyweight = null; if (flyweights.ContainsKey(key)) { flyweight = flyweights[key]; } else { flyweight = new ConcreteFlyweight(key); flyweights.Add(key, flyweight); } return flyweight; } } Note that in this example we are using one ConcreteFlyweight class. Multiple instances of this class differ from one another on the value of the key. In practice, you might want to create several concrete classes that extend the Flyweight class. We’ve omitted multiple instances here for simplicity. Implement the Flyweight client in C# Lastly, here is what the client would look like. static void Main(string[] args) { var factory = new FlyweightFactory(); var flyweight = factory.GetFlyweight("A"); flyweight.Display(); Console.Read(); } Flyweight design pattern example in C# Here is the complete program for your reference. public abstract class Flyweight { public abstract void Display(); } public class ConcreteFlyweight : Flyweight { private readonly string _key = null; public ConcreteFlyweight(string key) { _key = key; } public override void Display() { Console.WriteLine("The Key is: "+ _key); } } public class FlyweightFactory { private Dictionary<string, Flyweight> flyweights = new Dictionary<string, Flyweight>(); public Flyweight GetFlyweight(string key) { Flyweight flyweight = null; if (flyweights.ContainsKey(key)) { flyweight = flyweights[key]; } else { flyweight = new ConcreteFlyweight(key); flyweights.Add(key, flyweight); } return flyweight; } } class Program { static void Main(string[] args) { var factory = new FlyweightFactory(); var flyweight = factory.GetFlyweight("A"); flyweight.Display(); Console.Read(); } } When you execute the above program, you should see the following output. IDG Figure 1: The flyweight design pattern in action! You can take advantage of the flyweight design pattern in scenarios where availability of memory is a constraint. However, in practice, the complexities involved in implementing the flyweight design pattern often outweigh the benefits. Hence, the usefulness of the flyweight pattern is limited. In many cases, a better alternative is the Prototype design pattern. Related content feature What is Rust? Safe, fast, and easy software development Unlike most programming languages, Rust doesn't make you choose between speed, safety, and ease of use. Find out how Rust delivers better code with fewer compromises, and a few downsides to consider before learning Rust. By Serdar Yegulalp Nov 20, 2024 11 mins Rust Programming Languages Software Development how-to Kotlin for Java developers: Classes and coroutines Kotlin was designed to bring more flexibility and flow to programming in the JVM. Here's an in-depth look at how Kotlin makes working with classes and objects easier and introduces coroutines to modernize concurrency. By Matthew Tyson Nov 20, 2024 9 mins Java Kotlin Programming Languages analysis Azure AI Foundry tools for changes in AI applications Microsoft’s launch of Azure AI Foundry at Ignite 2024 signals a welcome shift from chatbots to agents and to using AI for business process automation. By Simon Bisson Nov 20, 2024 7 mins Microsoft Azure Generative AI Development Tools news Microsoft unveils imaging APIs for Windows Copilot Runtime Generative AI-backed APIs will allow developers to build image super resolution, image segmentation, object erase, and OCR capabilities into Windows applications. By Paul Krill Nov 19, 2024 2 mins Generative AI APIs Development Libraries and Frameworks Resources Videos