Flutter Community
Published in

Flutter Community

Flutter Design Patterns: 21 — Visitor

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

Table of Contents

  • What is the Visitor design pattern?
  • Analysis
  • Implementation
  • Other articles in this series
  • Your contribution

What is the Visitor design pattern?

Class component with applied Visitor design pattern be like (source)

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.

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?

Analysis

The general structure of the Visitor design pattern looks like this:

Structure of the Visitor design pattern (source)
  • Concrete visitors — implements each operation declared by Visitor;
  • Element — declares an accept method that takes Visitor as an argument;
  • Concrete elements — implements the acceptance method. The implementation should rely on redirecting the request to the proper visitor’s method corresponding to the current element class;
  • Client — usually contains a collection or a complex object structure, initialises the concrete visitor object and then traverses the object structure by visiting each element with the visitor.

Applicability

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.

Implementation

  • It’s a violation of the Single-responsibility principle. 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.

Class diagram

The class diagram below shows the implementation of the Visitor design pattern:

Class Diagram — Implementation of the Visitor design pattern
  • render() — renders the component’s UI;
  • accept() — delegates request to a visitor.
  • visitDirectory() — defines a visiting method for the Directory class;
  • visitAudioFile() — defines a visiting method for the AudioFile class;
  • visitImageFile() — defines a visiting method for the ImageFile class;
  • visitTextFile() — defines a visiting method for the TextFile class;
  • visitVideoFile() — defines a visiting method for the VideoFile class.

IFile

An interface that defines methods to be implemented by specific files and directories. The interface also defines an accept() 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.

ifile.dart

File

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

file.dart

Concrete file classes

All of the specific file type classes implement the accept() method that delegates request to the specific visitor’s method.

audio_file.dart
image_file.dart
text_file.dart
video_file.dart

Directory

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

directory.dart

Formatting extensions

Defines an extension method indentAndAddNewLine that adds nTab tabs at the beginning and a new line symbol at the end of a String.

formatting_extensions.dart

IVisitor

An interface that defines methods to be implemented by all specific visitors.

ivisitor.dart

Concrete visitors

  • HumanReadableVisitor — implements the specific visitor that provides file information of each file type in a human-readable format.
human_readable_visitor.dart
xml_visitor.dart

Example

First of all, a markdown file is prepared and provided as a pattern’s description:

visitor_example.dart

Your contribution

👏 Press the clap button below to show your support and motivate me to write better!
💬 Leave a response to this article by providing your insights, comments or wishes for the series.
📢 Share this article with your friends, colleagues on social media.
➕ Follow me on Medium.
⭐ Star the Github repository.

https://www.twitter.com/FlutterComm

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store