Flutter Design Patterns: 14 — Prototype

An overview of the Prototype design pattern and its implementation in Dart and Flutter

Mangirdas Kazlauskas
Jan 23 · 7 min read

Previously in the series, I have analyzed one of the behavioural design patterns — Memento. This time I would like to represent a relatively simple design pattern comparing to the other patterns in the series which belongs to the category of creational design patterns — the Prototype.


Table of Contents

  • Analysis
  • Implementation
  • Other articles in this series
  • Your contribution

What is the Prototype design pattern?

How cloning works (source)

The Prototype is a creational design pattern, which intention in the GoF book is described like this:

Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

That is, instead of creating a new object, some prototype is used which allows creating new objects by copying from this prototype. This could be useful when you want to copy an object which has a complicated state, which means that just initialising a new object will not be enough, you also need to reach that particular state of the object to consider it as a valid copy. In simple words, when your code only wants a copy of a specific object with the exact same state and you do not care about the details on how this state was reached — well, your code should just provide a way to copy (clone) it.

In general, an inflexible way is to create an object directly within the class that requires (uses) the object. The Prototype design pattern enables the run-time flexibility since a class can be configured with different Prototype objects, which are copied to create new objects, and even more, Prototype objects can be added and removed dynami­cally at run-time.

Let’s move to the analysis and implementation parts to understand and learn the details about this pattern and how to implement it!


Analysis

Structure of the Prototype design pattern (source)
  • Prototype — declares an interface for cloning itself. Usually, it is a single clone method, but there could be other methods declared/defined if needed;
  • ConcretePrototype — implements an operation for cloning itself. In addition to copying the original object’s data to the clone, this method may also handle some edge cases of the cloning process related to cloning linked objects, untangling recursive dependencies, etc.;
  • SubclassPrototype — has the same purpose as the ConcretePrototype, but could also extend the base class by defining additional properties, behaviour, etc.;
  • Client — creates a new object by asking a prototype to clone itself.

Applicability

Also, the pattern could be used when you want to reduce the number of subclasses that only differ in the way they initialize their respective objects. Instead of instantiating a subclass that matches some configuration, the client can simply look for an appropriate prototype and clone it.

Finally, the pattern is quite useful when you have a set of pre-built objects that are ready to be copied. These objects could be stored inside some kind of prototype registry from which you can access the frequently-used prototypes. In this way, you can instantiate a dynamically loaded class and use it inside your code.


Implementation

This time, the implementation part of the design pattern is very simple and straightforward (but that could be also a good sign, right?). Let’s say there are multiple shapes in your application which should be copied at run-time and provided to the UI. Of course, it is possible to instantiate a specific shape by checking all the properties and using them to just simply create another object. However, different shapes contain different properties, they are of a different type, hence the logic just to copy a specific shape could lead to a cumbersome mess in the application code base which you probably want to avoid.

Wouldn’t it be nice to have a unified way to copy any shape in your application without even considering any details about it in your client code? Well, we have just analysed the Prototype design pattern, maybe give it a try?

Class diagram

Class Diagram — Implementation of the Prototype design pattern

Shape is an abstract class which is used as a base class for all the specific shapes. The class contains a color property and defines several abstract methods:

  • clone() — an abstract method to clone (copy) the specific shape;
  • randomiseProperties() — an abstract method to randomise property values of the shape;
  • render() — an abstract method to render the shape. The method is used in UI.

Circle and Rectangle are concrete shape classes which extend the abstract class Shape and implement its abstract methods.

PrototypeExample initializes and contains several Shape objects. These objects are rendered in the UI using the render() method. Also, specific shape objects could be copied using clone() and their properties could be randomised using randomiseProperties() methods respectively.

Shape

  • Shape() — a basic constructor to create a shape object with the provided colour value;
  • Shape.clone() — a named constructor to create a shape object as a copy of the provided Shape value.

Shapes

Rectangle — a specific class which defines a shape of a rectangle. The class defines height and width properties, extends the Shape class and implements its abstract methods clone(), randomiseProperties() and render().

Example

PrototypeExample contains a couple of Shape objects — Circle and Rectangle. By pressing the Randomise properties button, the values of shape’s properties are randomised (the randomiseProperties() method is called on the shape). Also, if the Clone button is pressed, the clone() method is called on the shape and a copy of that particular shape is crated with the exact same values of all the properties.

The PrototypeExample does not care about the specific type of shape object as long as it extends the Shape abstract class and implements all of its abstract methods. As a result, the clone() method could be called on any shape, all of its properties are copied even though these are different on different shapes e.g. the circle has only the radius property which is specific for that particular shape, while the rectangle has two different properties — height and width.

As you can see in the example, it does not matter of which type the specific shape is. As long as it extends the prototype base class defining the clone() method, the shape object could be copied at any time and used across your code — whether it is your business logic or UI, it is irrelevant.

All of the code changes for the Prototype design pattern and its example implementation could be found here.



Your contribution

Flutter Community

Articles and Stories from the Flutter Community

Mangirdas Kazlauskas

Written by

Software Engineer | Flutter Enthusiast https://www.linkedin.com/in/mangirdas-kazlauskas/

Flutter Community

Articles and Stories from the Flutter Community

More From Medium

More from Flutter Community

More from Flutter Community

More from Flutter Community

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade