<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mangirdas Kazlauskas 🚀</title>
    <description>The latest articles on DEV Community by Mangirdas Kazlauskas 🚀 (@mkobuolys).</description>
    <link>https://dev.to/mkobuolys</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F553563%2Ffb317a5b-86ae-4f13-8319-a7c55cbeba97.jpg</url>
      <title>DEV Community: Mangirdas Kazlauskas 🚀</title>
      <link>https://dev.to/mkobuolys</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mkobuolys"/>
    <language>en</language>
    <item>
      <title>23 - Observer</title>
      <dc:creator>Mangirdas Kazlauskas 🚀</dc:creator>
      <pubDate>Mon, 21 Jun 2021 10:23:29 +0000</pubDate>
      <link>https://dev.to/mkobuolys/23-observer-1c54</link>
      <guid>https://dev.to/mkobuolys/23-observer-1c54</guid>
      <description>&lt;p&gt;In the last article, I have analysed a behavioural design pattern that reduces dependencies between a set of interacting objects by decoupling the interaction logic from the objects and moving it to a dedicated controller — Mediator. In this article, I would like to analyse and implement another behavioural design pattern that lets you define a publish-subscribe mechanism to notify multiple objects about any events that happen to the object they’re subscribed to — it is Observer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is the Observer design pattern?&lt;/li&gt;
&lt;li&gt;Analysis&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Your Contribution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the Observer design pattern?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6d2efifmnas8vzuvppqz.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6d2efifmnas8vzuvppqz.jpeg" alt="Neale Donald Walsch Quote About The Observer Effect"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observer&lt;/strong&gt;, also known as &lt;strong&gt;Dependents&lt;/strong&gt; or &lt;strong&gt;Publish-Subscribe&lt;/strong&gt;, belongs to the category of behavioural design patterns. The intention of this design pattern is described in the &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns" rel="noopener noreferrer"&gt;GoF book&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Spoiler alert&lt;/strong&gt;: if you have ever heard about reactive programming or even used the related frameworks/libraries/tools such as &lt;a href="http://reactivex.io/" rel="noopener noreferrer"&gt;ReactiveX&lt;/a&gt;, &lt;a href="https://pub.dev/packages/rxdart" rel="noopener noreferrer"&gt;RxDart&lt;/a&gt; or just basic streams in Dart, this design pattern won’t be a game-changer to you. But it is still worth knowing how reactive programming ideas are implemented in the OOP context from the ground up, though.&lt;/p&gt;

&lt;p&gt;The motivation for this design pattern comes from the problem of having a collection of tightly coupled objects in the system where changes for one object should trigger changes in the others (one-to-many relationship). An inflexible way to implement this is to define an object that implements updating the state of other dependent ones. Such object becomes hard to implement, maintain, test and reuse because of the dependency chaos.&lt;/p&gt;

&lt;p&gt;A better way to approach this is to implement a publish-subscribe mechanism that sends the update events to dependent objects so they could implement and maintain the update logic on their own. To achieve this, the Observer design pattern introduces two roles: &lt;strong&gt;Subject&lt;/strong&gt; and &lt;strong&gt;Observer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The subject is the publisher of notifications that also defines a way for the observers to subscribe/unsubscribe from those notifications. A subject may have any number of dependent observers — the same idea of maintaining a one-to-many relationship just in a more flexible way. When a subject changes state, all registered observers are notified and updated automatically. This way the subject could trigger an update on dependent objects without even knowing who its observers are — this enables loose coupling between subject and observers.&lt;/p&gt;

&lt;p&gt;Let’s move to the analysis and implementation parts to understand and learn the details about this pattern and how to implement it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;The general structure of the Observer design pattern looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hzwpgbxft8milgca6c9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hzwpgbxft8milgca6c9.png" alt="Observer Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Publisher (Subject)&lt;/em&gt; — provides an interface for attaching and detaching &lt;em&gt;Subscriber (Observer)&lt;/em&gt; objects, contains a list of observers;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;(Optional) Concrete Publishers&lt;/em&gt; — stores state of interest for &lt;em&gt;Concrete Subscribers&lt;/em&gt; and sends a notification to its observers when the state changes. This class is optional when only a single type of &lt;em&gt;Publisher&lt;/em&gt; is needed. In such case, the state and notification logic is handled by the &lt;em&gt;Publisher&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Subscriber (Observer)&lt;/em&gt; — declares the notification interface for objects that should be notified of changes in a &lt;em&gt;Subject&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Concrete Subscribers&lt;/em&gt; — implements the &lt;em&gt;Subscriber (Observer)&lt;/em&gt; interface to keep its state consistent with the subject’s state;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Client&lt;/em&gt; — creates &lt;em&gt;Subject&lt;/em&gt; and &lt;em&gt;Observer&lt;/em&gt; objects, attaches observers to subject updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Observer vs Mediator
&lt;/h3&gt;

&lt;p&gt;If you have read the previous article in the series or are familiar with the Mediator design pattern you could feel some kind of &lt;em&gt;déjà vu&lt;/em&gt; — isn’t the Observer design pattern the same thing? Let me explain.&lt;/p&gt;

&lt;p&gt;The primary goal of the Mediator design pattern is to replace many-to-many relationships between objects with one-to-many relationship by using the dedicated mediator object that handles the communication part. Observer allows establishing a dynamic one-way connection between objects, where some objects act as subordinates of others.&lt;/p&gt;

&lt;p&gt;If you have only one mediator that allows subscriptions to its state, this implementation is based on the Observer design pattern but the Mediator design pattern could be also used only as a part of the publish-subscribe communication. Now, if we have multiple publishers and multiple subscribers (which could be publishers as well), there won’t be any mediator object only a distributed set of observers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Applicability
&lt;/h3&gt;

&lt;p&gt;The Observer design pattern should be used when a change to one object requires changing others, but you don’t know how many objects need to be changed and how. The pattern allows subscribing to such object events and changing the dependent object’s state accordingly.&lt;/p&gt;

&lt;p&gt;Also, this pattern should be used when some objects must observe others, but only for a limited time. The subscription mechanism allows dependent objects to listen to the update events on demand and change this behaviour at run-time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjuaohboq9ba03j4rbud.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjuaohboq9ba03j4rbud.gif" alt="Bring It On"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the implementation part, we will use the Observer design pattern to implement a stock market prototype.&lt;/p&gt;

&lt;p&gt;In the stock market, there are hundreds and thousands of different stocks. Of course, not all of them are relevant to you, so you would like to subscribe and track only the specific ones.&lt;/p&gt;

&lt;p&gt;The prototype allows subscribing to 3 different stocks — GameStop (GME), Alphabet Inc. a.k.a. Google (GOOGL) and Tesla Motors (TSLA). Also, there are two different types of subscriptions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Default stock subscription — notifies about every subscribed stock change.&lt;/li&gt;
&lt;li&gt;Growing stock subscription — notifies only about the growing stock changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Such stocks’ tracker could be easily implemented by using the Observer design pattern. Of course, the prototype only supports 3 different stock types, but new stock tickers or even new subscription types could be easily added later on without affecting the existing code. Let’s check the class diagram first and then implement the pattern!&lt;/p&gt;

&lt;h3&gt;
  
  
  Class diagram
&lt;/h3&gt;

&lt;p&gt;The class diagram below shows the implementation of the Observer design pattern:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dgva29llgzxlu3ocrs5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dgva29llgzxlu3ocrs5.png" alt="Observer Implementation Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;StockTicker&lt;/em&gt; is an abstract class that is used as a base class for all the specific stock ticker classes. The class contains &lt;em&gt;title&lt;/em&gt;, &lt;em&gt;stockTimer&lt;/em&gt; and &lt;em&gt;stock&lt;/em&gt; properties, &lt;em&gt;subscribers&lt;/em&gt; list, provides several methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;subscribe()&lt;/em&gt; — subscribes to the stock ticker;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;unsubscribe()&lt;/em&gt; — unsubscribes from the stock ticker;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;notifySubscribers()&lt;/em&gt; — notifies subscribers about the stock change;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;setStock()&lt;/em&gt; — sets stock value;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;stopTicker()&lt;/em&gt; — stops ticker emitting stock events.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;GameStopStockTicker&lt;/em&gt;, &lt;em&gt;GoogleStockTicker&lt;/em&gt; and &lt;em&gt;TeslaStockTicker&lt;/em&gt; are concrete stock ticker classes that extend the abstract class &lt;em&gt;StockTicker&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Stock&lt;/em&gt; class contains &lt;em&gt;symbol&lt;/em&gt;, &lt;em&gt;changeDirection&lt;/em&gt;, &lt;em&gt;price&lt;/em&gt; and &lt;em&gt;changeAmount&lt;/em&gt; properties to store info about the stock.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;StockTickerSymbol&lt;/em&gt; is an enumerator class defining supported stock ticker symbols — GME, GOOGL and TSLA.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;StockChangeDirection&lt;/em&gt; is an enumerator class defining stock change directions — growing and falling.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;StockSubscriber&lt;/em&gt; is an abstract class that is used as a base class for all the specific stock subscriber classes. The class contains &lt;em&gt;title&lt;/em&gt;, &lt;em&gt;id&lt;/em&gt; and &lt;em&gt;stockStreamController&lt;/em&gt; properties, &lt;em&gt;stockStream&lt;/em&gt; getter and defines the abstract &lt;em&gt;update()&lt;/em&gt; method to update subscriber state.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;DefaultStockSubscriber&lt;/em&gt; and &lt;em&gt;GrowingStockSubscriber&lt;/em&gt; are concrete stock subscriber classes that extend the abstract class &lt;em&gt;StockSubscriber&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  StockTicker
&lt;/h3&gt;

&lt;p&gt;An abstract class implementing base methods for all the specific stock ticker classes. Property &lt;em&gt;title&lt;/em&gt; is used in the UI for stock ticker selection, &lt;em&gt;stockTimer&lt;/em&gt; periodically emits a new stock value that is stored in the &lt;em&gt;stock&lt;/em&gt; property by using the &lt;em&gt;setStock()&lt;/em&gt; method. The class also stores a list of stock subscribers that can subscribe to the stock ticker and unsubscribe from it by using the &lt;em&gt;subscribe()&lt;/em&gt; and &lt;em&gt;unsubscribe()&lt;/em&gt; respectively. Stock ticker subscribers are notified about the value change by calling the &lt;em&gt;notifySubscribers()&lt;/em&gt; method. The stock timer could be stopped by calling the &lt;em&gt;stopTicker()&lt;/em&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmn29r9r0zri2h4orarjo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmn29r9r0zri2h4orarjo.png" alt="stock_ticker.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Concrete stock ticker classes
&lt;/h3&gt;

&lt;p&gt;All of the specific stock ticker classes extend the abstract &lt;em&gt;StockTicker&lt;/em&gt; class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;GameStopStockTicker&lt;/em&gt; — a stock ticker of the GameStop stocks that emits a new stock event every 2 seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fblv3nc2h1fguiqgkp34z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fblv3nc2h1fguiqgkp34z.png" alt="gamestop_stock_ticker.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;TeslaStockTicker&lt;/em&gt; — a stock ticker of the Tesla stocks that emits a new stock event every 3 seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz12mpq12rnrmec9jfpsg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz12mpq12rnrmec9jfpsg.png" alt="tesla_stock_ticker.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;GoogleStockTicker&lt;/em&gt; — a stock ticker of the Google stocks that emits a new stock event every 5 seconds.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbd3s7td1wgwtz4tcgqy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbd3s7td1wgwtz4tcgqy.png" alt="google_stock_ticker.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Stock
&lt;/h3&gt;

&lt;p&gt;A simple class to store information about the stock. Stock class contains data about the stocker ticker symbol, stock change direction, current price and the change amount.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6zprqkmp64j5yka90xq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs6zprqkmp64j5yka90xq.png" alt="stock.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  StockTickerSymbol
&lt;/h3&gt;

&lt;p&gt;A special kind of class — &lt;em&gt;enumeration&lt;/em&gt; — to define supported stock ticker symbols. Also, there is a &lt;em&gt;StockTickerSymbolExtension&lt;/em&gt; defined where the &lt;em&gt;toShortString()&lt;/em&gt; method returns a short version of the enumeration string value.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ambr8huzkj4ddgmjq9p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ambr8huzkj4ddgmjq9p.png" alt="stock_ticker_symbol.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  StockChangeDirection
&lt;/h3&gt;

&lt;p&gt;A special kind of class — &lt;em&gt;enumeration&lt;/em&gt; — to define stock change directions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyilwp5t3w1x178jw3zfx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyilwp5t3w1x178jw3zfx.png" alt="stock_change_direction.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  StockSubscriber
&lt;/h3&gt;

&lt;p&gt;An abstract class containing base properties for all the specific stock ticker classes. Property &lt;em&gt;title&lt;/em&gt; is used in the UI for stock subscriber selection, &lt;em&gt;id&lt;/em&gt; uniquely identifies the subscriber. Updated stock values are added to the &lt;em&gt;stockStreamController&lt;/em&gt; and emitted via the &lt;em&gt;stockStream&lt;/em&gt;. Abstract method &lt;em&gt;update()&lt;/em&gt; is defined and must be implemented by all the concrete stock subscriber classes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxqx5sn0xkqw934x0q3m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdxqx5sn0xkqw934x0q3m.png" alt="stock_subscriber.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Concrete stock subscriber classes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;DefaultStockSubscriber&lt;/em&gt; — a default stock subscriber that emits every stock change on update.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8h7kqatklsymmkhnxu5e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8h7kqatklsymmkhnxu5e.png" alt="default_stock_subscriber.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;GrowingStockSubscriber&lt;/em&gt; — a growing stock subscriber that emits only growing stock changes on update.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpugeqvb98zk6b6tbb2a8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpugeqvb98zk6b6tbb2a8.png" alt="growing_stock_subscriber.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;First of all, a markdown file is prepared and provided as a pattern’s description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foaaua58cxjt8t64lhv3v.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foaaua58cxjt8t64lhv3v.gif" alt="Observer Markdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ObserverExample&lt;/em&gt; contains a list of &lt;em&gt;StockSubscriber&lt;/em&gt; as well as a list of &lt;em&gt;StockTickerModel&lt;/em&gt; objects (specific &lt;em&gt;StockTicker&lt;/em&gt; class with a flag of whether the user is subscribed to the stock ticker or not).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnblt9l6t063g84ywtn9g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnblt9l6t063g84ywtn9g.png" alt="observer_example.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A specific subscriber class could be easily changed by using the &lt;em&gt;StockSubscriberSelection&lt;/em&gt; widget. Also, &lt;em&gt;StockTickerSelection&lt;/em&gt; allows easily subscribe/unsubscribe from the specific stock ticker at run-time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo69l10vy7hn2cay0c7ue.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo69l10vy7hn2cay0c7ue.gif" alt="Observer Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the example, the subscription type could be easily changed at run-time, you could start and stop tracking of the specific stocks at any point as well.&lt;/p&gt;

&lt;p&gt;All of the code changes for the Observer design pattern and its example implementation could be found &lt;a href="https://github.com/mkobuolys/flutter-design-patterns/pull/29" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Contribution
&lt;/h2&gt;

&lt;p&gt;💖 or 🦄 this article to show your support and motivate me to write better!&lt;br&gt;
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.&lt;br&gt;
📢 Share this article with your friends, colleagues on social media.&lt;br&gt;
➕ Follow me on dev.to or any other social media platform.&lt;br&gt;
⭐ Star the &lt;a href="https://github.com/mkobuolys/flutter-design-patterns" rel="noopener noreferrer"&gt;Github&lt;/a&gt; repository.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>oop</category>
      <category>programming</category>
    </item>
    <item>
      <title>22 - Mediator</title>
      <dc:creator>Mangirdas Kazlauskas 🚀</dc:creator>
      <pubDate>Mon, 14 Jun 2021 06:27:49 +0000</pubDate>
      <link>https://dev.to/mkobuolys/22-mediator-4ell</link>
      <guid>https://dev.to/mkobuolys/22-mediator-4ell</guid>
      <description>&lt;p&gt;Previously in the series, I have analysed a behavioural design pattern that separates algorithms from the objects they operate on — Visitor. This time I would like to represent once another behavioural design pattern that lets you reduce dependencies between a set of interacting objects by decoupling the interaction logic from the objects and moving it to a dedicated controller — it is the Mediator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is the Mediator design pattern?&lt;/li&gt;
&lt;li&gt;Analysis&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Your Contribution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the Mediator design pattern?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffemw0y595x1olix0iww2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffemw0y595x1olix0iww2.gif" alt="The Importance Of A Mediator"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mediator&lt;/strong&gt;, also known as &lt;strong&gt;Intermediary&lt;/strong&gt; or &lt;strong&gt;Controller&lt;/strong&gt;, is a behavioural design pattern, which intention in the &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns" rel="noopener noreferrer"&gt;GoF book&lt;/a&gt; is described like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;TL;DR: the main target of the Mediator design pattern is to move from the communicating object dependencies chaos provided on the left to the decoupled one provided on the right:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fokm132uiy7cwzd5bzrss.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fokm132uiy7cwzd5bzrss.png" alt="Object Dependencies Map"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Mediator design pattern context, communicating objects are called &lt;strong&gt;colleagues&lt;/strong&gt; while the object that controls and coordinates the interaction is called *&lt;em&gt;drums rolls&lt;/em&gt;* the &lt;strong&gt;mediator&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The mediator is like a telephone exchange that keeps references to interacting objects and maintains all the required logic to “connect” colleague A with colleague B. As a result, colleague objects have no explicit knowledge of each other, they only refer to their mediator — in the OOP world, we could say that objects are loosely coupled. This allows reusing individual colleague objects independently since they have fewer dependencies on the other objects.&lt;/p&gt;

&lt;p&gt;Another upside of the Mediator design pattern is that it simplifies and abstracts the way of how objects interact. First of all, the mediator replaces many-to-many (N:M) relationships with one-to-many (1:N) interactions between the mediator and its colleagues. In general, 1:N relationships are just easier to understand and maintain. Besides, the mediator object abstracts the interaction logic — colleagues should be aware only of the communication act but not of any details on how it is implemented. This abstraction enables adding new mediators without changing the actual components. Also, having the whole communication logic in a single place helps a lot when you need to adjust or maintain it.&lt;/p&gt;

&lt;p&gt;Let’s just jump right in by analysing the Mediator design pattern and its implementation in more detail!&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;The general structure of the Mediator design pattern looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsxbdw39vwj52qa2st3s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsxbdw39vwj52qa2st3s.png" alt="Mediator Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Mediator&lt;/em&gt; — defines an interface for communicating with components;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;ConcreteMediator&lt;/em&gt; — encapsulates relations between components by containing references to them;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;(Optional) Abstract Component&lt;/em&gt; or &lt;em&gt;Component Interface&lt;/em&gt; — similar communicating components could implement the same interface or extend the same base class. In this case, &lt;em&gt;ConcreteMediator&lt;/em&gt; could store a list of components extending/implementing this class instead of keeping multiple references as separate properties;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Concrete component&lt;/em&gt; or &lt;em&gt;Colleague&lt;/em&gt; — contains a reference to a mediator. Each colleague communicates with its mediator whenever it would have otherwise communicated with another colleague (component).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Applicability
&lt;/h3&gt;

&lt;p&gt;The Mediator design pattern should be used when instead of having tightly coupled classes you want to have loose-coupled ones, because:&lt;/p&gt;

&lt;p&gt;a) You want to reuse the component elsewhere. When a component is too dependent on other classes, it’s hard to reuse it as a stand-alone object.&lt;br&gt;
b) You want to make changes in some of the classes, but they affect other dependencies. By using the Mediator design pattern, the relationship logic between objects is extracted to a separate class, hence the changes could be implemented without directly affecting the rest of the components.&lt;/p&gt;

&lt;p&gt;Also, you should consider using the Mediator design pattern when there is a need to add communicating objects at run-time. Since the mediator class takes care of the communication logic and all the dependencies between objects, it’s possible to add or remove those dependencies later from the code just like adding a new user to the chat room.&lt;/p&gt;

&lt;p&gt;However, by moving all the communication logic to a dedicated class there is a risk to end up having a &lt;a href="https://en.wikipedia.org/wiki/God_object" rel="noopener noreferrer"&gt;God Object&lt;/a&gt;. To avoid this, make sure that the mediator class is only responsible for the communication part. If you notice any other calculations, data manipulations or extraneous operations (Eminem would be proud of this line, I think) they should be extracted to a dedicated class.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fll5rm4927v5w35u0bb1m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fll5rm4927v5w35u0bb1m.gif" alt="Let's Start Coding"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will use the Mediator design pattern to implement a notification hub for the engineering team.&lt;/p&gt;

&lt;p&gt;Let’s say that we want a solution to send notifications to other team members. Inside the team, there are 3 main roles: Admin a.k.a. God, Developer and tester (QA engineer). There are times when the admin wants to send notifications to the whole team or members of a specific role. Also, any other team member should be able to send a quick note to the whole team, too.&lt;/p&gt;

&lt;p&gt;If you think of this problem, you could quickly notice a many-to-many relationship between team members — every engineer should be aware of the others just to send the notification. For this reason, we will implement a centralised way to send notifications — a notification hub. You could think of it as a chat room — every team member joins the hub and later they use it to send notifications by simply calling a &lt;em&gt;send&lt;/em&gt; method. Then, the hub distributes the message to the others — to all of them or by specific role.&lt;/p&gt;

&lt;p&gt;By using this solution, team members should not be aware of the others, they are completely decoupled. Also, in the case of a new team member, it is enough to add him/her to the notification hub and you could be sure that all the notifications would be delivered.&lt;/p&gt;

&lt;p&gt;Sounds too good to be true? Watch and learn!&lt;/p&gt;

&lt;h3&gt;
  
  
  Class diagram
&lt;/h3&gt;

&lt;p&gt;The class diagram below shows the implementation of the Mediator design pattern:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frszynutfh3e2tgk7tthg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frszynutfh3e2tgk7tthg.png" alt="Mediator Implementation Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;TeamMember&lt;/em&gt; is an abstract class that is used as a base class for all the specific team member classes. The class contains &lt;em&gt;name&lt;/em&gt;, &lt;em&gt;lastNotification&lt;/em&gt; and &lt;em&gt;notificationHub&lt;/em&gt; properties, provides several methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;receive()&lt;/em&gt; — receives the notification from the notification hub;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;send()&lt;/em&gt; — sends a notification;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;sendTo()&lt;/em&gt; — sends a notification to specific team members.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Admin&lt;/em&gt;, &lt;em&gt;Developer&lt;/em&gt; and &lt;em&gt;Tester&lt;/em&gt; are concrete team member classes that extend the abstract class &lt;em&gt;TeamMember&lt;/em&gt; as well as override the default &lt;em&gt;toString()&lt;/em&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NotificationHub&lt;/em&gt; is an abstract class that is used as a base class for all the specific notification hubs and defines several abstract methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;getTeamMembers()&lt;/em&gt; — returns a list of team members of the hub;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;register()&lt;/em&gt; — registers a team member to the hub;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;send()&lt;/em&gt; — sends a notification to registered team members;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;sendTo()&lt;/em&gt; — sends a notification to specific registered team members.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;TeamNotificationHub&lt;/em&gt; is a concrete notification hub that extends the abstract class &lt;em&gt;NotificationHub&lt;/em&gt; and implements its abstract methods. Also, this class contain a list of registered team members — &lt;em&gt;teamMembers&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;MediatorExample&lt;/em&gt; initialises and contains a notification hub property to send and receive notifications, register team members to the hub.&lt;/p&gt;

&lt;h3&gt;
  
  
  TeamMember
&lt;/h3&gt;

&lt;p&gt;An abstract class implementing base methods for all the specific team member classes. Method &lt;em&gt;receive()&lt;/em&gt; sets the &lt;em&gt;lastNotification&lt;/em&gt; value, &lt;em&gt;send()&lt;/em&gt; and &lt;em&gt;sendTo()&lt;/em&gt; methods send notification by using the corresponding &lt;em&gt;notificationHub&lt;/em&gt; methods.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ecn3ytr1t25ko5whl7f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ecn3ytr1t25ko5whl7f.png" alt="team_member.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Concrete team member classes
&lt;/h3&gt;

&lt;p&gt;All of the specific team member classes extend the &lt;em&gt;TeamMember&lt;/em&gt; and override the default &lt;em&gt;toString()&lt;/em&gt; method.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Admin&lt;/em&gt; — a team member class representing the admin role.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93lyn8btuil7ou985vta.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F93lyn8btuil7ou985vta.png" alt="admin.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Developer&lt;/em&gt; — a team member class representing the developer role.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cu1gz80nlts1l37x4ia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4cu1gz80nlts1l37x4ia.png" alt="developer.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Tester&lt;/em&gt; — a team member class representing the tester (QA) role.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9fq2kor72br8xvoczdr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9fq2kor72br8xvoczdr.png" alt="tester.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  NotificationHub
&lt;/h3&gt;

&lt;p&gt;An abstract class that defines abstract methods to be implemented by specific notification hub classes. Method &lt;em&gt;getTeamMembers()&lt;/em&gt; returns a list of registered team members to the hub, &lt;em&gt;register()&lt;/em&gt; registers a new member to the hub. Method &lt;em&gt;send()&lt;/em&gt; sends the notification to all the registered team members to the hub (excluding sender) while &lt;em&gt;sendTo()&lt;/em&gt; sends the notification to team members of a specific type (excluding sender).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyicpsy1t4t4f8or2806n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyicpsy1t4t4f8or2806n.png" alt="notification_hub.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  TeamNotificationHub
&lt;/h3&gt;

&lt;p&gt;A specific notification hub implementing abstract &lt;em&gt;NotificationHub&lt;/em&gt; methods. The class also contains private &lt;em&gt;teamMembers&lt;/em&gt; property — a list of registered team members to the hub.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhn3hqvf4s2h6br3k2ibd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhn3hqvf4s2h6br3k2ibd.png" alt="team_notification_hub.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;First of all, a markdown file is prepared and provided as a pattern’s description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjrv040a5azyvttf4sztd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjrv040a5azyvttf4sztd.gif" alt="Mediator Markdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;MediatorExample&lt;/em&gt; widget initialises the &lt;em&gt;TeamNotificationHub&lt;/em&gt; and later uses it to send notifications between team members.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdt329ml5jy5n6oi20ww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkdt329ml5jy5n6oi20ww.png" alt="mediator_example.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specific team members do not contain any reference about the others, they are completely decoupled. For communication, the notification hub is used that handles all the necessary logic to send and receive notifications from the team.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1f5ysq7i0uuys1d16qn0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1f5ysq7i0uuys1d16qn0.gif" alt="Mediator Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the example, you could send notifications from different team members, add new members later to the hub so they will be notified, too.&lt;/p&gt;

&lt;p&gt;All of the code changes for the Mediator design pattern and its example implementation could be found &lt;a href="https://github.com/mkobuolys/flutter-design-patterns/pull/28" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Contribution
&lt;/h2&gt;

&lt;p&gt;💖 or 🦄 this article to show your support and motivate me to write better!&lt;br&gt;
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.&lt;br&gt;
📢 Share this article with your friends, colleagues on social media.&lt;br&gt;
➕ Follow me on dev.to or any other social media platform.&lt;br&gt;
⭐ Star the &lt;a href="https://github.com/mkobuolys/flutter-design-patterns" rel="noopener noreferrer"&gt;Github&lt;/a&gt; repository.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>oop</category>
      <category>programming</category>
    </item>
    <item>
      <title>21 - Visitor</title>
      <dc:creator>Mangirdas Kazlauskas 🚀</dc:creator>
      <pubDate>Mon, 07 Jun 2021 06:12:24 +0000</pubDate>
      <link>https://dev.to/mkobuolys/21-visitor-2on0</link>
      <guid>https://dev.to/mkobuolys/21-visitor-2on0</guid>
      <description>&lt;p&gt;In the last article, I have analysed a behavioural design pattern that enables loose coupling between the sender of a request and its receiver — Chain of Responsibility. In this article, I would like to analyse and implement another behavioural design pattern that lets you separate algorithms from the objects on which they operate — it is Visitor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is the Visitor design pattern?&lt;/li&gt;
&lt;li&gt;Analysis&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Your Contribution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the Visitor design pattern?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qwQuQKsD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4dsmzqrjtwy97e9l8pg3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qwQuQKsD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4dsmzqrjtwy97e9l8pg3.png" alt="Unexpected Visitor"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visitor&lt;/strong&gt; belongs to the category of behavioural design patterns. The intention of this design pattern is described in the &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns"&gt;GoF book&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s say we have a complex object structure, maybe it is a tree or collection, that consists of several different class components. Now, we want to add some kind of new functionality to these components without changing the classes themselves — is that even possible?&lt;/p&gt;

&lt;p&gt;The key idea here is to define a double-dispatch operation (in the Visitor design pattern’s context, the operation is called &lt;em&gt;accept&lt;/em&gt;) for each specific complex object class — I know, you could think that I lied to you about adding new operations without changing the existing code, but wait, there is a good reason for that! When clients traverse the object structure, the &lt;em&gt;accept&lt;/em&gt; method is called on each element to delegate the request to the specific &lt;em&gt;visitor&lt;/em&gt; object, which is passed to the method as a parameter. Then, the specific method of the visitor object is called (the request is delegated), hence performing the actual request. That’s the main idea of a double-dispatch operation — the client sends the request to the component, while the component delegates the request to the specific visitor’s method. It means, that it is enough to implement a single method to the component class and then you can define a new operation over an object structure simply by adding a new visitor. And this time, you could implement as many different visitor classes as you want without changing the existing code! How cool is that?&lt;/p&gt;

&lt;p&gt;Also, the Visitor design pattern allows gathering related operations into a single class without spreading the implementation details across the whole object structure. That helps when you want to accumulate state while traversing an object structure — there is no need to pass the state to operations that perform the accumulation since the state is stored in the visitor object itself and is accessible by all the specific visitor methods.&lt;/p&gt;

&lt;p&gt;At first, all the &lt;em&gt;visitor&lt;/em&gt;, &lt;em&gt;accept&lt;/em&gt;, &lt;em&gt;double-dispatch&lt;/em&gt; terms could look confusing — don’t worry, it gets much clearer when you see the Visitor design pattern in action. Let’s move to the analysis and implementation parts to understand and learn the details about this pattern and how to implement it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;The general structure of the Visitor design pattern looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lO79dn_x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mk1f9bfnt2cz3aw1g2r3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lO79dn_x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mk1f9bfnt2cz3aw1g2r3.png" alt="Visitor Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Visitor&lt;/em&gt; — declares a visit operation for each &lt;em&gt;concrete element&lt;/em&gt; class in the object structure. If the programming language supports &lt;a href="https://en.wikipedia.org/wiki/Function_overloading"&gt;function overloading&lt;/a&gt;, visit operations could have the same name (Dart does not support that at the moment), but the type of their parameters must be different. Usually, the operation’s name and signature is different and identifies the class (&lt;em&gt;concrete element&lt;/em&gt;) that sends the visit request to the visitor;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Concrete visitors&lt;/em&gt; — implements each operation declared by &lt;em&gt;Visitor&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Element&lt;/em&gt; — declares an &lt;em&gt;accept&lt;/em&gt; method that takes &lt;em&gt;Visitor&lt;/em&gt; as an argument;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Concrete elements&lt;/em&gt; — implements the acceptance method. The implementation should rely on redirecting the request to the proper visitor’s method corresponding to the current element class;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Client&lt;/em&gt; — usually contains a collection or a complex object structure, initialises the &lt;em&gt;concrete visitor&lt;/em&gt; object and then traverses the object structure by visiting each element with the visitor.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Applicability
&lt;/h3&gt;

&lt;p&gt;The primary purpose of the Visitor design pattern is to separate algorithms from the objects on which they operate, hence cleaning up the business logic. This way, the classes of your app could focus on their main job while auxiliary behaviours are extracted into a set of visitor classes. Also, visitors allows keeping the related operations together by defining them in one class.&lt;/p&gt;

&lt;p&gt;Furthermore, the Visitor design pattern should be used when you want to execute an operation on all elements of a complex object structure and you do not want to change the interface(s) of concrete classes. Different visiting method implementations are executed on different classes which accept the visitors, hence the specific implementation details could be changed or new specific visitor implementations could be added without interfering with the existing code base of the object structure and its components.&lt;/p&gt;

&lt;p&gt;Finally, there is one important thing to note: the Visitor design pattern only makes sense for object structures that rarely change (as always, take it with a grain of salt). If you just want to change or add new implementations of visitor — that’s fine. However, changing the object structure classes requires redefining the interface to all visitors which could become cumbersome and violates the Open-Closed (the letter &lt;strong&gt;O&lt;/strong&gt; in &lt;a href="https://en.wikipedia.org/wiki/SOLID"&gt;SOLID&lt;/a&gt; principles). A simple solution to this problem is just defining the operations in those classes without extracting them to a visitor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XD2YKh5t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jg5a9tvcztu489myi6bo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XD2YKh5t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jg5a9tvcztu489myi6bo.gif" alt="Let's Dive In"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the implementation part, we will use the Visitor design pattern on the already implemented complex object structure which was introduced with the Composite design pattern. In my opinion, it would be a great example of how different design patterns could complement each other and how to reuse/extend the already existing codebase.&lt;/p&gt;

&lt;p&gt;Our complex object structure is a file system that consists of directories and files of various types (audio, video, text, etc.). Let’s say that this kind of structure is already implemented using the Composite design pattern. Now, we want to add a possibility to export such file structure in two different formats: human-readable (just provide each file in a single, formatted list) and XML.&lt;/p&gt;

&lt;p&gt;The first possible approach to implement this feature is to define the export method for each specific file type. In this case, this is wrong for several reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For each specific export option, we would need to implement a separate export method in each specific file class. Also, by adding a new export option in the future, we would need to add some extra code to each file class once again.&lt;/li&gt;
&lt;li&gt;It’s a violation of the &lt;a href="https://en.wikipedia.org/wiki/Single-responsibility_principle"&gt;Single-responsibility principle&lt;/a&gt;. The export functionality is just an auxiliary operation applied on top of the file structure, hence each specific file should not care and store the implementation details inside the class itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you could guess, these problems could be easily resolved by applying the Visitor design pattern and defining each specific export option in a separate visitor class which takes care of all the specific implementation details for all the file types in a single place. Let’s check the class diagram first and then implement the pattern!&lt;/p&gt;

&lt;h3&gt;
  
  
  Class diagram
&lt;/h3&gt;

&lt;p&gt;The class diagram below shows the implementation of the Visitor design pattern:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ouo6Rn9S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4b63oy97aeyft11enfxn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ouo6Rn9S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4b63oy97aeyft11enfxn.png" alt="Visitor Implementation Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;IFile&lt;/em&gt; defines a common interface for both &lt;em&gt;File&lt;/em&gt; and &lt;em&gt;Directory&lt;/em&gt; classes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;getSize()&lt;/em&gt; — returns the size of the file;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;render()&lt;/em&gt; — renders the component’s UI;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;accept()&lt;/em&gt; — delegates request to a visitor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;File&lt;/em&gt; class implements the &lt;em&gt;getSize()&lt;/em&gt; and &lt;em&gt;render()&lt;/em&gt; methods, additionally contains &lt;em&gt;title&lt;/em&gt;, &lt;em&gt;fileExtension&lt;/em&gt;, &lt;em&gt;size&lt;/em&gt; and &lt;em&gt;icon&lt;/em&gt; properties.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;AudioFile&lt;/em&gt;, &lt;em&gt;ImageFile&lt;/em&gt;, &lt;em&gt;TextFile&lt;/em&gt; and &lt;em&gt;VideoFile&lt;/em&gt; are concrete file classes implementing the &lt;em&gt;accept()&lt;/em&gt; method from &lt;em&gt;IFile&lt;/em&gt; interface and containing some additional information about the specific file.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Directory&lt;/em&gt; implements the same required methods as &lt;em&gt;File&lt;/em&gt;, but it also contains &lt;em&gt;title&lt;/em&gt;, &lt;em&gt;level&lt;/em&gt;, &lt;em&gt;isInitiallyExpanded&lt;/em&gt; properties and &lt;em&gt;files&lt;/em&gt; list, containing the &lt;em&gt;IFile&lt;/em&gt; objects. It also defines the &lt;em&gt;addFile()&lt;/em&gt; method, which allows adding &lt;em&gt;IFile&lt;/em&gt; objects to the directory (&lt;em&gt;files&lt;/em&gt; list). Similarly as in specific file classes, &lt;em&gt;accept()&lt;/em&gt; method is implemented here as well.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;IVisitor&lt;/em&gt; defines a common interface for the specific visitor classes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;getTitle()&lt;/em&gt; — returns the title of the visitor that is used in the UI;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;visitDirectory()&lt;/em&gt; — defines a visiting method for the &lt;em&gt;Directory&lt;/em&gt; class;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;visitAudioFile()&lt;/em&gt; — defines a visiting method for the &lt;em&gt;AudioFile&lt;/em&gt; class;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;visitImageFile()&lt;/em&gt; — defines a visiting method for the &lt;em&gt;ImageFile&lt;/em&gt; class;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;visitTextFile()&lt;/em&gt; — defines a visiting method for the &lt;em&gt;TextFile&lt;/em&gt; class;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;visitVideoFile()&lt;/em&gt; — defines a visiting method for the &lt;em&gt;VideoFile&lt;/em&gt; class.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;HumanReadableVisitor&lt;/em&gt; and &lt;em&gt;XmlVisitor&lt;/em&gt; are concrete visitor classes that implement visit methods for each specific file type.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;VisitorExample&lt;/em&gt; contains a list of visitors implementing the &lt;em&gt;IVisitor&lt;/em&gt; interface and the composite file structure. The selected visitor is used to format the visible files structure as text and provide it to the UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  IFile
&lt;/h3&gt;

&lt;p&gt;An interface that defines methods to be implemented by specific files and directories. The interface also defines an &lt;em&gt;accept()&lt;/em&gt; method which is used for the Visitor design pattern implementation. Dart language does not support the interface as a class type, so we define an interface by creating an abstract class and providing a method header (name, return type, parameters) without the default implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--46ViCl7l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8aox08ztpwgjt83gsn4n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--46ViCl7l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8aox08ztpwgjt83gsn4n.png" alt="ifile.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  File
&lt;/h3&gt;

&lt;p&gt;A concrete implementation of the &lt;em&gt;IFile&lt;/em&gt; interface. In &lt;em&gt;File&lt;/em&gt; class, &lt;em&gt;getSize()&lt;/em&gt; method simply returns the file size, &lt;em&gt;render()&lt;/em&gt; — returns the file’s UI widget which is used in the example screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TZmRHt7v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/chbn0ucg3q13wimj2cm7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TZmRHt7v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/chbn0ucg3q13wimj2cm7.png" alt="file.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Concrete file classes
&lt;/h3&gt;

&lt;p&gt;All of the specific file type classes implement the &lt;em&gt;accept()&lt;/em&gt; method that delegates request to the specific visitor’s method.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;AudioFile&lt;/em&gt; — a specific file class representing the audio file type that contains an additional &lt;em&gt;albumTitle&lt;/em&gt; property.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gd_yLksG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z4gwwabol9ksrhybzmly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gd_yLksG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z4gwwabol9ksrhybzmly.png" alt="audio_file.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;ImageFile&lt;/em&gt; — a specific file class representing the image file type that contains an additional &lt;em&gt;resolution&lt;/em&gt; property.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8IAqqDNP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pl9ivoa8oat59l34b7rv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8IAqqDNP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pl9ivoa8oat59l34b7rv.png" alt="image_file.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;TextFile&lt;/em&gt; — a specific file class representing the text file type that contains an additional &lt;em&gt;content&lt;/em&gt; property.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jxnxLc-l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d9prhgpb5quxpma5ih8l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jxnxLc-l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d9prhgpb5quxpma5ih8l.png" alt="text_file.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;VideoFile&lt;/em&gt; — a specific file class representing the video file type that contains an additional &lt;em&gt;directedBy&lt;/em&gt; property.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0SWeD7UE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nugwybqpvmkiocmut70j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0SWeD7UE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nugwybqpvmkiocmut70j.png" alt="video_file.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Directory
&lt;/h3&gt;

&lt;p&gt;A concrete implementation of the &lt;em&gt;IFile&lt;/em&gt; interface. Similarly as in &lt;em&gt;File&lt;/em&gt; class, &lt;em&gt;render()&lt;/em&gt; returns the directory’s UI widget which is used in the example screen. However, in this class &lt;em&gt;getSize()&lt;/em&gt; method calculates the directory size by calling the &lt;em&gt;getSize()&lt;/em&gt; method for each item in the &lt;em&gt;files&lt;/em&gt; list and adding up the results. Also, the class implements the &lt;em&gt;accept()&lt;/em&gt; method that delegates request to the specific visitor’s method for the directory.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QfdUE1rD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oba2p8y7mpmb9kde5lty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QfdUE1rD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oba2p8y7mpmb9kde5lty.png" alt="directory.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Formatting extensions
&lt;/h3&gt;

&lt;p&gt;Defines an extension method &lt;em&gt;indentAndAddNewLine&lt;/em&gt; that adds &lt;em&gt;nTab&lt;/em&gt; tabs at the beginning and a new line symbol at the end of a String.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y_3pmZyI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d4dllzrn012vvlmk60ub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y_3pmZyI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d4dllzrn012vvlmk60ub.png" alt="formatting_extensions.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  IVisitor
&lt;/h3&gt;

&lt;p&gt;An interface that defines methods to be implemented by all specific visitors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E6HCQTsI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ncu43gidc0t7384dohmz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E6HCQTsI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ncu43gidc0t7384dohmz.png" alt="ivisitor.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Concrete visitors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;HumanReadableVisitor&lt;/em&gt; — implements the specific visitor that provides file information of each file type in a human-readable format.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m823yH7D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cc24aprc50z9jkum24zm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m823yH7D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cc24aprc50z9jkum24zm.png" alt="human_readable_visitor.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;XmlVisitor&lt;/em&gt; — implements the specific visitor that provides file information of each file type in XML format.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4hL-sdUz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qbn7fjo3hx1te0pcmdy7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4hL-sdUz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qbn7fjo3hx1te0pcmdy7.png" alt="xml_visitor.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;First of all, a markdown file is prepared and provided as a pattern’s description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SVCtSPzO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vwgfz2h1twwdebr4tfp6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SVCtSPzO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vwgfz2h1twwdebr4tfp6.gif" alt="Visitor Markdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;VisitorExample&lt;/em&gt; widget contains the &lt;em&gt;buildMediaDirectory()&lt;/em&gt; method which builds the file structure for the example. Also, it contains a list of different visitors and provides it to the &lt;em&gt;FilesVisitorSelection&lt;/em&gt; widget where the index of a specific visitor is selected by triggering the &lt;em&gt;setSelectedVisitorIndex()&lt;/em&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MkN2tXoz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9r5unr09ucqaq8dkldf8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MkN2tXoz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9r5unr09ucqaq8dkldf8.png" alt="visitor_example.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When exporting files’ information and providing it in the modal via the &lt;em&gt;showFilesDialog()&lt;/em&gt; method, the example widget does not care about the concrete selected visitor as long as it implements the &lt;em&gt;IVisitor&lt;/em&gt; interface. The selected visitor is just applied to the whole file structure by passing it as a parameter to the &lt;em&gt;accept()&lt;/em&gt; method, hence retrieving the formatted files’ structure as text and providing it to the opened &lt;em&gt;FilesDialog&lt;/em&gt; modal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aaucr2H8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tvxycutvinwsevdn5cfu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aaucr2H8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tvxycutvinwsevdn5cfu.gif" alt="Visitor Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the example, by selecting the specific visitor (export as text or XML option), the file structure is exported in the corresponding text format and provided to the user.&lt;/p&gt;

&lt;p&gt;All of the code changes for the Visitor design pattern and its example implementation could be found &lt;a href="https://github.com/mkobuolys/flutter-design-patterns/pull/22"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Contribution
&lt;/h2&gt;

&lt;p&gt;💖 or 🦄 this article to show your support and motivate me to write better!&lt;br&gt;
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.&lt;br&gt;
📢 Share this article with your friends, colleagues on social media.&lt;br&gt;
➕ Follow me on dev.to or any other social media platform.&lt;br&gt;
⭐ Star the &lt;a href="https://github.com/mkobuolys/flutter-design-patterns"&gt;Github&lt;/a&gt; repository.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>oop</category>
      <category>programming</category>
    </item>
    <item>
      <title>20 - Chain of Responsibility</title>
      <dc:creator>Mangirdas Kazlauskas 🚀</dc:creator>
      <pubDate>Mon, 31 May 2021 07:32:38 +0000</pubDate>
      <link>https://dev.to/mkobuolys/20-chain-of-responsibility-37</link>
      <guid>https://dev.to/mkobuolys/20-chain-of-responsibility-37</guid>
      <description>&lt;p&gt;Previously in the series, I have analysed a structural design pattern that introduced a concept of a “shared object” which could be used in multiple contexts simultaneously, hence reducing the memory usage of your code — Flyweight. This time I would like to represent a behavioural design pattern, which enables loose coupling between the sender of a request and its receiver, also adding a possibility for the same request to be handled by multiple handlers — it is the Chain of Responsibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is the Chain of Responsibility design pattern?&lt;/li&gt;
&lt;li&gt;Analysis&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Your Contribution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the Chain of Responsibility design pattern?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YDo0qb_E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0tbc8kg1ewpoirgstk9k.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YDo0qb_E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0tbc8kg1ewpoirgstk9k.jpeg" alt="A Chain Of People Responsible For Freedom"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chain of Responsibility (CoR)&lt;/strong&gt;, also known as &lt;strong&gt;Chain of Command&lt;/strong&gt;, is a behavioural design pattern, which intention in the &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns"&gt;GoF book&lt;/a&gt; is described like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;TL;DR: the Chain of Responsibility design pattern is an ordered list of message handlers that know how to do two things — process a specific type of message or pass the message along to the next message handler.&lt;/p&gt;

&lt;p&gt;First of all, the Chain of Responsibility design pattern is behavioural which means that its primary purpose is to rework the basic workflow (behaviour) and split it into several separate parts or stand-alone objects (recall Command or State design patterns as examples). Let’s say you have some kind of workflow defined in your code where each step should be executed sequentially. It works and everything is fine until…&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some additional steps should be introduced. &lt;em&gt;Ok, not a big deal, just add them&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Some of these steps are optional based on the request. &lt;em&gt;Well, let’s add some conditional blocks, nothing extraordinary&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Oops, we forgot validation… &lt;em&gt;Hmm, the code starts bloating somehow&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;A wild feature request appears: the order of the steps is different based on the request. &lt;em&gt;Please, stahp…&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well, I hope you get the idea that this code could easily become a mess (not to mention the violation of the Open-Closed Principle — the letter &lt;strong&gt;O&lt;/strong&gt; in &lt;a href="https://en.wikipedia.org/wiki/SOLID"&gt;SOLID&lt;/a&gt; principles). What the CoR pattern suggests is to split each step into a separate component — &lt;em&gt;handler&lt;/em&gt; — and later link these handlers into a chain. Each handler contains a reference to the next one, hence once the request is received it is processed by the handler and passed to the next one along the chain until the workflow is finished. As a result, we still have the same sequential code execution, but now each step is separated, additional steps could be added without changing the existing code. But wait, there is more!&lt;/p&gt;

&lt;p&gt;The Chain of Responsibility pattern allows reordering, adding or removing handlers in the chain at run-time — how cool is that, right? Also, each handler could be implemented in a way that it could decide whether to pass the request further down the chain or not.&lt;/p&gt;

&lt;p&gt;Lots of great ideas already mentioned here, so let’s just jump right in by analysing the CoR design pattern and its implementation in more detail!&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;The general structure of the Chain of Responsibility design pattern looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BYqJuyQD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nfjtboulon6uid8e8uav.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BYqJuyQD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nfjtboulon6uid8e8uav.png" alt="Chain of Responsibility Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Handler&lt;/em&gt; — defines an interface for handling requests. This interface is optional when all the handlers extend the &lt;em&gt;BaseHandler&lt;/em&gt; class — then having a single abstract method for handling requests should be enough;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;BaseHandler&lt;/em&gt; — an abstract class that contains the boilerplate code that’s common to all the handler classes and maintains a reference to the next handler object on the chain. Also, the class may implement the default handling behaviour e.g. it can pass the request to the next handler if there is one;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;ConcreteHandlers&lt;/em&gt; — contain the actual code for processing the request. Upon receiving a request, the handler could either handle it or pass it along the chain. Usually, handlers are immutable once they are initialised;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Client&lt;/em&gt; — composes the chain(s) of handlers and later initiates the request to a &lt;em&gt;ConcreteHandler&lt;/em&gt; object on the chain.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Applicability
&lt;/h3&gt;

&lt;p&gt;The Chain of Responsibility design pattern should be used when the system is expected to process different kinds of requests in various ways, but neither the request types nor the handling sequence is defined at compile-time. The pattern enables linking several handlers into one chain and allowing the client to pass requests along that chain. As a result, each handler will receive the request and process it and/or pass it further. Also, to resolve the unknown handling sequence problem, handlers could provide setters for a reference field of the successor inside the handler classes — you will be able to add, delete or reorder handlers at run-time, hence changing the handling sequence of a request.&lt;/p&gt;

&lt;p&gt;Furthermore, the CoR pattern should be used when a single request must be handled by multiple handlers, usually in a particular order. In this case, the chain could be defined at compile-time and all requests will get through the chain exactly as planned. If the execution order is irrelevant, just roll the dice and build the chain in random order — all handlers would still receive the request and handle it.&lt;/p&gt;

&lt;p&gt;Finally, one thing to remember — &lt;strong&gt;the receipt isn’t guaranteed&lt;/strong&gt;. Since CoR introduces the loose coupling between sender and receiver, and the request could be handled by any handler in the chain, there is no guarantee that it will be actually handled. In cases when the request must be processed by at least one handler, you must ensure that the chain is configured properly, for instance, by adding some kind of a monitor handler at the end of the chain that notifies about unhandled requests and/or executes some specific logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0zUHWf4r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v0b08zvsn1qzed8ibavn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0zUHWf4r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v0b08zvsn1qzed8ibavn.gif" alt="Let's Get The Party Started"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will use the Chain of Responsibility design pattern to implement a custom logging workflow in the application.&lt;/p&gt;

&lt;p&gt;Let’s say that we want 3 different log levels based on their importance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debug — only needed in the local environment for development purposes;&lt;/li&gt;
&lt;li&gt;Info — we want to see those logs locally, but also they should be stored and visible in the external logging service when the application is deployed;&lt;/li&gt;
&lt;li&gt;Error — those logs must be visible locally and external logging service, but also we want to notify our development team by sending an e-mail when such log appears.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this case, our request is a log message with its content and log level. Our handlers — debug, info and error loggers with their custom logic. To implement the wanted workflow, we could link the loggers in the following order: Debug -&amp;gt; Info -&amp;gt; Error. If the logger’s log level is lower or equal to the one defined in the message, the message should be logged. And that’s basically it, really, it’s that simple!&lt;/p&gt;

&lt;p&gt;A picture is worth a thousand words, so let’s check the class diagram first and then implement the pattern.&lt;/p&gt;

&lt;h2&gt;
  
  
  Class diagram
&lt;/h2&gt;

&lt;p&gt;The class diagram below shows the implementation of the Chain of Responsibility design pattern:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--e_By0pBe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/niirr29l0hgyn64c1o8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--e_By0pBe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/niirr29l0hgyn64c1o8g.png" alt="Chain of Responsibility Implementation Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;LogLevel&lt;/em&gt; is an enumerator class defining possible log levels — Debug, Info and Error.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;LogMessage&lt;/em&gt; class is used to store information about the log message: its log level and the message text. It also provides a public &lt;em&gt;getFormattedMessage()&lt;/em&gt; method to format the log entry as a Widget object (for that, a private helper method &lt;em&gt;getLogEntryColor()&lt;/em&gt; and a getter &lt;em&gt;logLevelString&lt;/em&gt; are used).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;LoggerBase&lt;/em&gt; is an abstract class that is used as a base class for all the specific loggers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;logMessage()&lt;/em&gt; — logs message using the &lt;em&gt;log()&lt;/em&gt; method and passes the request along the chain;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;logDebug()&lt;/em&gt; — logs the message with a log level of Debug;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;logInfo()&lt;/em&gt; — logs the message with a log level of Info;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;logError()&lt;/em&gt; — logs the message with a log level of Error;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;log()&lt;/em&gt; — an abstract method to log the message (must be implemented by a specific logger).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, the &lt;em&gt;LoggerBase&lt;/em&gt; contains a reference to the next logger (&lt;em&gt;nextLogger&lt;/em&gt;) and logger’s log level (&lt;em&gt;logLevel&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;DebugLogger&lt;/em&gt;, &lt;em&gt;InfoLogger&lt;/em&gt; and &lt;em&gt;ErrorLogger&lt;/em&gt; are concrete logger classes that extend the &lt;em&gt;LoggerBase&lt;/em&gt; class and implement the abstract &lt;em&gt;log()&lt;/em&gt; method. &lt;em&gt;InfoLogger&lt;/em&gt; uses the &lt;em&gt;ExternalLoggingService&lt;/em&gt; to log messages, &lt;em&gt;ErrorLogger&lt;/em&gt; — the &lt;em&gt;MailService&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;All the specific loggers use or inject the &lt;em&gt;LogBloc&lt;/em&gt; class to mock the actual logging and provide log entries to the UI.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;LogBloc&lt;/em&gt; stores a list of logs and exposes them through the stream — &lt;em&gt;outLogStream&lt;/em&gt;. Also, it defines the &lt;em&gt;log()&lt;/em&gt; method to add a new log to the list and notify &lt;em&gt;outLogStream&lt;/em&gt; subscribers with an updated log entries list.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ChainOfResponsibilityExample&lt;/em&gt; creates a chain of loggers and uses public methods defined in &lt;em&gt;LoggerBase&lt;/em&gt; to log messages. It also initialises and contains the &lt;em&gt;LogBloc&lt;/em&gt; instance to store log entries and later show them in the UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  LogLevel
&lt;/h3&gt;

&lt;p&gt;A special kind of class — &lt;em&gt;enumeration&lt;/em&gt; — to define different log levels. Also, there is a &lt;em&gt;LogLevelExtensions&lt;/em&gt; defined where the operator &amp;lt;= is overridden to compare whether one log level is lower or equal to the other.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6zmPoMlc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2jesprd26m6hdytvled1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6zmPoMlc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2jesprd26m6hdytvled1.png" alt="log_level.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  LogMessage
&lt;/h3&gt;

&lt;p&gt;A simple class to store information about the log entry: log level and message. Also, this class defines a private getter &lt;em&gt;logLevelString&lt;/em&gt; to return the text representation of a specific log level and a private method &lt;em&gt;getLogEntryColor()&lt;/em&gt; to return the log entry colour based on the log level. The &lt;em&gt;getFormattedMessage()&lt;/em&gt; method returns the formatted log entry as a &lt;em&gt;Text&lt;/em&gt; widget which is used in the UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ug-N70s9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/us0biwt4jbl3s1tekfwa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ug-N70s9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/us0biwt4jbl3s1tekfwa.png" alt="log_message.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  LogBloc
&lt;/h3&gt;

&lt;p&gt;A Business Logic component (BLoC) class to store log messages and provide them to the UI through a public stream. New log entries are added to the logs list via the &lt;em&gt;log()&lt;/em&gt; method while all the logs could be accessed through the public &lt;em&gt;outLogStream&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L_aeWKgf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bkmu50b6ruum8h2l0q38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L_aeWKgf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bkmu50b6ruum8h2l0q38.png" alt="log_bloc.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ExternalLoggingService
&lt;/h3&gt;

&lt;p&gt;A simple class that represents the actual external logging service. Instead of sending the log message to some kind of 3rd party logging service (which, in fact, could be called in the &lt;em&gt;logMessage()&lt;/em&gt; method), it just logs the message to UI through the &lt;em&gt;LogBloc&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FbUU8meG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hj5dzgpbelb9c42pp0vn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FbUU8meG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hj5dzgpbelb9c42pp0vn.png" alt="external_logging_service.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  MailService
&lt;/h3&gt;

&lt;p&gt;A simple class that represents the actual mail logging service. Instead of sending the log message as an email to the user, it just logs the message to UI through the &lt;em&gt;LogBloc&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TFNIH9qP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gevlr106k3yzn4g716fp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TFNIH9qP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gevlr106k3yzn4g716fp.png" alt="mail_service.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  LoggerBase
&lt;/h3&gt;

&lt;p&gt;An abstract class for the base logger implementation. It stores the log level and a reference (successor) to the next logger in the chain. Also, the class implements a common &lt;em&gt;logMessage()&lt;/em&gt; method that logs the message if its log level is lower than the current logger’s and then forwards the message to the successor (if there is one). The abstract &lt;em&gt;log()&lt;/em&gt; method must be implemented by specific loggers extending the &lt;em&gt;LoggerBase&lt;/em&gt; class.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hZ8idz9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pruohe8p7jv7iz75ey3g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hZ8idz9N--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pruohe8p7jv7iz75ey3g.png" alt="logger_base.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Concrete loggers
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;DebugLogger&lt;/em&gt; — a specific implementation of the logger that sets the log level to &lt;em&gt;Debug&lt;/em&gt; and simply logs the message to UI through the &lt;em&gt;LogBloc&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1-L8upzk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k40w4dh4tn7gx2x4jeqz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1-L8upzk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k40w4dh4tn7gx2x4jeqz.png" alt="debug_logger.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;InfoLogger&lt;/em&gt; — a specific implementation of the logger that sets the log level to &lt;em&gt;Info&lt;/em&gt; and uses the &lt;em&gt;ExternalLoggingService&lt;/em&gt; to log the message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dkTXEAR---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i016diqwbyi9v46fntvp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dkTXEAR---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i016diqwbyi9v46fntvp.png" alt="info_logger.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;ErrorLogger&lt;/em&gt; — a specific implementation of the logger that sets the log level to &lt;em&gt;Error&lt;/em&gt; and uses the &lt;em&gt;MailService&lt;/em&gt; to log the message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XOQWPqim--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4jt7fj2kxhnugahfzi1c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XOQWPqim--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4jt7fj2kxhnugahfzi1c.png" alt="error_logger.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;First of all, a markdown file is prepared and provided as a pattern’s description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZViZDTXu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pk67o11vuuwoezgy3vf6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZViZDTXu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pk67o11vuuwoezgy3vf6.gif" alt="Chain of Responsibility Markdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;ChainOfResponsibilityExample&lt;/em&gt; widget initialises and contains the loggers’ chain object (see the &lt;em&gt;initState()&lt;/em&gt; method). Also, for demonstration purposes, the &lt;em&gt;LogBloc&lt;/em&gt; object is initialised there, too, and used to send logs and retrieve a list of them through the stream — &lt;em&gt;outLogStream&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--urfxM6Iu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iv61n2d484topkm6tuse.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--urfxM6Iu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iv61n2d484topkm6tuse.png" alt="chain_of_responsibility_example.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By creating a chain of loggers, the client — &lt;em&gt;ChainOfResponsibilityExample&lt;/em&gt; widget — does not care about the details on which specific logger should handle the log entry, it just passes (logs) the message to a chain of loggers. This way, the sender (client) and receiver (logger) are decoupled, the loggers’ chain itself could be built at run-time in any order or structure e.g. you can skip the Debug logger for non-local environments and only use the Info -&amp;gt; Error chain.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--59pDM0-M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/40l8rt6rjv3q4cajxyhf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--59pDM0-M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/40l8rt6rjv3q4cajxyhf.gif" alt="Chain of Responsibility Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the example, &lt;em&gt;debug&lt;/em&gt; level logs are only handled by the debug logger, &lt;em&gt;info&lt;/em&gt; — by debug and info level handlers and &lt;em&gt;error&lt;/em&gt; logs are handled by all three loggers.&lt;/p&gt;

&lt;p&gt;All of the code changes for the Chain of Responsibility design pattern and its example implementation could be found &lt;a href="https://github.com/mkobuolys/flutter-design-patterns/pull/21"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Contribution
&lt;/h2&gt;

&lt;p&gt;💖 or 🦄 this article to show your support and motivate me to write better!&lt;br&gt;
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.&lt;br&gt;
📢 Share this article with your friends, colleagues on social media.&lt;br&gt;
➕ Follow me on dev.to or any other social media platform.&lt;br&gt;
⭐ Star the &lt;a href="https://github.com/mkobuolys/flutter-design-patterns"&gt;Github&lt;/a&gt; repository.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>oop</category>
      <category>programming</category>
    </item>
    <item>
      <title>19 - Flyweight</title>
      <dc:creator>Mangirdas Kazlauskas 🚀</dc:creator>
      <pubDate>Mon, 24 May 2021 06:47:29 +0000</pubDate>
      <link>https://dev.to/mkobuolys/19-flyweight-2dcn</link>
      <guid>https://dev.to/mkobuolys/19-flyweight-2dcn</guid>
      <description>&lt;p&gt;In the last article, I have analysed a creational design pattern that divides the construction of a complex object into several separate steps — Builder. In this article, I would like to analyse and implement a structural design pattern that helps using a huge number of objects in your code that could barely fit into available RAM — it is Flyweight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is the Flyweight design pattern?&lt;/li&gt;
&lt;li&gt;Analysis&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Your Contribution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the Flyweight design pattern?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QZNeWZDp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qcek1unfyfx7z3solg57.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QZNeWZDp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qcek1unfyfx7z3solg57.png" alt="Sharing Is Caring"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flyweight&lt;/strong&gt; belongs to the category of structural design patterns. The intention of this design pattern is described in the &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns"&gt;GoF book&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use sharing to support large numbers of fine-grained objects efficiently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s take an object-oriented document editor as an example. For document elements like tables, images or figures, separate objects are created. However, for text elements (individual characters) this is not feasible even though it promotes flexibility: characters and any other embedded elements could be treated uniformly, the application could be extended to support new character sets very easily. The reason is simple — limitations of the hardware. Usually, a document contains hundreds of thousands of character objects which would consume a lot of memory and it could lead to unexpected crashes, for instance, when the document is being edited and eventually there would be no memory left for new characters or any other type of embedded objects. How this kind of object-oriented document editors could be implemented, then?&lt;/p&gt;

&lt;p&gt;The “secret” relies on the flyweight objects — shared objects that can be used in multiple contexts simultaneously. But how this could even work? If we reuse the same object, doesn’t that mean that when the object is changed in one place, all the other places are affected, too? Well, the key concept here is the distinction between &lt;strong&gt;intrinsic&lt;/strong&gt; and &lt;strong&gt;extrinsic&lt;/strong&gt; state. The intrinsic state is invariant (context-independent) and therefore can be shared e.g. the code of a character in the used character set. The extrinsic state is variant (context-dependent) and therefore can not be shared e.g. the position of a character in the document. And that’s the reason why this concept works in object-oriented editors — a separate flyweight object is created for each character in the set (e.g. each letter in the alphabet) which stores the character code as the intrinsic state, while the coordinate positions in the document of that character are passed to the flyweight object as an extrinsic state. As a result, only one flyweight object instance per character could be stored in the memory and shared across different contexts in the document structure. &lt;em&gt;Sharing is caring&lt;/em&gt;, right?&lt;/p&gt;

&lt;p&gt;Let’s move to the analysis and implementation parts to understand and learn the details about this pattern and how to implement it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;The general structure of the Flyweight design pattern looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n0sQnzA1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xeqyprq77fhxcxk5rkqd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n0sQnzA1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xeqyprq77fhxcxk5rkqd.png" alt="Flyweight Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Flyweight&lt;/em&gt; — contains intrinsic state while the extrinsic state is passed to the flyweight’s methods. The object must be shareable (can be used in many different contexts);&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;FlyweightFactory&lt;/em&gt; — creates and manages flyweight objects. When a client calls the factory, it checks whether the specific flyweight object exists. If yes, it is simply returned to the client, otherwise, a new instance of the flyweight object is created and then returned;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Context&lt;/em&gt; — contains the extrinsic state, unique across all original objects;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Client&lt;/em&gt; — computes or stores the extrinsic state of flyweight(s) and maintains a reference to it/them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Applicability
&lt;/h3&gt;

&lt;p&gt;The Flyweight design pattern should be used only when your program must support a huge number of objects which barely fit into available RAM. The pattern’s effectiveness depends on how and where it’s used. It would be the most useful when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An application uses a large number of objects;&lt;/li&gt;
&lt;li&gt;The objects drain all available RAM on a target device;&lt;/li&gt;
&lt;li&gt;The objects contain duplicate states which can be extracted and shared between multiple objects;&lt;/li&gt;
&lt;li&gt;Many groups of objects could be replaced by a few shared objects once the extrinsic state is removed;&lt;/li&gt;
&lt;li&gt;The application doesn’t depend on object identity. Since flyweight objects are shared, conceptually distinct objects could be considered as the same object.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bWZlOR80--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zpulj57mxuv2lxylhwzc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bWZlOR80--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zpulj57mxuv2lxylhwzc.gif" alt="Let's Make It Real"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sadly, the implementation would not resolve any real-world problem this time, but we will implement a simple representation screen and later investigate how the usage of the Flyweight design pattern reduces memory consumption.&lt;/p&gt;

&lt;p&gt;Let’s say, we want to draw our custom background using two different geometric shapes — circles and squares. Also, in the background, we want to put a total of 1000 shapes at random positions. This will be implemented in two different ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A new shape object would be created for each shape in the background;&lt;/li&gt;
&lt;li&gt;A flyweight factory would be used which creates a single object per shape.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Later, we will use a profiler tool for Dart Apps — &lt;a href="https://dart-lang.github.io/observatory/"&gt;Observatory&lt;/a&gt; — to investigate how much memory is used for each of these implementations. Let’s check the class diagram first and then implement the pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  Class diagram
&lt;/h3&gt;

&lt;p&gt;The class diagram below shows the implementation of the Flyweight design pattern:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_Xvrw3K7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/npew1k7qulr73zm1mxzt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_Xvrw3K7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/npew1k7qulr73zm1mxzt.png" alt="Flyweight Implementation Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;ShapeType&lt;/em&gt; is an enumerator class defining possible shape types — Circle and Square.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;IPositionedShape&lt;/em&gt; is an abstract class that is used as an interface for the specific shape classes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;render()&lt;/em&gt; — renders the shape — returns the positioned shape widget. Also, the &lt;strong&gt;extrinsic&lt;/strong&gt; state (x and y coordinates) are passed to this method to render the shape in the exact position.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Circle&lt;/em&gt; and &lt;em&gt;Square&lt;/em&gt; are concrete positioned shape classes that implement the abstract class &lt;em&gt;IPositionedShape&lt;/em&gt;. Both of these shapes have their own &lt;strong&gt;intrinsic&lt;/strong&gt; state: circle defines &lt;em&gt;color&lt;/em&gt; and &lt;em&gt;diameter&lt;/em&gt; properties while square contains &lt;em&gt;color&lt;/em&gt;, &lt;em&gt;width&lt;/em&gt; properties and a getter &lt;em&gt;height&lt;/em&gt; which returns the same value as &lt;em&gt;width&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;ShapeFactory&lt;/em&gt; is a simple factory class that creates and returns a specific shape object via the &lt;em&gt;createShape()&lt;/em&gt; method by providing the &lt;em&gt;ShapeType&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;ShapeFlyweightFactory&lt;/em&gt; is a flyweight factory that contains a map of flyweight objects — &lt;em&gt;shapesMap&lt;/em&gt;. When the concrete flyweight is requested via the &lt;em&gt;getShape()&lt;/em&gt; method, the flyweight factory checks whether it exists in the map and returns it from there. Otherwise, a new instance of the shape is created using the &lt;em&gt;ShapeFactory&lt;/em&gt; and persisted in the map object for further usage.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;FlyweightExample&lt;/em&gt; initialises and contains the &lt;em&gt;ShapeFlyweightFactory&lt;/em&gt; object. Also, it contains a list of positioned shape — &lt;em&gt;shapesList&lt;/em&gt; — which is built using the &lt;em&gt;ShapeFlyweightFactory&lt;/em&gt; and flyweight positioned shape objects.&lt;/p&gt;

&lt;h3&gt;
  
  
  ShapeType
&lt;/h3&gt;

&lt;p&gt;A special kind of class — &lt;em&gt;enumeration&lt;/em&gt; — to define different shape types.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PgiesdRp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jhagaeqh1vl6z3ymhjv3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PgiesdRp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jhagaeqh1vl6z3ymhjv3.png" alt="shape_type.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  IPositionedShape
&lt;/h3&gt;

&lt;p&gt;An interface that defines the &lt;em&gt;render()&lt;/em&gt; method to be implemented by concrete shape classes. Dart language does not support the interface as a class type, so we define an interface by creating an abstract class and providing a method header (name, return type, parameters) without the default implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b7-xvM8P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1vmntc0nv8kulf141d2r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b7-xvM8P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1vmntc0nv8kulf141d2r.png" alt="ipositioned_shape.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Concrete shapes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Circle&lt;/em&gt; — a specific implementation of the &lt;em&gt;IPositionedShape&lt;/em&gt; interface representing the shape of a circle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bFsTCC96--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2m4x0u871syv425b025v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bFsTCC96--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2m4x0u871syv425b025v.png" alt="circle.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Square&lt;/em&gt; — a specific implementation of the &lt;em&gt;IPositionedShape&lt;/em&gt; interface representing the shape of a square.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kHupRnaD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydxfpm18qey7bc5um80d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kHupRnaD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ydxfpm18qey7bc5um80d.png" alt="square.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ShapeFactory
&lt;/h3&gt;

&lt;p&gt;A simple factory class that defines the &lt;em&gt;createShape()&lt;/em&gt; method to create a concrete shape by providing its type.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WeQFsUHa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mo20ss2dhzfiw3xk310r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WeQFsUHa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mo20ss2dhzfiw3xk310r.png" alt="shape_factory.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ShapeFlyweightFactory
&lt;/h3&gt;

&lt;p&gt;A flyweight factory class that keeps track of all the flyweight objects and creates them if needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q6foJW_S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cjm9955k5xa93mwusqly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q6foJW_S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cjm9955k5xa93mwusqly.png" alt="shape_flyweight_factory.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;First of all, a markdown file is prepared and provided as a pattern’s description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hCMZQKiS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0bxcpu3gxbtfc5qp8nyo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hCMZQKiS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0bxcpu3gxbtfc5qp8nyo.gif" alt="Flyweight Markdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;FlyweightExample&lt;/em&gt; initialises and contains the &lt;em&gt;ShapeFlyweightFactory&lt;/em&gt; class object. Also, for demonstration purposes, the &lt;em&gt;ShapeFactory&lt;/em&gt; object is initialised here, too. Based on the selected option, either the &lt;em&gt;ShapeFactory&lt;/em&gt; or &lt;em&gt;ShapeFlyweightFactory&lt;/em&gt; is used to populate a list of &lt;em&gt;IPositionedShape&lt;/em&gt; objects which are rendered in the background of the example screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y2PjAEMv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2yoj0ru3c5ay1llxa57i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y2PjAEMv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2yoj0ru3c5ay1llxa57i.png" alt="flyweight_example.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the &lt;em&gt;ShapeFlyweightFactory&lt;/em&gt;, the client — &lt;em&gt;FlyweightExample&lt;/em&gt; widget — does not care about the flyweight objects’ creation or management. &lt;em&gt;IPositionedShape&lt;/em&gt; objects are requested from the factory by passing the &lt;em&gt;ShapeType&lt;/em&gt;, flyweight factory keeps all the instances of the needed shapes itself, only returns references to them. Hence, only a single instance of a shape object per type could be created and reused when needed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bCb-fUt8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3ofaita2y7rywastaryy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bCb-fUt8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3ofaita2y7rywastaryy.gif" alt="Flyweight Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the example, we could see that either 2 or 1000 shape instances are created to build the screen background. However, to understand what is happening under the hood, we can check the memory consumption using Dart Observatory.&lt;/p&gt;

&lt;p&gt;When we access the Markdown screen of the Flyweight design pattern, Circle and Square instances are not created since they are not visible on the screen:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lUC-Dn9v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4xxuy77gn0wcu55dvrmx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lUC-Dn9v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4xxuy77gn0wcu55dvrmx.png" alt="Shapes Not Created"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before rendering the Example screen (without using flyweight factory), a total of 1000 shape instances are created — in this case, 484 circles and 516 squares:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hsBK7Ysi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dqsvop6obsib8wc1u4l1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hsBK7Ysi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dqsvop6obsib8wc1u4l1.png" alt="Shapes Without Flyweight"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we use the flyweight factory, only one instance per specific shape is needed which is initiated and then shared (reused) later:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iTO2UVpZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k65cvc00mlwkdfb5uin2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iTO2UVpZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k65cvc00mlwkdfb5uin2.png" alt="Shapes With Flyweight"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One shape instance uses 16 bytes of memory, so when we initiate 1000 shapes, that is ~16kB of memory in total. However, when a flyweight factory is used, only 32 bytes are enough to store all different shape instances — 500 times less memory is needed! Now, if you increase the number of shapes to 1 million, without the flyweight factory you would need ~15.2MB of memory to store them, but with a flyweight factory, the same 32 bytes would be enough.&lt;/p&gt;

&lt;p&gt;All of the code changes for the Flyweight design pattern and its example implementation could be found &lt;a href="https://github.com/mkobuolys/flutter-design-patterns/pull/20"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Contribution
&lt;/h2&gt;

&lt;p&gt;💖 or 🦄 this article to show your support and motivate me to write better!&lt;br&gt;
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.&lt;br&gt;
📢 Share this article with your friends, colleagues on social media.&lt;br&gt;
➕ Follow me on dev.to or any other social media platform.&lt;br&gt;
⭐ Star the &lt;a href="https://github.com/mkobuolys/flutter-design-patterns"&gt;Github&lt;/a&gt; repository.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>oop</category>
      <category>programming</category>
    </item>
    <item>
      <title>18 - Builder</title>
      <dc:creator>Mangirdas Kazlauskas 🚀</dc:creator>
      <pubDate>Mon, 17 May 2021 13:56:05 +0000</pubDate>
      <link>https://dev.to/mkobuolys/18-builder-fgg</link>
      <guid>https://dev.to/mkobuolys/18-builder-fgg</guid>
      <description>&lt;p&gt;Previously in the series, I have analysed a relatively complex, but very practical and useful structural design pattern — Bridge. This time I would like to represent a design pattern, which divides the construction of a complex object into several separate steps. It is a creational design pattern called Builder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is the Builder design pattern?&lt;/li&gt;
&lt;li&gt;Analysis&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Your Contribution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the Builder design pattern?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TRVKskfp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xmw60tgptct6kaczkhig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TRVKskfp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xmw60tgptct6kaczkhig.png" alt="If Bob The Builder Were A Programmer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Builder&lt;/strong&gt; is a creational design pattern, which intention in the &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns"&gt;GoF book&lt;/a&gt; is described like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Separate the construction of a complex object from its representation so that the same construction process can create different representations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The intention could be split into two parts:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Separate the construction of a complex object from its representation…&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You should have already noticed this in the majority of the design patterns overviewed in the series, maybe in a slightly different form, e.g. &lt;em&gt;separate the abstraction from its representation&lt;/em&gt;. In this case, one of the main purposes of the Builder design pattern is to separate the creation process (logic) of a complex object from the object (data) itself. What is a complex object? Well, there is no specific point or any criteria of the object when you could say that it is complex. Usually, an object could be considered as complex when the object’s creation does not simply end with calling its constructor — additionally, you should set some extra specific parameters, call additional methods.&lt;/p&gt;

&lt;p&gt;Ok, at this point we have a complex object, we can create it by using some additional parameters and/or methods — why we need any additional abstraction on top of that, why we should separate this creation process from the object at all?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;… so that the same construction process can create different representations.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ahh, that’s the point! To understand it better, let’s say we are building a house. To build a house (object), the construction steps (build logic) are pretty much the same — you need the foundation, floor, some walls, doors, windows, a roof, etc. Even though the construction process of the house is the same, each of these steps could be adjusted, hence the final result would look completely different. And that is the main idea of the Builder design pattern — abstract the object’s creation process so that constructions steps could be adjusted to provide a different representation (final result).&lt;/p&gt;

&lt;p&gt;The Builder design pattern moves the object construction code out of its own class to separate objects called &lt;em&gt;builders&lt;/em&gt;. Each of these builders follows the same interface and implements separate object’s construction steps. That is, if you want a different object’s representation, just create a different &lt;em&gt;builder&lt;/em&gt; class and implement these construction steps correspondingly. Also, there is one additional layer in the Builder design pattern — &lt;em&gt;Director&lt;/em&gt;. The &lt;em&gt;Director&lt;/em&gt; is a simple class that is aware of the &lt;em&gt;Builder&lt;/em&gt; interface and defines the order in which to execute the building steps. This class is not mandatory, though, but it hides the details of product construction from the client code.&lt;/p&gt;

&lt;p&gt;I know, the structure of the Builder design pattern is quite complex, so let’s move to the analysis and implementation parts to understand it better!&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;The general structure of the Builder design pattern looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4mPgcvPz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vmrwwxsmdtaps916mnxx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4mPgcvPz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vmrwwxsmdtaps916mnxx.png" alt="Builder Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Builder&lt;/em&gt; — defines an abstract interface that is common to all types of builders for creating parts of a &lt;em&gt;Product&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Concrete Builder&lt;/em&gt; — provides a specific implementation of the construction steps. Also, it defines and keeps track of the &lt;em&gt;Product&lt;/em&gt; it creates;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Director&lt;/em&gt; — constructs an object using the &lt;em&gt;Builder&lt;/em&gt; interface, defines the order in which the construction steps are called;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Product&lt;/em&gt; — represents the complex object under construction, exposes interface/methods for assembling the parts into the final result;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Client&lt;/em&gt; — associates the specific &lt;em&gt;Builder&lt;/em&gt; object with the &lt;em&gt;Director&lt;/em&gt;. Later, a &lt;em&gt;Product&lt;/em&gt; object is created by calling the &lt;em&gt;Director&lt;/em&gt; class instance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Applicability
&lt;/h3&gt;

&lt;p&gt;The Builder design pattern should be used when you notice multiple constructors of the same class referencing each other. For instance, you have a constructor with multiple optional parameters. Some of these parameters have default values, so you create several shorter constructors with fewer parameters, but still refer to the main one. By using the Builder design pattern, you are building objects step by step only using those steps that are really needed — you do not need to cope with the problem of multiple constructors with optional parameters anymore.&lt;/p&gt;

&lt;p&gt;As already mentioned, this pattern should be used when you want to create different representations of some product. That is, the pattern could be applied when the construction steps are similar, but they differ in the details. The builder interface defines those steps (some of them may even have the default implementation) while concrete builders implement these steps to construct a particular representation of the product.&lt;/p&gt;

&lt;p&gt;Finally, the Builder design pattern is useful when the algorithm for creating a complex object should be independent of the parts that make up the objects and how they are assembled. In simple words, it is just a simple extraction of the object’s creation logic from its own class. Therefore, the construction algorithm could evolve separately from the actual product it provides, the modification of this process does require changing the object’s code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q0LBzAIG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sostrjdufnl7esi56wpf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q0LBzAIG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sostrjdufnl7esi56wpf.gif" alt="Let's Do This"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This time, the implementation part is very straightforward — we will use the Builder design pattern to implement the build process of &lt;em&gt;McDonald’s&lt;/em&gt; burgers.&lt;/p&gt;

&lt;p&gt;As you may know, &lt;em&gt;McDonald’s&lt;/em&gt; menu contains multiple burgers (regular burger, cheeseburger, Big Mac just to name a few). All of these burgers use the very same products, just the ingredients list is different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regular burger — buns, beef patty, ketchup, mustard, grill seasoning, onions, pickle slices;&lt;/li&gt;
&lt;li&gt;Cheeseburger — buns, beef patty, cheese, ketchup, mustard, grill seasoning, onions, pickle slices;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Big Mac&lt;/em&gt; — buns, cheese, beef patty, Big Mac sauce, grill seasoning, onions, pickle slices, shredded lettuce.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, by changing the build process of the burger (changing ingredients), we completely change the final result. Also, at any moment there could be a requirement to add a new burger to the menu. Finally, the user-friendly UI should be implemented where you can select a burger from the menu and see its price, ingredients and allergens list.&lt;/p&gt;

&lt;p&gt;For this problem, the Builder design pattern is a great option since we can define different &lt;em&gt;builder&lt;/em&gt; classes which build specific burgers. Also, if a new burger should be added to the menu at any point, we can simply introduce another &lt;em&gt;builder&lt;/em&gt; class to cope with this change. Let’s check the class diagram first and then implement the pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  Class diagram
&lt;/h3&gt;

&lt;p&gt;The class diagram below shows the implementation of the Builder design pattern:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pnfRDmDe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fo43fjetxhvs945j57jk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pnfRDmDe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fo43fjetxhvs945j57jk.png" alt="Builder Implementation Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Ingredient&lt;/em&gt; is an abstract class that is used as a base class for all the ingredient classes. The class contains &lt;em&gt;allergens&lt;/em&gt; and &lt;em&gt;name&lt;/em&gt; properties as well as &lt;em&gt;getAllergens()&lt;/em&gt; and &lt;em&gt;getName()&lt;/em&gt; methods to return the values of these properties.&lt;/p&gt;

&lt;p&gt;There are a lot of concrete ingredient classes: &lt;em&gt;BigMacBun&lt;/em&gt;, &lt;em&gt;RegularBun&lt;/em&gt;, &lt;em&gt;BeefPatty&lt;/em&gt;, &lt;em&gt;McChickenPatty&lt;/em&gt;, &lt;em&gt;BigMacSauce&lt;/em&gt;, &lt;em&gt;Ketchup&lt;/em&gt;, &lt;em&gt;Mayonnaise&lt;/em&gt;, &lt;em&gt;Mustard&lt;/em&gt;, &lt;em&gt;Onions&lt;/em&gt;, &lt;em&gt;PickleSlices&lt;/em&gt;, &lt;em&gt;ShreddedLettuce&lt;/em&gt;, &lt;em&gt;Cheese&lt;/em&gt; and &lt;em&gt;GrillSeasoning&lt;/em&gt;. All of these classes represent a specific ingredient of a burger and contains a default constructor to set the &lt;em&gt;allergens&lt;/em&gt; and &lt;em&gt;name&lt;/em&gt; property values of the base class.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Burger&lt;/em&gt; is a simple class representing the product of a builder. It contains the &lt;em&gt;ingredients&lt;/em&gt; list and &lt;em&gt;price&lt;/em&gt; property to store the corresponding values. Also, the class contains several methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;addIngredient()&lt;/em&gt; — adds an ingredient to the burger;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;getFormattedIngredients()&lt;/em&gt; — returns a formatted ingredients’ list of a burger (separated by commas);&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;getFormattedAllergens()&lt;/em&gt; — returns a formatted allergens’ list of a burger (separated by commas);&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;getFormattedPrice()&lt;/em&gt; — returns a formatted price of a burger;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;setPrice()&lt;/em&gt; — sets the price for the burger.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;BurgerBuilderBase&lt;/em&gt; is an abstract class that is used as a base class for all the burger builder classes. It contains &lt;em&gt;burger&lt;/em&gt; and &lt;em&gt;price&lt;/em&gt; properties to store the final product — burger — and its price correspondingly. Additionally, the class stores some methods with default implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;createBurger()&lt;/em&gt; — initialises a &lt;em&gt;Burger&lt;/em&gt; class object;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;getBurger()&lt;/em&gt; — returns the built burger result;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;setBurgerPrice()&lt;/em&gt; — sets the price for the burger object.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;BurgerBuilderBase&lt;/em&gt; also contain several abstract methods which must be implemented in the specific implementation classes of the burger builder: &lt;em&gt;addBuns()&lt;/em&gt;, &lt;em&gt;addCheese()&lt;/em&gt;, &lt;em&gt;addPatties()&lt;/em&gt;, &lt;em&gt;addSauces()&lt;/em&gt;, &lt;em&gt;addSeasoning()&lt;/em&gt; and &lt;em&gt;addVegetables()&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;BigMacBuilder&lt;/em&gt;, &lt;em&gt;CheeseburgerBuilder&lt;/em&gt;, &lt;em&gt;HamburgerBuilder&lt;/em&gt; and &lt;em&gt;McChickenBuilder&lt;/em&gt; are concrete builder classes that extend the abstract class &lt;em&gt;BurgerBuilderBase&lt;/em&gt; and implement its abstract methods.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;BurgerMaker&lt;/em&gt; is a director class that manages the burger’s build process. It contains a specific builder implementation as a &lt;em&gt;burgerBuilder&lt;/em&gt; property, &lt;em&gt;prepareBurger()&lt;/em&gt; method to build the burger and a &lt;em&gt;getBurger()&lt;/em&gt; method to return it. Also, the builder’s implementation could be changed using the &lt;em&gt;changeBurgerBuilder()&lt;/em&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;BuilderExample&lt;/em&gt; initialises and contains the &lt;em&gt;BurgerMaker&lt;/em&gt; class. Also, it references all the specific burger builders which could be changed at run-time using the UI dropdown selection.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ingredient
&lt;/h3&gt;

&lt;p&gt;An abstract class that stores the allergens, name fields and is extended by all of the ingredient classes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CUyFFTCz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d4qscc2svnc8iejy9d73.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CUyFFTCz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d4qscc2svnc8iejy9d73.png" alt="ingredient.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Concrete ingredients
&lt;/h3&gt;

&lt;p&gt;All of these classes represent a specific ingredient by extending the &lt;em&gt;Ingredient&lt;/em&gt; class and specifying an allergens’ list as well as the name value.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Big Mac Bun&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mGynyBW0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/box2rppwj16k9japf031.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mGynyBW0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/box2rppwj16k9japf031.png" alt="big_mac_bun.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regular Bun&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xn0JF9Bq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3z3ys4y4cstb05ncquqx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xn0JF9Bq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3z3ys4y4cstb05ncquqx.png" alt="regular_bun.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cheese&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x4W8vKxE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4i4jv9s4jlnmrzafl7cm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x4W8vKxE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4i4jv9s4jlnmrzafl7cm.png" alt="cheese.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grill Seasoning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eNGV82Mx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ws190zvruwohkbn5nksa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eNGV82Mx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ws190zvruwohkbn5nksa.png" alt="grill_seasoning.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Beef Patty&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hoEj0TVA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uv7vti9wobqc88pbsr4p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hoEj0TVA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uv7vti9wobqc88pbsr4p.png" alt="beef_patty.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;McChicken Patty&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DaiUvw30--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmmuzf5m8ortp6a5ucm5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DaiUvw30--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmmuzf5m8ortp6a5ucm5.png" alt="mc_chicken_patty.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Big Mac Sauce&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--umb-B_29--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bva2a4xic86pu8f8z08t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--umb-B_29--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bva2a4xic86pu8f8z08t.png" alt="big_mac_sauce.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ketchup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k9Ws6is8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ru622qkboroer7chtx6t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k9Ws6is8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ru622qkboroer7chtx6t.png" alt="ketchup.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mayonnaise&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kBm523HJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2xn32nvs8uj1ti30vcd7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kBm523HJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2xn32nvs8uj1ti30vcd7.png" alt="mayonnaise.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mustard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CGpN1ZTt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmedxm4pmqfvjg1jmxi5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CGpN1ZTt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pmedxm4pmqfvjg1jmxi5.png" alt="mustard.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Onions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CAYh7lAh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aysp2tjiw33nudlhaaal.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CAYh7lAh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aysp2tjiw33nudlhaaal.png" alt="onions.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pickle Slices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jPV1EA8Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sr47jbszpkwljmzakstg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jPV1EA8Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sr47jbszpkwljmzakstg.png" alt="pickle_slices.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shredded Lettuce&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OK9he1K2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/03ajyx1kwnlzor7kbldr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OK9he1K2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/03ajyx1kwnlzor7kbldr.png" alt="shredded_lettuce.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Burger
&lt;/h3&gt;

&lt;p&gt;A simple class to store information about the burger: its price and a list of ingredients it contains. Also, class methods, such as &lt;em&gt;getFormattedIngredients()&lt;/em&gt;, &lt;em&gt;getFormattedAllergens()&lt;/em&gt; and &lt;em&gt;getFormattedPrice()&lt;/em&gt;, returns these values in human-readable format.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5CwPdO_h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6w5h2trx4kio5s9t6l74.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5CwPdO_h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6w5h2trx4kio5s9t6l74.png" alt="burger.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  BurgerBuilderBase
&lt;/h3&gt;

&lt;p&gt;An abstract class that stores &lt;em&gt;burger&lt;/em&gt; and &lt;em&gt;price&lt;/em&gt; properties defines some default methods to create/return the burger object and set its price. Also, the class defines several abstract methods which must be implemented by the derived burger builder classes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eB53HgeQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t13lpm1f0mrirgopa1xw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eB53HgeQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t13lpm1f0mrirgopa1xw.png" alt="burger_builder_base.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Concrete builders
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;BigMacBuilder&lt;/em&gt; — builds a Big Mac using the following ingredients: &lt;em&gt;BigMacBun&lt;/em&gt;, &lt;em&gt;Cheese&lt;/em&gt;, &lt;em&gt;BeefPatty&lt;/em&gt;, &lt;em&gt;BigMacSauce&lt;/em&gt;, &lt;em&gt;GrillSeasoning&lt;/em&gt;, &lt;em&gt;Onions&lt;/em&gt;, &lt;em&gt;PickleSlices&lt;/em&gt; and &lt;em&gt;ShreddedLettuce&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mbiMFaoK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8rueoev2713qgnatwuxf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mbiMFaoK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8rueoev2713qgnatwuxf.png" alt="big_mac_builder.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;CheeseburgerBuilder&lt;/em&gt; — builds a cheeseburger using the following ingredients: &lt;em&gt;RegularBun&lt;/em&gt;, &lt;em&gt;Cheese&lt;/em&gt;, &lt;em&gt;BeefPatty&lt;/em&gt;, &lt;em&gt;Ketchup&lt;/em&gt;, &lt;em&gt;Mustard&lt;/em&gt;, &lt;em&gt;GrillSeasoning&lt;/em&gt;, &lt;em&gt;Onions&lt;/em&gt; and &lt;em&gt;PickleSlices&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vYphir44--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1bnl8pfaj1dkj4ne47y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vYphir44--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n1bnl8pfaj1dkj4ne47y.png" alt="cheeseburger_builder.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;HamburgerBuilder&lt;/em&gt; — builds a cheeseburger using the following ingredients: &lt;em&gt;RegularBun&lt;/em&gt;, &lt;em&gt;BeefPatty&lt;/em&gt;, &lt;em&gt;Ketchup&lt;/em&gt;, &lt;em&gt;Mustard&lt;/em&gt;, &lt;em&gt;GrillSeasoning&lt;/em&gt;, &lt;em&gt;Onions&lt;/em&gt; and &lt;em&gt;PickleSlices&lt;/em&gt;. &lt;em&gt;AddCheese()&lt;/em&gt; method is not relevant for this builder, hence the implementation is not provided (skipped).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IZZXuZTZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ur9zd65qkkdy8p2vngij.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IZZXuZTZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ur9zd65qkkdy8p2vngij.png" alt="hamburger_builder.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;McChickenBuilder&lt;/em&gt; — builds a cheeseburger using the following ingredients: &lt;em&gt;RegularBun&lt;/em&gt;, &lt;em&gt;McChickenPatty&lt;/em&gt;, &lt;em&gt;Mayonnaise&lt;/em&gt; and &lt;em&gt;ShreddedLettuce&lt;/em&gt;. &lt;em&gt;AddCheese()&lt;/em&gt; and &lt;em&gt;addSeasoning()&lt;/em&gt; methods are not relevant for this builder, hence the implementation is not provided (skipped).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jaT_SEij--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/89zrsli1jxatngilvl8c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jaT_SEij--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/89zrsli1jxatngilvl8c.png" alt="mc_chicken_builder.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  BurgerMaker
&lt;/h3&gt;

&lt;p&gt;A director class that manages the burger’s build process and returns the build result. A specific implementation of the builder is injected into the class via the constructor.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0gxzeozQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2duo3p2qy8fxa798zycr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0gxzeozQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2duo3p2qy8fxa798zycr.png" alt="burger_maker.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;First of all, a markdown file is prepared and provided as a pattern’s description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wdl0zrfw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/frveibk6wiui6r8vagj1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wdl0zrfw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/frveibk6wiui6r8vagj1.gif" alt="Builder Markdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;BuilderExample&lt;/em&gt; initialises and contains the &lt;em&gt;BurgerMaker&lt;/em&gt; class object. Also, it contains a list of &lt;em&gt;BurgerMenuItem&lt;/em&gt; objects/selection items which is used to select the specific builder using UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l96GdSn4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ufjzekv4d40suxp1r8p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l96GdSn4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4ufjzekv4d40suxp1r8p.png" alt="builder_example.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The director class &lt;em&gt;BurgerMaker&lt;/em&gt; does not care about the specific implementation of the builder — the specific implementation could be changed at run-time, hence providing a different result. Also, this kind of implementation allows easily adding a new builder (as long as it extends the &lt;em&gt;BurgerBuilderBase&lt;/em&gt; class) to provide another different product’s representation without breaking the existing code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HAYT6e4q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aenha1l1htz3uo84j52g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HAYT6e4q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aenha1l1htz3uo84j52g.gif" alt="Builder Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the example when a specific builder is selected from the dropdown list, a new product (burger) is created and its information is provided in the UI — price, ingredients and allergens.&lt;/p&gt;

&lt;p&gt;All of the code changes for the Builder design pattern and its example implementation could be found &lt;a href="https://github.com/mkobuolys/flutter-design-patterns/pull/19"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Contribution
&lt;/h2&gt;

&lt;p&gt;💖 or 🦄 this article to show your support and motivate me to write better!&lt;br&gt;
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.&lt;br&gt;
📢 Share this article with your friends, colleagues on social media.&lt;br&gt;
➕ Follow me on dev.to or any other social media platform.&lt;br&gt;
⭐ Star the &lt;a href="https://github.com/mkobuolys/flutter-design-patterns"&gt;Github&lt;/a&gt; repository.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>oop</category>
      <category>programming</category>
    </item>
    <item>
      <title>17 - Bridge</title>
      <dc:creator>Mangirdas Kazlauskas 🚀</dc:creator>
      <pubDate>Mon, 10 May 2021 12:37:29 +0000</pubDate>
      <link>https://dev.to/mkobuolys/17-bridge-4hbl</link>
      <guid>https://dev.to/mkobuolys/17-bridge-4hbl</guid>
      <description>&lt;p&gt;In the last article, I have analysed a structural design pattern that provides a way of changing the skin of an object without changing its guts — Decorator. In this article, I would like to analyse and implement another structural design pattern that tends to be relatively difficult to understand compared to the other design patterns, but at the same time is practical and useful — it is Bridge.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is the Bridge design pattern?&lt;/li&gt;
&lt;li&gt;Analysis&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Your Contribution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the Bridge design pattern?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9sdbdensbx2pn9b4hwu4.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9sdbdensbx2pn9b4hwu4.jpeg" alt="Dog Jumping Over A Bridge"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bridge&lt;/strong&gt;, also known as &lt;strong&gt;Handle/Body&lt;/strong&gt;, belongs to the category of structural design patterns. The intention of this design pattern is described in the &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns" rel="noopener noreferrer"&gt;GoF book&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Decouple an abstraction from its implementation so that the two can vary independently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The usual way for an abstraction to have one of several possible implementations is to use inheritance — an abstraction defines the interface while concrete subclasses implement it in different ways. However, this approach is not very flexible since it binds the implementation to abstraction at compile-time and makes it impossible to change the implementation at run-time. What if we want the implementation to be selected and exchanged at run-time?&lt;/p&gt;

&lt;p&gt;The Bridge design pattern separates an abstraction from its implementation so that the two can vary independently from each other. In this case, the abstraction uses another abstraction as its implementation instead of using the implementation directly. This relationship between an abstraction and its implementation (well, another abstraction, to be more specific) is called a &lt;em&gt;bridge — it bridges the abstraction and its implementation, letting them vary independently&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;If the &lt;em&gt;Abstraction&lt;/em&gt; and &lt;em&gt;Implementation&lt;/em&gt; terms sound too academic to you, imagine this: abstraction (or interface) is just a high-level layer for some particular entity. This layer is just an interface that is not supposed to do any real work on its own — it should delegate the work to the implementation layer. A good example of this is a GUI (graphical user interface) and OS (operating system). GUI is just a top-level layer for the user to communicate with the operating system, but it does not do any real work by itself — it just passes user commands (events) to the platform. And what is important about this, both GUI and OS could be extended separately from each other, e.g. a desktop application could have different views/panels/dashboards and at the same time support several APIs (could be run on Windows, Linux and macOS) — these two parts could vary independently. Sounds like a Bridge design pattern, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;The general structure of the Bridge design pattern looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7i3azdqkfri2vesba6u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7i3azdqkfri2vesba6u.png" alt="Bridge Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Abstraction&lt;/em&gt; — defines an interface for the abstraction and maintains a reference to an object of type &lt;em&gt;Implementation&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Refined abstraction&lt;/em&gt; — implements the &lt;em&gt;Abstraction&lt;/em&gt; interface and provides different variants of control logic;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Implementation&lt;/em&gt; — defines an interface for the implementation classes. An &lt;em&gt;Abstraction&lt;/em&gt; can only communicate with an &lt;em&gt;Implementation&lt;/em&gt; object via methods that are declared there;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Concrete implementations&lt;/em&gt; — implement the &lt;em&gt;Implementation&lt;/em&gt; interface and contain platform-specific code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Applicability
&lt;/h3&gt;

&lt;p&gt;The Bridge design pattern should be used when you want to divide a monolithic class with several functionality variants. In this case, the pattern allows splitting the class into several class hierarchies which could be changed independently — it simplifies code maintenance, smaller classes minimizes the risk of breaking existing code. A good example of this approach is when you want to use several different approaches in the persistence layer e.g. both database and file system persistence.&lt;/p&gt;

&lt;p&gt;The bridge design pattern should also be used when both the abstractions and their implementations should be extensible by subclassing — the pattern allows combining different abstractions and implementation and extending them independently.&lt;/p&gt;

&lt;p&gt;Finally, the bridge design pattern is a lifesaver when you need to be able to switch implementations at run-time. The pattern lets you replace the implementation object inside the abstraction — you can inject it via the constructor or just assign it as a new value to a field/property.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj74tn1j5byunyxig11pt.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj74tn1j5byunyxig11pt.gif" alt="Let's Get To Work"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will implement the persistence layer for our example using the Bridge design pattern for the implementation part.&lt;/p&gt;

&lt;p&gt;Let’s say your application uses the external SQL database (not the local SQLite option in your device, but the cloud one). Everything is fine until the wild connection problems appear. In this case, there are two options: you are not allowing users to use the application and provide a funny &lt;em&gt;connection lost&lt;/em&gt; screen or you can store the data in some kind of local storage and synchronise the data later when the connection is up again. Obviously, the second approach is more user friendly, but how to implement it?&lt;/p&gt;

&lt;p&gt;In the persistence layer, there are multiple repositories for each entity type. The repositories share a common interface — that is our abstraction. If you want to change the storage type (to use the local or cloud one) at run-time, these repositories could not reference the specific implementation of the storage, they should use some kind of abstraction shared between different types of storages. Well, we can build another abstraction (interface) on top of that which is then implemented by the specific storages. Now we connect our repositories’ abstraction with the storages’ interface — &lt;em&gt;voilà&lt;/em&gt;, that is how the Bridge design pattern is introduced into our application! Let’s check the class diagram first and then investigate some implementation details.&lt;/p&gt;

&lt;h3&gt;
  
  
  Class diagram
&lt;/h3&gt;

&lt;p&gt;The class diagram below shows the implementation of the Bridge design pattern:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffab7658k8xok7xkmv1ti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffab7658k8xok7xkmv1ti.png" alt="Bridge Implementation Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;EntityBase&lt;/em&gt; is an abstract class that is used as a base class for all the entity classes. The class contains an id property and a named constructor &lt;em&gt;EntityBase.fromJson&lt;/em&gt; to map the JSON object to the class field.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Customer&lt;/em&gt; and &lt;em&gt;Order&lt;/em&gt; are concrete entities that extend the abstract class &lt;em&gt;EntityBase&lt;/em&gt;. &lt;em&gt;Customer&lt;/em&gt; class contains &lt;em&gt;name&lt;/em&gt; and &lt;em&gt;email&lt;/em&gt; properties, &lt;em&gt;Customer.fromJson&lt;/em&gt; named constructor to map the JSON object to class fields and a &lt;em&gt;toJson()&lt;/em&gt; method to map class fields to the corresponding JSON map object. &lt;em&gt;Order&lt;/em&gt; class contain &lt;em&gt;dishes&lt;/em&gt; (a list of dishes of that order) and &lt;em&gt;total&lt;/em&gt; fields, a named constructor &lt;em&gt;Order.fromJson&lt;/em&gt; and a &lt;em&gt;toJson()&lt;/em&gt; method respectively.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;IRepository&lt;/em&gt; is an abstract class that is used as an interface for the repositories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;getAll()&lt;/em&gt; — returns all records from the repository;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;save()&lt;/em&gt; — saves an entity of type &lt;em&gt;EntityBase&lt;/em&gt; in the repository.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;CustomersRepository&lt;/em&gt; and &lt;em&gt;OrdersRepository&lt;/em&gt; are concrete repository classes that extend the abstract class &lt;em&gt;IRepository&lt;/em&gt; and implement its abstract methods. Also, these classes contain a storage property of type &lt;em&gt;IStorage&lt;/em&gt; which is injected into the repository via the constructor.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;IStorage&lt;/em&gt; is an abstract class that is used as an interface for the storages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;getTitle()&lt;/em&gt; — returns the title of the storage. The method is used in UI;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;fetchAll()&lt;/em&gt; — returns all the records of type &lt;em&gt;T&lt;/em&gt; from the storage;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;store()&lt;/em&gt; — stores a record of type &lt;em&gt;T&lt;/em&gt; in the storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;FileStorage&lt;/em&gt; and &lt;em&gt;SqlStorage&lt;/em&gt; are concrete storage classes that extend the abstract class &lt;em&gt;IStorage&lt;/em&gt; and implement its abstract methods. Additionally, &lt;em&gt;FileStorage&lt;/em&gt; class uses the &lt;em&gt;JsonHelper&lt;/em&gt; class and its static methods to serialise/deserialise JSON objects.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;BridgeExample&lt;/em&gt; initialises and contains both — customer and order — repositories which are used to retrieve the corresponding data. Additionally, the storage type of these repositories could be changed between the &lt;em&gt;FileStorage&lt;/em&gt; and &lt;em&gt;SqlStorage&lt;/em&gt; separately and at the run-time.&lt;/p&gt;

&lt;h3&gt;
  
  
  EntityBase
&lt;/h3&gt;

&lt;p&gt;An abstract class that stores the &lt;em&gt;id&lt;/em&gt; field and is extended by all of the entity classes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ctithg6qsvy4crpji5x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ctithg6qsvy4crpji5x.png" alt="entity_base.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Customer
&lt;/h3&gt;

&lt;p&gt;A simple class to store information about the customer: its &lt;em&gt;name&lt;/em&gt; and &lt;em&gt;email&lt;/em&gt;. Also, the constructor generates random values when initialising the &lt;em&gt;Customer&lt;/em&gt; object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9dfjz15h1obza39kox3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9dfjz15h1obza39kox3.png" alt="customer.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Order
&lt;/h3&gt;

&lt;p&gt;A simple class to store information about the order: a list of &lt;em&gt;dishes&lt;/em&gt; it contains and the &lt;em&gt;total&lt;/em&gt; price of the order. Also, the constructor generates random values when initialising the &lt;em&gt;Order&lt;/em&gt; object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyholfukqsrlthmvc2er2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyholfukqsrlthmvc2er2.png" alt="order.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  JsonHelper
&lt;/h3&gt;

&lt;p&gt;A helper classes used by the &lt;em&gt;FileStorage&lt;/em&gt; to serialise objects of type &lt;em&gt;EntityBase&lt;/em&gt; to JSON map objects and deserialise them from the JSON string.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmc2ef2h5twh1e82zznsx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmc2ef2h5twh1e82zznsx.png" alt="json_helper.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  IRepository
&lt;/h3&gt;

&lt;p&gt;An interface that defines methods to be implemented by the derived repository classes. Dart language does not support the interface as a class type, so we define an interface by creating an abstract class and providing a method header (name, return type, parameters) without the default implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24snqdxdl9n3mijvwrub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F24snqdxdl9n3mijvwrub.png" alt="irepository.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Concrete repositories
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;CustomersRepository&lt;/em&gt; — a specific implementation of the &lt;em&gt;IRepository&lt;/em&gt; interface to store customers’ data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7tq5dw5ghrwf1rdh849d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7tq5dw5ghrwf1rdh849d.png" alt="customers_repository.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;OrdersRepository&lt;/em&gt; — a specific implementation of the &lt;em&gt;IRepository&lt;/em&gt; interface to store orders’ data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftujw1admp4h9044vuvcb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftujw1admp4h9044vuvcb.png" alt="orders_repository.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  IStorage
&lt;/h3&gt;

&lt;p&gt;An interface that defines methods to be implemented by the derived storage classes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fji47bf176e5ngbevbppd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fji47bf176e5ngbevbppd.png" alt="istorage.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Concrete storages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;FileStorage&lt;/em&gt; — a specific implementation of the &lt;em&gt;IStorage&lt;/em&gt; interface to store an object in the storage as a file — this behaviour is mocked by storing an object as a JSON string.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xys6hfc5w7wjmgekqj3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0xys6hfc5w7wjmgekqj3.png" alt="file_storage.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;SqlStorage&lt;/em&gt; — a specific implementation of the &lt;em&gt;IStorage&lt;/em&gt; interface to store an object in the storage as an entity — this behaviour is mocked by using the Map data structure and appending entities of the same type to the list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11yrsr8fjzdk3nquvqnn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F11yrsr8fjzdk3nquvqnn.png" alt="sql_storage.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;First of all, a markdown file is prepared and provided as a pattern’s description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5s0zo5wv24ki2byplvpg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5s0zo5wv24ki2byplvpg.gif" alt="Bridge Markdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;BridgeExample&lt;/em&gt; contains a list of storages — instances of &lt;em&gt;SqlStorage&lt;/em&gt; and &lt;em&gt;FileStorage&lt;/em&gt; classes. Also, it initialises &lt;em&gt;Customer&lt;/em&gt; and &lt;em&gt;Order&lt;/em&gt; repositories. In the repositories the concrete type of storage could be interchanged by triggering the &lt;em&gt;onSelectedCustomerStorageIndexChanged()&lt;/em&gt; for the &lt;em&gt;CustomersRepository&lt;/em&gt; and &lt;em&gt;onSelectedOrderStorageIndexChanged()&lt;/em&gt; for the &lt;em&gt;OrdersRepository&lt;/em&gt; respectively.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp33o4g2z878df1sf2ovq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp33o4g2z878df1sf2ovq.png" alt="bridge_example.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The concrete repository does not care about the specific type of storage it uses as long as the storage implements the &lt;em&gt;IStorage&lt;/em&gt; interface and all of its abstract methods. As a result, the abstraction (repository) is separated from the implementor (storage) — the concrete implementation of the storage could be changed for the repository at run-time, the repository does not depend on its implementation details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrdp40thnbjlea4addr1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrdp40thnbjlea4addr1.gif" alt="Bridge Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the example, the storage type could be changed for each repository separately and at run-time — it would not be possible by using the simple class inheritance approach.&lt;/p&gt;

&lt;p&gt;All of the code changes for the Bridge design pattern and its example implementation could be found &lt;a href="https://github.com/MangirdasKazlauskas/flutter-design-patterns/pull/18" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Contribution
&lt;/h2&gt;

&lt;p&gt;💖 or 🦄 this article to show your support and motivate me to write better!&lt;br&gt;
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.&lt;br&gt;
📢 Share this article with your friends, colleagues on social media.&lt;br&gt;
➕ Follow me on dev.to or any other social media platform.&lt;br&gt;
⭐ Star the &lt;a href="https://github.com/mkobuolys/flutter-design-patterns" rel="noopener noreferrer"&gt;Github&lt;/a&gt; repository.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>oop</category>
      <category>programming</category>
    </item>
    <item>
      <title>16 - Decorator</title>
      <dc:creator>Mangirdas Kazlauskas 🚀</dc:creator>
      <pubDate>Mon, 03 May 2021 07:52:38 +0000</pubDate>
      <link>https://dev.to/mkobuolys/16-decorator-5dog</link>
      <guid>https://dev.to/mkobuolys/16-decorator-5dog</guid>
      <description>&lt;p&gt;Previously in the series, I have analysed a relatively simple, but very practical design pattern — Proxy. This time I would like to represent a design pattern, which, unlike the Strategy design pattern, extends the functionality of an object instead of exchanging it. It is a structural design pattern called Decorator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is the Decorator design pattern?&lt;/li&gt;
&lt;li&gt;Analysis&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Your Contribution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the Decorator design pattern?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsktn7guibf3xem8u90at.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsktn7guibf3xem8u90at.gif" alt="MIB Decorator"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decorator&lt;/strong&gt;, also known as &lt;strong&gt;Wrapper&lt;/strong&gt;, is a structural design pattern, which intention in the &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns" rel="noopener noreferrer"&gt;GoF book&lt;/a&gt; is described like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Decorator design pattern provides a way of &lt;em&gt;changing the skin of an object without changing its guts&lt;/em&gt; — it extends an object’s functionality by wrapping it in an object of a Decorator class, leaving the original object intact without modification. Therefore, the pattern helps support one of the &lt;a href="https://en.wikipedia.org/wiki/SOLID" rel="noopener noreferrer"&gt;SOLID&lt;/a&gt; principles — the Open/Closed Principle (classes should be closed for modification, but open for extension).&lt;/p&gt;

&lt;p&gt;The decorations (decorator classes) are independent of each other, hence they can be composed and chained together to add multiple behaviours (inception flashbacks, huh?). Also, another advantage is that this behaviour could be added at run-time, which leads to very flexible reuse of code, unlike using class inheritance. In addition to this, changing the order of decorators allows adding any combinations of responsibilities. However…&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With great power comes great responsibility&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The usage of the Decorator design pattern can also increase the complexity of code. To implement a specific component and make it modifiable at the run-time, not only you need to implement the Component, but also an indefinite amount of Decorator classes should be added to wrap it. A larger number of classes can sometimes be overwhelming, also debugging and testing the component wrapped by several additional classes does not make the development easier, too.&lt;/p&gt;

&lt;p&gt;Let’s move to the analysis and implementation parts to understand and learn the details about this pattern and how to implement it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;The general structure of the Decorator design pattern looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7q01ue7p3lw4zgevsym.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw7q01ue7p3lw4zgevsym.png" alt="Decorator Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Component&lt;/em&gt; — defines the interface for objects that can have responsibilities added to them dynamically;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Concrete Component&lt;/em&gt; — defines an object to which additional responsibilities can be added. It contains the basic behaviour which can be altered by decorators;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Base Decorator&lt;/em&gt; — has a field referencing a wrapped object which type should be declared as the component interface so it can contain both concrete components and decorators;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Concrete Decorators&lt;/em&gt; — adds responsibilities (extra behaviour) to the components dynamically;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Client&lt;/em&gt; — initialises the concrete component and wraps it in multiple layers of decorators extending its default behaviour dynamically.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Applicability
&lt;/h3&gt;

&lt;p&gt;The Decorator design pattern should be used when you need to add extra responsibilities to objects dynamically (at run-time) without affecting other objects. Since all the decorator objects implement the same interface, they can be used in various combinations and interchanged with each other.&lt;/p&gt;

&lt;p&gt;Also, this design pattern is useful when extension by subclassing is impractical or even not possible. For instance, sometimes a large number of independent extensions are possible and would produce a huge number of subclasses to support every combination — for those cases, the Decorator design pattern is a better option.&lt;/p&gt;

&lt;p&gt;Finally, the Decorator design pattern could be simply used to refactor the code base and split components with hard-wired extensions (compile-time implementation dependencies) into separate classes. As a result, code becomes more readable/maintainable (there would be less code in smaller classes) and at the same time more flexible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa26jdy388k3colbo1t2q.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa26jdy388k3colbo1t2q.gif" alt="Let's Do This"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Flutter community, it is quite popular to create food delivery/restaurant type of applications. With the implementation of the Decorator design pattern, we will jump into this &lt;em&gt;hype train&lt;/em&gt; and will build a prototype for the pizza delivery application, to be more specific, for the pizza selection from the menu.&lt;/p&gt;

&lt;p&gt;Let’s say we have a small restaurant which makes 3 kinds of pizza:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Margherita — Sauce, Mozzarella, Basil, Oregano, Pecorino, Olive Oil;&lt;/li&gt;
&lt;li&gt;Pepperoni — Sauce, Mozzarella, Pepperoni, Oregano;&lt;/li&gt;
&lt;li&gt;“Make-Your-Own” — any combination of pizza toppings from the list of Basil, Mozzarella, Olive Oil, Oregano, Pecorino, Pepperoni, and Sauce.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the pizzas are of the same size, pizza toppings have different prices.&lt;/p&gt;

&lt;p&gt;It is quite clear for the pizza Margherita or Pepperoni — the recipe is clear, you just need to add the necessary toppings and calculate the final price, easy peasy. However, for the custom pizza, it would be very impractical to prepare the pre-defined recipes for all the possible combinations — that’s just not how it works usually from the business point of view.&lt;/p&gt;

&lt;p&gt;For this problem, the Decorator design pattern is a great option since we can make the pizza toppings as separate decorator classes, use them to wrap the pizza base (the base component) and calculate the final price of the pizza based on the selected toppings. Let’s check the class diagram first and then implement the pattern.&lt;/p&gt;

&lt;h3&gt;
  
  
  Class diagram
&lt;/h3&gt;

&lt;p&gt;The class diagram below shows the implementation of the Decorator design pattern:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dc7hqlxmgs6gtgxm40j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dc7hqlxmgs6gtgxm40j.png" alt="Decorator Implementation Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Pizza&lt;/em&gt; defines a common interface for wrappers (decorators) and wrapped objects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;getDescription()&lt;/em&gt; — returns the description of the pizza;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;getPrice()&lt;/em&gt; — returns the price of the pizza.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;PizzaBase&lt;/em&gt; represents the component object which extends the &lt;em&gt;Pizza&lt;/em&gt; class and implements its abstract methods.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PizzaDecorator&lt;/em&gt; references the &lt;em&gt;Pizza&lt;/em&gt; object and forwards requests to it via the &lt;em&gt;getDescription()&lt;/em&gt; and &lt;em&gt;getPrice()&lt;/em&gt; methods.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Basil&lt;/em&gt;, &lt;em&gt;Mozzarella&lt;/em&gt;, &lt;em&gt;OliveOil&lt;/em&gt;, &lt;em&gt;Oregano&lt;/em&gt;, &lt;em&gt;Pecorino&lt;/em&gt;, &lt;em&gt;Pepperoni&lt;/em&gt; and &lt;em&gt;Sauce&lt;/em&gt; are concrete decorators extending the &lt;em&gt;PizzaDecorator&lt;/em&gt; class and overriding its default behaviour by adding some extra functionality/calculations of their own.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PizzaToppingData&lt;/em&gt; class stores information about the pizza topping’s selection chip used in the UI — its label and whether it is selected or not.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PizzaMenu&lt;/em&gt; class provides a &lt;em&gt;getPizzaToppingsDataMap()&lt;/em&gt; method to retrieve the pizza topping’s selection chip data. Also, &lt;em&gt;getPizza()&lt;/em&gt; method is defined to return the specific &lt;em&gt;Pizza&lt;/em&gt; object based on the selected index in the UI or the selected pizza toppings.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;DecoratorExample&lt;/em&gt; initialises and contains the &lt;em&gt;PizzaMenu&lt;/em&gt; class object to retrieve the selected &lt;em&gt;Pizza&lt;/em&gt; object based on the user’s selection in the UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pizza
&lt;/h3&gt;

&lt;p&gt;An abstract class of the &lt;em&gt;Pizza&lt;/em&gt; component that defines a common interface for concrete component and decorator objects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6ukpspajkbjva5rbljo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6ukpspajkbjva5rbljo.png" alt="pizza.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  PizzaBase
&lt;/h3&gt;

&lt;p&gt;A concrete component that extends the &lt;em&gt;Pizza&lt;/em&gt; class and implements its methods. An object of this class (its behaviour) gets decorated by the specific decorator classes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlvuj9yh40795i3aspo6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhlvuj9yh40795i3aspo6.png" alt="pizza_base.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  PizzaDecorator
&lt;/h3&gt;

&lt;p&gt;An abstract decorator class that maintains a reference to a component class and forwards requests to it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7i57wlyen534xdhmakqf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7i57wlyen534xdhmakqf.png" alt="pizza_decorator.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Concrete pizza decorators
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Basil&lt;/em&gt;, &lt;em&gt;Mozzarella&lt;/em&gt;, &lt;em&gt;OliveOil&lt;/em&gt;, &lt;em&gt;Oregano&lt;/em&gt;, &lt;em&gt;Pecorino&lt;/em&gt;, &lt;em&gt;Pepperoni&lt;/em&gt; and &lt;em&gt;Sauce&lt;/em&gt; are concrete decorator classes of the &lt;em&gt;Pizza&lt;/em&gt; component. Each of these classes wraps the pizza object and adds additional value for the final price in the &lt;em&gt;getPrice()&lt;/em&gt; method, also extends the final pizza’s description in the &lt;em&gt;getDescription()&lt;/em&gt; method.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basil:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvvd83lomz3mtxp0j9gx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxvvd83lomz3mtxp0j9gx.png" alt="basil.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mozzarella:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5cipmr56cux2wu0pod09.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5cipmr56cux2wu0pod09.png" alt="mozzarella.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Olive Oil:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71bic55ghe95fkox4dph.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F71bic55ghe95fkox4dph.png" alt="olive_oil.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Oregano:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0iliiqu5rh7vxjsgqmcj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0iliiqu5rh7vxjsgqmcj.png" alt="oregano.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pecorino:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxkppwz1l008rq0t33lvg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxkppwz1l008rq0t33lvg.png" alt="pecorino.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pepperoni:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mq3t5q8bamhef6g3tii.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7mq3t5q8bamhef6g3tii.png" alt="pepperoni.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sauce:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5l0d4leimn1kz1wk7iw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5l0d4leimn1kz1wk7iw.png" alt="sauce.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  PizzaToppingData
&lt;/h3&gt;

&lt;p&gt;A simple class that contains data used by the pizza topping’s selection chip in the UI. The data consists of the &lt;em&gt;label&lt;/em&gt; property and the current selection state (whether the chip is currently selected or not) which could be changed by using the &lt;em&gt;setSelected()&lt;/em&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw03edfkjnzot0w9uzian.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fw03edfkjnzot0w9uzian.png" alt="pizza_topping_data.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  PizzaMenu
&lt;/h3&gt;

&lt;p&gt;A simple class that provides a map of &lt;em&gt;PizzaToppingData&lt;/em&gt; objects via the &lt;em&gt;getPizzaToppingsDataMap()&lt;/em&gt; method for the pizza toppings selection in UI. Also, the class defines a &lt;em&gt;getPizza()&lt;/em&gt; method which returns a &lt;em&gt;Pizza&lt;/em&gt; object that is built by using the pre-defined concrete decorator classes based on the pizza recipe — Margherita, Pepperoni or custom (based on the selected pizza toppings).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwd7lfmu8824sf7bzsx3s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwd7lfmu8824sf7bzsx3s.png" alt="pizza_menu.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This class (to be more specific, &lt;em&gt;getMargherita()&lt;/em&gt;, &lt;em&gt;getPepperoni()&lt;/em&gt; and &lt;em&gt;getCustom()&lt;/em&gt; methods) represents the main idea of the decorator design pattern — a base component class is instantiated and then wrapped by the concrete decorator classes, hence extending the base class and its behaviour. As a result, it is possible to use wrapper classes and add or remove responsibilities from an object at runtime, for instance, as it is used in the &lt;em&gt;getCustom()&lt;/em&gt; method where the appropriate decorator classes are used based on the selected pizza toppings data in the UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;First of all, a markdown file is prepared and provided as a pattern’s description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faoepnh7nvdxixkbscak3.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faoepnh7nvdxixkbscak3.gif" alt="Decorator Markdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;DecoratorExample&lt;/em&gt; contains the &lt;em&gt;PizzaMenu&lt;/em&gt; object which is used to get the specific &lt;em&gt;Pizza&lt;/em&gt; object based on the user’s selection. Also, all the logic related to the decorator’s design pattern and its implementation is extracted to the &lt;em&gt;PizzaMenu&lt;/em&gt; class, the &lt;em&gt;DecoratorExample&lt;/em&gt; widget only uses it to retrieve the necessary data to be represented in the UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F55hwnuhwat2ejdd4z4ch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F55hwnuhwat2ejdd4z4ch.png" alt="decorator_example.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The final result looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ebb5tyjx52ghfgtxv1g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ebb5tyjx52ghfgtxv1g.gif" alt="Decorator Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the example when selecting any of the pre-defined recipes, the final price of the pizza is recalculated as well as the description of its toppings is provided. Also, for the custom pizza, the price is recalculated every time a topping is selected or deselected, the pizza’s description is updated, too.&lt;/p&gt;

&lt;p&gt;All of the code changes for the Decorator design pattern and its example implementation could be found &lt;a href="https://github.com/mkobuolys/flutter-design-patterns/pull/17" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Contribution
&lt;/h2&gt;

&lt;p&gt;💖 or 🦄 this article to show your support and motivate me to write better!&lt;br&gt;
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.&lt;br&gt;
📢 Share this article with your friends, colleagues on social media.&lt;br&gt;
➕ Follow me on dev.to or any other social media platform.&lt;br&gt;
⭐ Star the &lt;a href="https://github.com/mkobuolys/flutter-design-patterns" rel="noopener noreferrer"&gt;Github&lt;/a&gt; repository.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>oop</category>
      <category>programming</category>
    </item>
    <item>
      <title>15 - Proxy</title>
      <dc:creator>Mangirdas Kazlauskas 🚀</dc:creator>
      <pubDate>Mon, 26 Apr 2021 11:01:04 +0000</pubDate>
      <link>https://dev.to/mkobuolys/15-proxy-38ac</link>
      <guid>https://dev.to/mkobuolys/15-proxy-38ac</guid>
      <description>&lt;p&gt;In the last article, I have analysed a relatively simple design pattern comparing to the other patterns in the series — Prototype. In this article, I would like to analyse and implement a structural design pattern that is very practical and could be used in a lot of cases when developing applications with Dart and Flutter — it is Proxy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is the Proxy design pattern?&lt;/li&gt;
&lt;li&gt;Analysis&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Your Contribution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the Proxy design pattern?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ofgRHkQe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j1y2s6j8zr5lmvp2haf0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ofgRHkQe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j1y2s6j8zr5lmvp2haf0.jpeg" alt="If The Proxy Service Were A Person"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Proxy&lt;/strong&gt;, also known as &lt;strong&gt;Surrogate&lt;/strong&gt;, belongs to the category of structural design patterns. The intention of this design pattern is described in the &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns"&gt;GoF book&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Provide a surrogate or placeholder for another object to control access to it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The key idea in this pattern is to work through a separate proxy object that performs additional functionality when accessing an (already existing) object. For instance, the user’s rights should be validated before accessing the object or the object’s creation is very expensive so it makes sense to defer its creation until the object is actually needed. Also, if you need to execute something either before or after the primary logic of the class, the proxy lets you do this without changing that class. Since the proxy implements the same interface as the original class, it can be passed to any client that expects a real service object.&lt;/p&gt;

&lt;p&gt;To understand the Proxy design pattern better, let’s dive in by analysing its structure, types and implementation in more detail!&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;The general structure of the Proxy design pattern looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zMkGgEWt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94jgpjvojsoxs8km1sjr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zMkGgEWt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/94jgpjvojsoxs8km1sjr.png" alt="Proxy Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;ServiceInterface&lt;/em&gt; — defines the common interface for &lt;em&gt;Service&lt;/em&gt; and &lt;em&gt;Proxy&lt;/em&gt; that the proxy service could be used instead of the real one;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Service&lt;/em&gt; — defines the real object which contains some useful business logic. This is the service that the proxy represents;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Proxy&lt;/em&gt; — implements the same interface as the real service. Also, has a reference field that points to a service object which allows controlling access to it. The &lt;em&gt;Proxy&lt;/em&gt; class may be responsible for creating and deleting the real service’s object;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Client&lt;/em&gt; — should work with both services and proxies via the same interface. This way you can pass a proxy into any code that expects a service object.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Applicability
&lt;/h3&gt;

&lt;p&gt;There are dozens of ways to utilize the Proxy pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lazy initialization (&lt;strong&gt;virtual proxy&lt;/strong&gt;) — instead of creating the object when the app launches, you can delay the object’s initialization to a time when it’s really needed;&lt;/li&gt;
&lt;li&gt;Access control (&lt;strong&gt;protection proxy&lt;/strong&gt;) — the proxy can pass the request to the service object only if the client’s credentials match some criteria;&lt;/li&gt;
&lt;li&gt;Local execution of a remote service (&lt;strong&gt;remote proxy&lt;/strong&gt;) — the proxy passes the client request over the network, handling all of the nasty details of working with the network;&lt;/li&gt;
&lt;li&gt;Logging requests (&lt;strong&gt;logging proxy&lt;/strong&gt;) — the proxy can log each request before passing it to the service;&lt;/li&gt;
&lt;li&gt;Caching request results (&lt;strong&gt;caching proxy&lt;/strong&gt;) — the proxy can implement caching for recurring requests that always yield the same results. The proxy may use the parameters of requests as the cache keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aYoJEfKL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k18sta2yyup97vmpf0t2.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aYoJEfKL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/k18sta2yyup97vmpf0t2.gif" alt="I'm Ready"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the following example of the Proxy design pattern, we will implement the &lt;strong&gt;caching proxy&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In my opinion, in any application which loads resources from an external service, it is quite a common problem to improve the performance and reduce load times of the data. It is possible to optimise and at least partially resolve it by implementing the caching layer.&lt;/p&gt;

&lt;p&gt;Let’s say we have a list of customers with some basic information — customer’s id and name. Any additional customer data should be loaded from an external web service. When providing the general list of customers, additional information is not loaded nor used. However, it could be accessed by selecting a specific customer and loading its data from the customer details service. To reduce the number of requests sent to the external service, it makes sense to introduce a caching layer to the application and provide the already loaded information from the cache for future requests.&lt;/p&gt;

&lt;p&gt;To achieve this, the Proxy design pattern is a great choice! Let’s check the class diagram first and then implement a proxy for the customer details service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Class diagram
&lt;/h3&gt;

&lt;p&gt;The class diagram below shows the implementation of the Proxy design pattern:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dAoF1FT0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ypgbsuupt2g7syjr9p4y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dAoF1FT0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ypgbsuupt2g7syjr9p4y.png" alt="Proxy Implementation Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Customer&lt;/em&gt; class is used to store information about the customer. One of its properties is the &lt;em&gt;CustomerDetails&lt;/em&gt; which stores additional data about the customer e.g. its email, hobby and position.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ICustomerDetailsService&lt;/em&gt; is an abstract class that is used as an interface for the customer details service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;getCustomerDetails()&lt;/em&gt; — an abstract method that returns details for the specific customer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;CustomerDetailsService&lt;/em&gt; is the “real” customer details service that implements the abstract class &lt;em&gt;ICustomerDetailsService&lt;/em&gt; and its methods.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;CustomerDetailsServiceProxy&lt;/em&gt; is a proxy service that contains the cache (dictionary object) and sends the request to the real &lt;em&gt;CustomerDetailsService&lt;/em&gt; only if the customer details object is not available in the cache.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ProxyExample&lt;/em&gt; initialises and contains the proxy object of the real customer details service. When a user selects the option to see more details about the customer, the dialog window appears and loads details about the customer. If the details object is already stored inside the cache, the proxy service returns that object instantly. Otherwise, a request is sent to the real customer details service and the details object is returned from there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Customer
&lt;/h3&gt;

&lt;p&gt;A simple class to store information about the customer: its id, name and details. Also, the constructor generates random id and name values when initialising the Customer object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zTUoE5hT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ryfe6ugpbbaqvh4ikvnb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zTUoE5hT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ryfe6ugpbbaqvh4ikvnb.png" alt="customer.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  CustomerDetails
&lt;/h3&gt;

&lt;p&gt;A simple class to store information about customer details: id to map the details information with the corresponding customer, e-mail address, hobby and the current position (job title).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xr2VGFKH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tka0rle31ly84czgowx4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xr2VGFKH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tka0rle31ly84czgowx4.png" alt="customer_details.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ICustomerDetailsService
&lt;/h3&gt;

&lt;p&gt;An interface that defines the &lt;em&gt;getCustomerDetails()&lt;/em&gt; method to be implemented by the customer details service and its proxy. Dart language does not support the interface as a class type, so we define an interface by creating an abstract class and providing a method header (name, return type, parameters) without the default implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--52U8Mhig--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ixvpodo2gijb62hysr6g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--52U8Mhig--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ixvpodo2gijb62hysr6g.png" alt="icustomer_details_service.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  CustomerDetailsService
&lt;/h3&gt;

&lt;p&gt;A specific implementation of the &lt;em&gt;ICustomerDetailsService&lt;/em&gt; interface — the real customer details service. The &lt;em&gt;getCustomerDetails()&lt;/em&gt; method mocks the real behaviour of the service and generates random values of customer details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0-4DbyGl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8umz1dkarvfzg3o1pmr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0-4DbyGl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x8umz1dkarvfzg3o1pmr.png" alt="customer_details_service.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  CustomerDetailsServiceProxy
&lt;/h3&gt;

&lt;p&gt;A specific implementation of the &lt;em&gt;ICustomerDetailsService&lt;/em&gt; interface — a proxy for the real customer details service. Before making a call to the customer details service, the proxy service checks whether the customer details are already fetched and saved in the cache. If yes, the customer details object is returned from the cache, otherwise, a request is sent to the real customer service and its value is saved to the cache and returned.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4TcaKBFJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hgt58y1u544mvl5188r0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4TcaKBFJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hgt58y1u544mvl5188r0.png" alt="customer_details_service_proxy.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;First of all, a markdown file is prepared and provided as a pattern’s description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_6InU4Lb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/umu5bt3wbw4i0ny9tujn.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_6InU4Lb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/umu5bt3wbw4i0ny9tujn.gif" alt="Proxy Markdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ProxyExample&lt;/em&gt; contains the proxy object of the real customer details service. When the user wants to see customer details, the &lt;em&gt;showDialog()&lt;/em&gt; method is triggered (via the &lt;em&gt;showCustomerDetails()&lt;/em&gt; method) which opens the dialog window of type &lt;em&gt;CustomerDetailsDialog&lt;/em&gt; and passes the proxy object via its constructor as well as the selected customer’s information — the &lt;em&gt;Customer&lt;/em&gt; object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WYrM0wgO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5zq4b72x3jfbovb6a6ea.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WYrM0wgO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5zq4b72x3jfbovb6a6ea.png" alt="proxy_example.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;CustomerDetailsDialog&lt;/em&gt; class uses the passed proxy service on its state’s initialisation, hence loading details of the selected customer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jYtlKu78--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn4tp01a8119o4fixxf1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jYtlKu78--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sn4tp01a8119o4fixxf1.png" alt="customer_details_dialog.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;CustomerDetailsDialog&lt;/em&gt; class does not care about the specific type of customer details service as long as it implements the &lt;em&gt;ICustomerDetailsService&lt;/em&gt; interface. As a result, an additional caching layer could be used by sending the request through the proxy service, hence improving the general performance of the application, possibly saving some additional network data and reducing the number of requests sent to the real customer details service as well. Also, if you want to call the real customer details service directly, you can just simply pass it via the &lt;em&gt;CustomerDetailsDialog&lt;/em&gt; constructor — no additional changes are needed in the UI code since both the real service and its proxy implements the same interface.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4_kcE0x4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yig6zl870w7c8zoh2s1z.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4_kcE0x4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yig6zl870w7c8zoh2s1z.gif" alt="Proxy Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the example, when trying to load the specific customer’s details for the first time, it takes some time for the information to load from the service. However, when the same information is accessed once again, it is provided from the cache stored in the proxy service, hence the request is not sent to the real customer details service — the customer details information is provided instantly.&lt;/p&gt;

&lt;p&gt;All of the code changes for the Proxy design pattern and its example implementation could be found &lt;a href="https://github.com/MangirdasKazlauskas/flutter-design-patterns/pull/16"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Contribution
&lt;/h2&gt;

&lt;p&gt;💖 or 🦄 this article to show your support and motivate me to write better!&lt;br&gt;
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.&lt;br&gt;
📢 Share this article with your friends, colleagues on social media.&lt;br&gt;
➕ Follow me on dev.to or any other social media platform.&lt;br&gt;
⭐ Star the &lt;a href="https://github.com/mkobuolys/flutter-design-patterns"&gt;Github&lt;/a&gt; repository.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>oop</category>
      <category>programming</category>
    </item>
    <item>
      <title>14 - Prototype</title>
      <dc:creator>Mangirdas Kazlauskas 🚀</dc:creator>
      <pubDate>Mon, 19 Apr 2021 07:38:47 +0000</pubDate>
      <link>https://dev.to/mkobuolys/14-prototype-kc7</link>
      <guid>https://dev.to/mkobuolys/14-prototype-kc7</guid>
      <description>&lt;p&gt;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 that belongs to the category of creational design patterns — the Prototype.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is the Prototype design pattern?&lt;/li&gt;
&lt;li&gt;Analysis&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Your Contribution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the Prototype design pattern?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h1QUcvV5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xv1ew4rs5mnb3frcifyr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h1QUcvV5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xv1ew4rs5mnb3frcifyr.gif" alt="How Cloning Works"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Prototype&lt;/strong&gt; is a &lt;strong&gt;creational&lt;/strong&gt; design pattern, which intention in the &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns"&gt;GoF book&lt;/a&gt; is described like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;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 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Let’s move to the analysis and implementation parts to understand and learn the details about this pattern and how to implement it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;The general structure of the Prototype design pattern looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sLwQ_49l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2kayl203erny6pz0i5di.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sLwQ_49l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2kayl203erny6pz0i5di.png" alt="Prototype Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Prototype&lt;/em&gt; — declares an interface for cloning itself. Usually, it is a single &lt;em&gt;clone&lt;/em&gt; method, but there could be other methods declared/defined if needed;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;ConcretePrototype&lt;/em&gt; — 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.;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;SubclassPrototype&lt;/em&gt; — has the same purpose as the &lt;em&gt;ConcretePrototype&lt;/em&gt;, but could also extend the base class by defining additional properties, behaviour, etc.;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Client&lt;/em&gt; — creates a new object by asking a prototype to clone itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Applicability
&lt;/h3&gt;

&lt;p&gt;The Prototype design pattern should be used when your code should not depend on the concrete classes of objects that you need to copy. The Prototype pattern provides the client code with a general interface for working with all objects that support cloning. This interface makes the client code independent from the concrete classes of objects that it clones.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--smoXZmpX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l90uh0pgl1ppif3c7ips.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--smoXZmpX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l90uh0pgl1ppif3c7ips.gif" alt="Let's Make It Happen"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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 that 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.&lt;/p&gt;

&lt;p&gt;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?&lt;/p&gt;

&lt;h3&gt;
  
  
  Class diagram
&lt;/h3&gt;

&lt;p&gt;The class diagram below shows the implementation of the Prototype design pattern:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ac-dtgcP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zbkogqv0p3fppthh79nz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ac-dtgcP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zbkogqv0p3fppthh79nz.png" alt="Prototype Implementation Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Shape&lt;/em&gt; is an abstract class that is used as a base class for all the specific shapes. The class contains a &lt;em&gt;color&lt;/em&gt; property and defines several abstract methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;clone()&lt;/em&gt; — an abstract method to clone (copy) the specific shape;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;randomiseProperties()&lt;/em&gt; — an abstract method to randomise property values of the shape;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;render()&lt;/em&gt; — an abstract method to render the shape. The method is used in UI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Circle&lt;/em&gt; and &lt;em&gt;Rectangle&lt;/em&gt; are concrete shape classes that extend the abstract class Shape and implement its abstract methods.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Shape
&lt;/h3&gt;

&lt;p&gt;An abstract class stores the shape’s colour and defines several abstract methods. Also, this class contains several constructors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Shape()&lt;/em&gt; — a basic constructor to create a shape object with the provided colour value;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Shape.clone()&lt;/em&gt; — a named constructor to create a shape object as a copy of the provided &lt;em&gt;Shape&lt;/em&gt; value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8KuU52NI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pka4tz7sasrhfiouqfmw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8KuU52NI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pka4tz7sasrhfiouqfmw.png" alt="shape.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Shapes
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Circle&lt;/em&gt; — a specific class that defines the shape of a circle. The class defines a &lt;em&gt;radius&lt;/em&gt; property, extends the &lt;em&gt;Shape&lt;/em&gt; class and implements its abstract methods &lt;em&gt;clone()&lt;/em&gt;, &lt;em&gt;randomiseProperties()&lt;/em&gt; and &lt;em&gt;render()&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HnxaseQD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ktxg4p5hquqfeu7hfvhm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HnxaseQD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ktxg4p5hquqfeu7hfvhm.png" alt="circle.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Rectangle&lt;/em&gt; — a specific class that defines the shape of a rectangle. The class defines &lt;em&gt;height&lt;/em&gt; and &lt;em&gt;width&lt;/em&gt; properties, extends the &lt;em&gt;Shape&lt;/em&gt; class and implements its abstract methods &lt;em&gt;clone()&lt;/em&gt;, &lt;em&gt;randomiseProperties()&lt;/em&gt; and &lt;em&gt;render()&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L14NlcLA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zmlr55pqq21duw8xzyku.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L14NlcLA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zmlr55pqq21duw8xzyku.png" alt="rectangle.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;First of all, a markdown file is prepared and provided as a pattern’s description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--a_x1OXxV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yet8rdjp4txjmzrjyksc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a_x1OXxV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yet8rdjp4txjmzrjyksc.gif" alt="Prototype Markdown"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D6TDf1h3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fqucdr8ggmgoulp1egx8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D6TDf1h3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fqucdr8ggmgoulp1egx8.png" alt="prototype_example.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;PrototypeExample&lt;/em&gt; does not care about the specific type of shape object as long as it extends the &lt;em&gt;Shape&lt;/em&gt; abstract class and implements all of its abstract methods. As a result, the &lt;em&gt;clone()&lt;/em&gt; 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 &lt;em&gt;radius&lt;/em&gt; property which is specific for that particular shape, while the rectangle has two different properties — &lt;em&gt;height&lt;/em&gt; and &lt;em&gt;width&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--syPAAFtx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mxw2fe3321u31iqoz8f6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--syPAAFtx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mxw2fe3321u31iqoz8f6.gif" alt="Prototype Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;All of the code changes for the Prototype design pattern and its example implementation could be found &lt;a href="https://github.com/mkobuolys/flutter-design-patterns/pull/15"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Contribution
&lt;/h2&gt;

&lt;p&gt;💖 or 🦄 this article to show your support and motivate me to write better!&lt;br&gt;
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.&lt;br&gt;
📢 Share this article with your friends, colleagues on social media.&lt;br&gt;
➕ Follow me on dev.to or any other social media platform.&lt;br&gt;
⭐ Star the &lt;a href="https://github.com/mkobuolys/flutter-design-patterns"&gt;Github&lt;/a&gt; repository.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>oop</category>
      <category>programming</category>
    </item>
    <item>
      <title>13 - Memento</title>
      <dc:creator>Mangirdas Kazlauskas 🚀</dc:creator>
      <pubDate>Tue, 13 Apr 2021 15:04:31 +0000</pubDate>
      <link>https://dev.to/mkobuolys/13-memento-2kpm</link>
      <guid>https://dev.to/mkobuolys/13-memento-2kpm</guid>
      <description>&lt;p&gt;In the last article, I have analysed a relatively popular design pattern — Command. In this article, I would like to analyse and implement a behavioural design pattern that works pretty well alongside the Command pattern — it is Memento.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is the Memento design pattern?&lt;/li&gt;
&lt;li&gt;Analysis&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Your Contribution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the Memento design pattern?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IjCmNYwJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z14lgamkip5zfe53oxn6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IjCmNYwJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z14lgamkip5zfe53oxn6.gif" alt="Making A Snapshot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memento&lt;/strong&gt;, also known as &lt;strong&gt;Token&lt;/strong&gt;, belongs to the category of behavioural design patterns. The intention of this design pattern is described in the &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns"&gt;GoF book&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Without violating encapsulation, capture and externalize an object’s internal state so that the object can be restored to this state later.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The key idea in this pattern is to make an object (&lt;strong&gt;originator&lt;/strong&gt;) itself responsible for saving and restoring its internal state. The internal state (a snapshot of it) is saved in another object — &lt;strong&gt;memento&lt;/strong&gt;. The undo mechanism will request a memento from the originator when it needs to restore the originator’s internal state. Clients (&lt;strong&gt;caretaker&lt;/strong&gt;) that are responsible for saving and restoring an originator’s internal state stores a list of memento objects so that a memento can be passed back to the originator to restore to a previous state. However, the caretaker itself isn’t permitted to access or modify a memento — only the originator object which created the specific memento is allowed to do that.&lt;/p&gt;

&lt;p&gt;To understand the Memento design pattern better, let’s dive in by analysing its structure and implementation in more detail!&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;The general structure of the Memento design pattern looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k6tLqv8f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/36bdnv54298yvm5h32h9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6tLqv8f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/36bdnv54298yvm5h32h9.png" alt="Memento Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Memento&lt;/em&gt; — an interface which restricts access to the &lt;em&gt;ConcreteMemento’s&lt;/em&gt; fields, only declares methods related to the memento’s metadata and which is used by the &lt;em&gt;Caretaker&lt;/em&gt; to work with &lt;em&gt;ConcreteMemento&lt;/em&gt; object;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;ConcreteMemento&lt;/em&gt; — stores an &lt;em&gt;Originator’s&lt;/em&gt; internal state. Also, protects against access by objects other than the &lt;em&gt;Originator&lt;/em&gt; which has created the &lt;em&gt;ConcreteMemento&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Caretaker&lt;/em&gt; — is responsible for the &lt;em&gt;Memento’s&lt;/em&gt; safekeeping and never operates or examines the contents of a &lt;em&gt;Memento&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Originator&lt;/em&gt; — creates a &lt;em&gt;ConcreteMemento&lt;/em&gt; containing a snapshot of its current internal state. Also, provides the &lt;em&gt;restore()&lt;/em&gt; method to restore the internal state using the &lt;em&gt;ConcreteMemento&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Applicability
&lt;/h3&gt;

&lt;p&gt;The Memento design pattern should be used when you want to produce snapshots of the object’s state to be able to restore a previous state of the object. The Memento pattern lets you make full copies of an object’s state, including private fields, and store them separately from the object.&lt;/p&gt;

&lt;p&gt;Also, the pattern could be used for safety reasons — when direct access to the object’s fields/getters/setters violates its encapsulation. The Memento makes the object itself responsible for creating a snapshot of its state. No other object can read the snapshot, making the original object’s state data safe and secure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zojLrDVL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/myu1px85tm5sotr81rof.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zojLrDVL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/myu1px85tm5sotr81rof.gif" alt="I'll Make It Work"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To implement the Memento design pattern and show its advantages, we will work further on the Command design pattern’s example. So if you have missed the previous article, I strongly recommend checking the implementation part of it now.&lt;/p&gt;

&lt;p&gt;The main idea of the example remains the same — we will create a very simple, fake graphics editor. To simplify the Command design pattern’s part, only one command is created and available in the example’s UI — RandomisePropertiesCommand. This command randomises all the properties of the Shape object — height, width and colour — which acts as a state of our example.&lt;/p&gt;

&lt;p&gt;Obviously, what is different from the previous implementation — the Memento design pattern is added. When implementing the Command design pattern’s example, we stored its state (Shape object) in the example component itself. This time, the state is stored inside the Originator object and could be manipulated only by it. The &lt;em&gt;RandomisePropertiesCommand&lt;/em&gt; acts as a caretaker object and stores the previous snapshot of the originator’s state in the &lt;em&gt;backup&lt;/em&gt; property. The &lt;em&gt;backup&lt;/em&gt; property is nothing else than the &lt;em&gt;Memento&lt;/em&gt; object which is created by the originator before executing the command.&lt;/p&gt;

&lt;p&gt;As a result of using the Memento design pattern, the example’s state is encapsulated and moved outside from the example component. Also, the previous state could be restored from its Memento snapshot on &lt;em&gt;undo()&lt;/em&gt; operation of the command. In this case, the Memento design pattern extends the Command design pattern and collaborates with it really well.&lt;/p&gt;

&lt;p&gt;Before implementing the Memento design pattern and integrating it inside our example, let’s check the class diagram first and investigate its components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Class diagram
&lt;/h3&gt;

&lt;p&gt;The class diagram below shows the implementation of the Memento design pattern:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qS8zKDJz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pz9rse2zrg8x62x780ne.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qS8zKDJz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pz9rse2zrg8x62x780ne.png" alt="Memento Implementation Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ICommand&lt;/em&gt; is an abstract class that is used as an interface for the specific command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;execute()&lt;/em&gt; — an abstract method that executes the command;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;undo()&lt;/em&gt; — an abstract method that undoes the command and returns the state to the previous snapshot of it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;RandomisePropertiesCommand&lt;/em&gt; is a concrete command which implements the abstract class &lt;em&gt;ICommand&lt;/em&gt; and its methods.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;CommandHistory&lt;/em&gt; is a simple class that stores a list of already executed commands (&lt;em&gt;commandList&lt;/em&gt;) and provides methods to add a new command to the command history list (&lt;em&gt;add()&lt;/em&gt;) and undo the last command from that list (&lt;em&gt;undo()&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;IMemento&lt;/em&gt; is an abstract class that is used as an interface for the specific memento class:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;getState()&lt;/em&gt; — an abstract method that returns the snapshot of the internal originator’s state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Memento&lt;/em&gt; is a class that acts as a snapshot of the originator’s internal state which is stored in the &lt;em&gt;state&lt;/em&gt; property and returned via the &lt;em&gt;getState()&lt;/em&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Shape&lt;/em&gt; is a simple data class that is used as an internal originator’s state. It stores multiple properties defining the shape presented in UI: &lt;em&gt;color&lt;/em&gt;, &lt;em&gt;height&lt;/em&gt; and &lt;em&gt;width&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originator&lt;/em&gt; — a simple class that contains its internal state and stores the snapshot of it to the &lt;em&gt;Memento&lt;/em&gt; object using the &lt;em&gt;createMemento()&lt;/em&gt; method. Also, the originator’s state could be restored from the provided &lt;em&gt;Memento&lt;/em&gt; object using the &lt;em&gt;restore()&lt;/em&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;MementoExample&lt;/em&gt; initializes and contains &lt;em&gt;CommandHistory&lt;/em&gt;, &lt;em&gt;Originator&lt;/em&gt; objects. Also, this component contains a &lt;em&gt;PlatformButton&lt;/em&gt; widget that has the command of &lt;em&gt;RandomisePropertiesCommand&lt;/em&gt; assigned to it. When the button is pressed, the command is executed and added to the command history list stored in &lt;em&gt;CommandHistory&lt;/em&gt; object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shape
&lt;/h3&gt;

&lt;p&gt;A simple class to store information about the shape: its color, height and width. Also, this class contains several constructors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Shape()&lt;/em&gt; — a basic constructor to create a shape object with provided values;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Shape.initial()&lt;/em&gt; — a named constructor to create a shape object with pre-defined initial values;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Shape.copy()&lt;/em&gt; — a named constructor to create a shape object as a copy of the provided &lt;em&gt;Shape&lt;/em&gt; value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YqZtEWSn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g1h3jiq639hboovopaiy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YqZtEWSn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g1h3jiq639hboovopaiy.png" alt="shape.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ICommand
&lt;/h3&gt;

&lt;p&gt;An interface that defines methods to be implemented by the specific command classes. Dart language does not support the interface as a class type, so we define an interface by creating an abstract class and providing a method header (name, return type, parameters) without the default implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ATN3F0No--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twruc9ca3zye683ka1k8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ATN3F0No--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twruc9ca3zye683ka1k8.png" alt="icommand.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  RandomisePropertiesCommand
&lt;/h3&gt;

&lt;p&gt;A specific implementation of the command that sets all the properties of the &lt;em&gt;Shape&lt;/em&gt; object stored in the &lt;em&gt;Originator&lt;/em&gt; to random values. Also, the class implements the &lt;em&gt;undo&lt;/em&gt; operation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g4EzBJQU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/39es085h1b84e8gvz34o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g4EzBJQU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/39es085h1b84e8gvz34o.png" alt="randomise_properties_command.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  CommandHistory
&lt;/h3&gt;

&lt;p&gt;A simple class that stores a list of already executed commands. Also, this class provides &lt;em&gt;isEmpty&lt;/em&gt; getter method to return true if the command history list is empty. A new command could be added to the command history list via the &lt;em&gt;add()&lt;/em&gt; method and the last command could be undone using the &lt;em&gt;undo()&lt;/em&gt; method (if the command history list is not empty).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--k2XJi64V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/09iijyym1ykrbvxkt62y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k2XJi64V--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/09iijyym1ykrbvxkt62y.png" alt="command_history.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  IMemento
&lt;/h3&gt;

&lt;p&gt;An interface that defines the &lt;em&gt;getState()&lt;/em&gt; method to be implemented by the specific Memento class.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FOx1iC6d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqvj011cm1j9lk6yv5c1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FOx1iC6d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cqvj011cm1j9lk6yv5c1.png" alt="imemento.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Memento
&lt;/h3&gt;

&lt;p&gt;An implementation of the &lt;em&gt;IMemento&lt;/em&gt; interface which stores the snapshot of &lt;em&gt;Originator’s&lt;/em&gt; internal state (&lt;em&gt;Shape&lt;/em&gt; object). The state is accessible to the &lt;em&gt;Originator&lt;/em&gt; via the &lt;em&gt;getState()&lt;/em&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kgWiepqc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1a9ialrmqonu0nrzdaxt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kgWiepqc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1a9ialrmqonu0nrzdaxt.png" alt="memento.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Originator
&lt;/h3&gt;

&lt;p&gt;A class that defines a &lt;em&gt;createMemento()&lt;/em&gt; method to save the current internal state to a &lt;em&gt;Memento&lt;/em&gt; object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8MU_1Vtu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ew43rl1ul2po8tro02wc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8MU_1Vtu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ew43rl1ul2po8tro02wc.png" alt="originator.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;First of all, a markdown file is prepared and provided as a pattern’s description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6MOFmOdd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ozr8jqmjjb6d8om695b.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6MOFmOdd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ozr8jqmjjb6d8om695b.gif" alt="Memento Markdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;MementoExample&lt;/em&gt; contains &lt;em&gt;CommandHistory&lt;/em&gt; and &lt;em&gt;Originator&lt;/em&gt; objects. Also, this widget contains a &lt;em&gt;PlatformButton&lt;/em&gt; component which uses the &lt;em&gt;RandomisePropertiesCommand&lt;/em&gt; to randomise property values of the shape. After the command’s execution, it is added to the command history list stored in the &lt;em&gt;CommandHistory&lt;/em&gt; object. If the command history is not empty, the &lt;em&gt;Undo&lt;/em&gt; button is enabled and the last command could be undone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t-kf9DsV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ctb7ffqjbkh6vvdc7ekp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t-kf9DsV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ctb7ffqjbkh6vvdc7ekp.png" alt="memento_example.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in this example, the client code (UI elements, command history, etc.) isn’t coupled to any specific command class because it works with it via the &lt;em&gt;ICommand&lt;/em&gt; interface.&lt;/p&gt;

&lt;p&gt;In addition to what the Command design pattern provides to this example, the Memento design pattern adds an additional layer to the example’s state. It is stored inside the Originator object, the command itself does not mutate the state directly but through the Originator. Also, the backup (state’s snapshot) stored inside the Command is a Memento object and not the state (Shape object) itself — in case of the state’s restore (undo is triggered on the command), the specific command calls the restore method on the Originator which restores its internal state to the value stored in the snapshot. Hence, it allows restoring multiple property values (a whole complex state object) in a single request, while the state itself is completely separated from the command’s code or UI logic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3cvPWhKy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q65bi48d6wshnxunvxlo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3cvPWhKy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q65bi48d6wshnxunvxlo.gif" alt="Memento Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the example, when the command is executed, under the hood the snapshot of the originator’s internal state is stored which could be restored later by executing the undo operation on the command.&lt;/p&gt;

&lt;p&gt;All of the code changes for the Memento design pattern and its example implementation could be found &lt;a href="https://github.com/mkobuolys/flutter-design-patterns/pull/14"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Contribution
&lt;/h2&gt;

&lt;p&gt;💖 or 🦄 this article to show your support and motivate me to write better!&lt;br&gt;
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.&lt;br&gt;
📢 Share this article with your friends, colleagues on social media.&lt;br&gt;
➕ Follow me on dev.to or any other social media platform.&lt;br&gt;
⭐ Star the &lt;a href="https://github.com/mkobuolys/flutter-design-patterns"&gt;Github&lt;/a&gt; repository.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>oop</category>
      <category>programming</category>
    </item>
    <item>
      <title>12 - Command</title>
      <dc:creator>Mangirdas Kazlauskas 🚀</dc:creator>
      <pubDate>Mon, 05 Apr 2021 16:42:35 +0000</pubDate>
      <link>https://dev.to/mkobuolys/12-command-md1</link>
      <guid>https://dev.to/mkobuolys/12-command-md1</guid>
      <description>&lt;p&gt;Previously in the series, I have analysed and implemented one of the most popular and useful creational design patterns — Abstract Factory. This time, I would like to introduce an OOP design pattern that belongs to the category of behavioural design patterns — the Command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is the Command design pattern?&lt;/li&gt;
&lt;li&gt;Analysis&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;li&gt;Your Contribution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is the Command design pattern?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ec34thWP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e8sra93h7vt8pd0tdc0f.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ec34thWP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e8sra93h7vt8pd0tdc0f.gif" alt="A Dangerous Command"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Command&lt;/strong&gt;, also known as &lt;strong&gt;Action&lt;/strong&gt; or &lt;strong&gt;Transaction&lt;/strong&gt;, is one of the &lt;strong&gt;behavioural&lt;/strong&gt; design patterns which intention is described in the &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns"&gt;GoF book&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable opera­tions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is, by encapsulating the request as an object, the client is completely decoupled from any of the details of how that command is implemented or how it will get executed — the client doesn’t have to care about any dependencies.&lt;/p&gt;

&lt;p&gt;There are multiple components of which the Command design pattern is consisted of. Usually, &lt;strong&gt;Command&lt;/strong&gt; objects serve as links between various UI and business logic objects. In this case, the command object could be bound to the UI element at runtime by the &lt;strong&gt;Client&lt;/strong&gt; and that particular UI component, called &lt;strong&gt;Sender&lt;/strong&gt;, invokes the request. The &lt;strong&gt;Sender&lt;/strong&gt; triggers the assigned &lt;strong&gt;Command&lt;/strong&gt; instead of sending the request directly to the &lt;strong&gt;Receiver&lt;/strong&gt; - a simple or complex object which contains the actual logic for the request to be fulfilled. A specific &lt;strong&gt;Command&lt;/strong&gt; passes the call to the receiver which does the actual work. As a result, commands become a convenient middle layer that reduces coupling between the UI and business logic layers.&lt;/p&gt;

&lt;p&gt;Let’s move to the analysis and implementation parts to understand the details about this pattern and learn how to implement it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;The general structure of the Command design pattern looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9PqK9dQK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/53kjfvmy90vwoohgnzpb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9PqK9dQK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/53kjfvmy90vwoohgnzpb.png" alt="Command Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Command&lt;/em&gt; — declares an interface for executing an operation;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Concrete Commands (Command1/Command2)&lt;/em&gt; — implement various kinds of requests by invoking the corresponding operation(s) on &lt;em&gt;Receiver&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Invoker&lt;/em&gt; — the sender class which triggers the &lt;em&gt;Command&lt;/em&gt; instead of sending the request directly to the &lt;em&gt;Receiver&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Receiver&lt;/em&gt; — knows how to perform the operations associated with carrying out a request. Any class may serve as a &lt;em&gt;Receiver&lt;/em&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Client&lt;/em&gt; — creates a &lt;em&gt;Concrete Command&lt;/em&gt; object and sets its &lt;em&gt;Receiver&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Applicability
&lt;/h3&gt;

&lt;p&gt;The Command design pattern could be used when you want to parameterize objects by an action to perform. That is, the operation (command) is extracted to a separate class which object could be passed as a method argument, stored inside another object or the linked command could be switched at runtime.&lt;/p&gt;

&lt;p&gt;Furthermore, the Command design pattern is useful when you want to queue operations, schedule their execution, or execute them remotely. Since the command itself is just a simple class, its object (as any other object) could be serialized, stored, e.g. in the database or a text file and later restored as the initial command and executed. This is useful when you want to schedule a specific task that should be executed at a particular time, or on a recurring schedule.&lt;/p&gt;

&lt;p&gt;Also, one of the most popular use-case for the Command is to use it for creating reversible operations. To be able to revert operations, you need to implement the history of performed operations. The command history is a stack that contains all executed command objects along with related backups of the application’s state.&lt;/p&gt;

&lt;p&gt;Finally, the Command design pattern helps you write cleaner and reusable code. By using this pattern, you propagate the &lt;strong&gt;Single Responsibility Principle&lt;/strong&gt; (the operation logic is decoupled from the component which performs that particular operation) and the &lt;strong&gt;Open/Closed Principle&lt;/strong&gt; (introducing new commands to the application does not require changing the existing code).&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2jNnrySg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9p6t06vm9etdrwpkb6e6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2jNnrySg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9p6t06vm9etdrwpkb6e6.gif" alt="Let's Have Some Fun"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To show the Command design pattern in action, we will implement a fake graphics editor. The editor itself is &lt;em&gt;super-ultra-mega-duper&lt;/em&gt; simplified (well, &lt;em&gt;Photoshop&lt;/em&gt; should have started from something, right?) and provides the following functionality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There is only one shape visible on the screen which cannot be removed, but its parameters (colour, height and width) could be adjusted using buttons;&lt;/li&gt;
&lt;li&gt;Change the shape’s colour to a random one;&lt;/li&gt;
&lt;li&gt;Change the shape’s height to a random value between 50 and 150;&lt;/li&gt;
&lt;li&gt;Change the shape’s width to a random value between 50 and 150;&lt;/li&gt;
&lt;li&gt;All of the operations could be undone using the Undo button.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that is basically it. I know, as a graphics editor, this one sounds terrible, but it would be more than enough to demonstrate the purpose of the Command design pattern.&lt;/p&gt;

&lt;p&gt;The main idea behind the implementation of the mentioned graphics editor is to separate the actual business logic of the button from its representation. To achieve this, each operation (request) of the button is encapsulated in a separate class object. Also, by using the Command design pattern, the implementation of &lt;em&gt;undo&lt;/em&gt; operation is possible — since every command is encapsulated in a separate class, it is easy to store an objects’ list of already executed commands as well as undoing the last operation by taking the last command from the list and calling the &lt;em&gt;undo()&lt;/em&gt; method on it.&lt;/p&gt;

&lt;p&gt;Let’s check the class diagram first and then investigate each class/component to see how the Command design pattern could help us building such a graphics editor.&lt;/p&gt;

&lt;h3&gt;
  
  
  Class diagram
&lt;/h3&gt;

&lt;p&gt;The class diagram below shows the implementation of the Command design pattern:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YYf-gush--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/584wkd9gvv7etfwxxaz0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YYf-gush--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/584wkd9gvv7etfwxxaz0.png" alt="Command Implementation Class Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Command&lt;/em&gt; is an abstract class that is used as an interface for all the specific commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;execute()&lt;/em&gt; — an abstract method that executes the command;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;getTitle()&lt;/em&gt; — an abstract method that returns the command’s title. Used in command history UI;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;undo()&lt;/em&gt; — an abstract method that undoes the command and returns the receiver to the previous state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;ChangeColorCommand&lt;/em&gt;, &lt;em&gt;ChangeHeightCommand&lt;/em&gt; and &lt;em&gt;ChangeWidthCommand&lt;/em&gt; are concrete command classes that implement the abstract class &lt;em&gt;Command&lt;/em&gt; and its methods.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Shape&lt;/em&gt; is a receiver class that stores multiple properties defining the shape presented in UI: &lt;em&gt;color&lt;/em&gt;, &lt;em&gt;height&lt;/em&gt; and &lt;em&gt;width&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;CommandHistory&lt;/em&gt; is a simple class that stores a list of already executed commands (&lt;em&gt;commandList&lt;/em&gt;) and provides methods to add a new command to the command history list (&lt;em&gt;add()&lt;/em&gt;) and undo the last command from that list (&lt;em&gt;undo()&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;CommandExample&lt;/em&gt; initializes and contains &lt;em&gt;CommandHistory&lt;/em&gt;, &lt;em&gt;Shape&lt;/em&gt; objects. Also, this component contains multiple &lt;em&gt;PlatformButton&lt;/em&gt; widgets which have a specific implementation of &lt;em&gt;Command&lt;/em&gt; assigned to each of them. When the button is pressed, the command is executed and added to the command history list stored in &lt;em&gt;CommandHistory&lt;/em&gt; object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Shape
&lt;/h3&gt;

&lt;p&gt;A simple class to store information about the shape: its color, height and width. Also, this class contains a named constructor to create a shape object with pre-defined initial values.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Na0KFApK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fcfvjnp46xe5s8mx1oqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Na0KFApK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fcfvjnp46xe5s8mx1oqs.png" alt="shape.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Command
&lt;/h3&gt;

&lt;p&gt;An interface that defines methods to be implemented by the specific command classes. Dart language does not support the interface as a class type, so we define an interface by creating an abstract class and providing a method header (name, return type, parameters) without the default implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z4BVA61m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xaajo4ifl2s6egrvp3ti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z4BVA61m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xaajo4ifl2s6egrvp3ti.png" alt="command.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Commands
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;ChangeColorCommand&lt;/em&gt; — a specific implementation of the command which changes the color of the &lt;em&gt;Shape&lt;/em&gt; object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g1lHFi8y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m62xkiw5m55zw9takffq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g1lHFi8y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m62xkiw5m55zw9takffq.png" alt="change_color_command.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ChangeHeightCommand&lt;/em&gt; — a specific implementation of the command which changes the height of the &lt;em&gt;Shape&lt;/em&gt; object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1rs7YDZv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p276vnuzvyfvbqra5nex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1rs7YDZv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p276vnuzvyfvbqra5nex.png" alt="change_height_command.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;ChangeWidthCommand&lt;/em&gt; — a specific implementation of the command which changes the width of the &lt;em&gt;Shape&lt;/em&gt; object.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wA0Ly99t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yhfdduy06t0rt5vll24w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wA0Ly99t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yhfdduy06t0rt5vll24w.png" alt="change_width_command.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  CommandHistory
&lt;/h3&gt;

&lt;p&gt;A simple class that stores a list of already executed commands. Also, this class provides &lt;em&gt;isEmpty&lt;/em&gt; and &lt;em&gt;commandHistoryList&lt;/em&gt; getter methods to return true if the command history list is empty and return a list of command names stored in the command history respectively. A new command could be added to the command history list via the &lt;em&gt;add()&lt;/em&gt; method and the last command could be undone using the &lt;em&gt;undo()&lt;/em&gt; method (if the command history list is not empty).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PBVqzljW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5gx7i1t6q75eb41esnxv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PBVqzljW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5gx7i1t6q75eb41esnxv.png" alt="command_history.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;First of all, a markdown file is prepared and provided as a pattern’s description:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Yq0FSmLA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztkyawt8soejrbn2hr3d.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Yq0FSmLA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ztkyawt8soejrbn2hr3d.gif" alt="Command Markdown"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;CommandExample&lt;/em&gt; contains &lt;em&gt;CommandHistory&lt;/em&gt; and &lt;em&gt;Shape&lt;/em&gt; objects. Also, this widget contains several &lt;em&gt;PlatformButton&lt;/em&gt; components, each of which uses a specific function executing a concrete command. After the command’s execution, it is added to the command history list stored in the &lt;em&gt;CommandHistory&lt;/em&gt; object. If the command history is not empty, the &lt;em&gt;Undo&lt;/em&gt; button is enabled and the last command could be undone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rnMZl6m7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s01tg1sqp1rt5eqgnreh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rnMZl6m7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s01tg1sqp1rt5eqgnreh.png" alt="command_example.dart"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The client code (UI elements, command history, etc.) isn’t coupled to concrete command classes because it works with commands via the command interface. This approach allows introducing new commands into the application without breaking any existing code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FGGdHcIe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3a2tg38uxbz81y8n8c09.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FGGdHcIe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3a2tg38uxbz81y8n8c09.gif" alt="Command Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the example, by triggering a specific command, its object is created, executed and added to the command history list. Hence, it is possible to undo the command even though it was executed several steps before — that’s one of the advantages of using the Command design pattern.&lt;/p&gt;

&lt;p&gt;All of the code changes for the Command design pattern and its example implementation could be found &lt;a href="https://github.com/mkobuolys/flutter-design-patterns/pull/13"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Contribution
&lt;/h2&gt;

&lt;p&gt;💖 or 🦄 this article to show your support and motivate me to write better!&lt;br&gt;
💬 Leave a response to this article by providing your insights, comments or wishes for the next topic.&lt;br&gt;
📢 Share this article with your friends, colleagues on social media.&lt;br&gt;
➕ Follow me on dev.to or any other social media platform.&lt;br&gt;
⭐ Star the &lt;a href="https://github.com/mkobuolys/flutter-design-patterns"&gt;Github&lt;/a&gt; repository.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>oop</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
