Skip to content

dbackspace/PracticeDesignPattern

Repository files navigation

🚀 Introduction

  • All codes are written by Kotlin.
  • This repository contains about 20 standard design patterns by GoF, and other design patterns such as Repository, Null Object, Transfer Object + DAO, Intercepting Filter, etc.
  • Some design patterns used (or can be used) in MyFiles (you can see it in in_myfiles package). Some are not used currently, so I put it in examples package.
  • All patterns are classified into each package with its correct type (Creational, Structural, Behavioral).
  • Some design patterns was not implemented, because I am quite lazy in this time. So I refered link from reliable sources that I think are easy to understand for you to learn more about. The reference links I attached in header comment each of Main.kt file.
  • Most of the design patterns mentioned here come with UML. I drew it with PlantUML. For a more detailed overview, visit PlantUML Official Website.

📖 More details

✔️ Creational patterns

Includes design patterns to instantiate objects in different ways.

  • Singleton: Create instance of object just once and use it throughout the application. This has two ways to implement (eager-initialization and lazy-initialization), but in this project, I only implement lazy-inititalization to simulate search queries from different sources (LOCAL, CLOUD) but only initialize a single SearchDataSource object (singleton).
  • Factory method: Encapsulate object creation with a common base class. I have simulated it for setting the sort for list file info by name, extension, size or time (factory_method).
  • Abstract factory: Encapsulates object creation and allows for the creation of many different types of objects. In MyFiles, it has two versions of app (one for global market, one for China market). Along with that are different ways to display items on the home page such as Trash, Cloud, etc. These items all inherit HomeItem. Therefore, I have created 2 factories for these 2 markets, each factory will be responsible for creating each individual home item (abstract_factory).
  • Builder: Separate the construction of a complex object from its representation so that the same construction process can create different representations. In this project, it is described as creating a dialog builder and setting parameters such as title, message, positive, neutral and negative button for dialog (builder).
  • Prototype: Used to copy an object from an existing object. I implemented it as creating a GroupHeaderInfo from an existing FileInfo object by just adding an extension method makeGroupHeader and changing the isGroupHeader value of the FileInfo object (prototype).

✔️ Structural patterns

Includes design patterns for connecting objects and expanding the system.

  • Adapter: Allows objects with incompatible interfaces to collaborate by converting the interface of one class to an interface of another class. This pattern is used a lot in Android programming, especially the RecyclerView part. I just created a simple example of a language translator to illustrate it well. Here, TranslatorAdapter will contain the interface of the source object JapaneseTranslator. Client will send text to TranslatorAdapter, TranslatorAdapter will receive, perform translation and forward it to JapaneseTranslator (adapter).
  • Bridge: Creating bridges between different layers aims to separate the implementation, allowing the layers to change independently of each other. An example exists in MyFiles where each component uses a variety of resources (string, drawable, dimen, color). However, this makes identifying the resource components of each object unclear. MyFiles has grouped these common properties based on the nature of the Bridge pattern - dividing Abstraction into objects used by the client such as DefaultRes (generic resource, default or ungrouped), HomeRes (resources on the home page), StorageRes (resources for storage components like Local Internal, SD Card, etc.), CloudRes (resources for cloud content), etc. and Interface are extensions of resources such as string, drawable, dimen, color. An intermediate class ResourceBridge will have the role of interacting with these two parts (bridge).
  • Composite: Combine classes together to avoid having to inherit or implement too many classes and interfaces. A simple example is calculating the size of a folder. We instantiate DirectoryFileInfo which inherits the FileInfo interface and overrides its getSize method. DirectoryFileInfo will become a type FileInfo, passed as a parameter a list of files in that folder. When client calls its getSize function, it will return the total size of the entire folder (composite).
  • Decorator: Lets you attach new behaviors to objects by placing these objects inside special wrapper objects that contain the behaviors. In this example, we want to perform some additional features such as downloading before copying the file, but the current operators do not allow that. Therefore, we create a DecoratorOperation class that inherits the current IFileOperation behavior, receives an instance from IFileOperation (the current operation) and adds a doExtraOperation method before executing the next doOperation from the instance there. The DownloadOperation subclass will extend DecoratorOperation and implement additional methods in doExtraOperation (decorator).
  • Flyweight: Lets you add more objects into the available amount of memory by sharing common parts of state between multiple objects instead of keeping all the data in each object. For example, if object A contains object B (immutable) and object C (mutable), we can initialize object B once and store it in cache. Next time, if we init new object A, we just need to use the previously cached object B instead of creating a new one. This saves significantly on generated memory. I have clearly described this pattern through two examples of initializing FileInfoGenerator in file_generator and PageSpec in page_spec.
  • Proxy: Lets you provide a substitute or placeholder for another object. A proxy controls access to the original object, allowing you to perform something either before or after the request gets through to the original object. This pattern is very useful when you need to prevent or check a certain condition, or reduce the number of concurrent object instantiations before reaching the root object. In this example, I have simulated downloading thumbnails from the cloud. By creating a CachedThumbnail object to check for the existence of a thumbnail before downloading it in DownloadThumbnail, this will help reduce the number of redundant thumbnail downloads (proxy).

✔️ Behavioral patterns

Includes design patterns used to process data and events that occur during program operation.

  • Chain of Responsibility: Allows you to pass requests along a chain of handlers. Upon receiving a request, each handler decides to process the request or pass it on to the next handler in the chain. An example that appeared in MyFiles 2016 - 2018 (Android Oreo OS), is that the display of home items such as LocalStorageItem, RecentItem, CategoryItem, AnalyzeStorageItem is executed and loaded in chain form (chain_of_responsibility).
  • Command: Process the action according to the corresponding command.
  • Facade: Provides a simplified interface to a library, framework, or any other complex set of classes.
  • Observer: Allows you to define a subscription mechanism to notify multiple objects about any event that occurs to the object they are observing.

As for these three design patterns (Facade, Command, Observer), in MyFiles they are used in combination. Here, Facade acts as MenuExecuteManager to encapsulate complex processing methods inside. Command is a descendant of AbsExecute. Observer is a procedure that registers to receive results returned by ResultListener via the addDataCallbackListener method (facade_and_command_and_observer).

  • Strategy: Separate the part that handles a specific function from the object. Then create a set of algorithms to handle that function and choose which algorithm we find most appropriate when executing the program. It's like the same sort function but there will be many different sorting strategies such as QuickSort, MergeSort, etc. The clearest example in MyFiles is the way list display types are divided based on BehaviorType. There are three display types: DefaultListBehavior (default type), ExpandableListBehavior (display type that includes group headers), CustomListBehavior (display type with expanded header detailed in AnalyzeStorageFileListPage). Depending on the BehaviorType definition, select the corresponding list display type (strategy).
  • State: Allows an object to change its behavior when its internal state changes. To illustrate, I give a typical example in the MVI architecture style. Here, I use UiState to notify HomePageController the appropriate states to update the data. The special thing about using UiState as a sealed class instead of using constant variable or enum class states is that it can carry return data or exception messages attached for the client to call. and use it directly (state).
  • Template method: Define the framework of the algorithm in a superclass but allow subclasses to override specific steps of the algorithm without changing its structure. It is similar to the onCreate, onStart, onPause, etc. functions in the lifecycle of Activity. Here I have an illustrative example (not in MyFiles) so you understand how it works. A PageTemplate will show components in the given order (showHeader, showBody, showFooter, showNavigation). However, on different pages such as ContactPage or HomePage, there will be different showBody methods. We will just re-implement this method from PageTemplate without changing the display order of the components (template_method).
  • Iterator: Used to iterate over a set, similar to how you use a loop to traverse a list. Here the example is very simple, you let your object inherit Iterable and create its Iterator instance. The DirectoryIterator object will then be capable of sequential traversal (iterator).

✔️ Other patterns

Includes other design patterns for tasks such as data stream processing, database queries, exception prevention, etc.

  • Null object: Provides an alternative handling solution when the returned result is not in the given set. To illustrate, I added NonNullFileOperation to handle when the get file operation from FileOpeationFactory is null (null_object).
  • Repository: Separate the Business Logic and Data Access (database) layers from each other, as an intermediate layer between data access and logic processing. It helps make data access more strict and secure. I described it the way MyFiles is using it, which is to create interfaces or abstract classes SearchRepository to bridge communication from the business logic layer (SearchController) and data access layer (SearchDataSource) (repository).
  • Intercepting filter: Used when you want to do some processing before (pre-processing) when the request is processed by the target application (target) or after (post-processing) when the response is returned from the target (commonly used in Java EE). Here, I have described it as a filter operator on the data stream. It will filter and remove invalid files through the VerifyHiddenFileFilter and VerifyLocalStorageFileFilter filters (intercepting_filter).
  • Data access object (DAO): Used to separate data storage logic in a separate layer. Instead of having logic that communicates directly with the database, file system, web service, or whatever storage mechanism the application needs to use, we'll let this logic communicate with the DAO middle layer. . This DAO layer then communicates with the storage system and database management system such as performing tasks related to storing and querying data (searching, adding, deleting, editing, etc.). The example here is very simple, I have created the FileSystemDao class to mediate communication between 2 different data types sources. The business logic layer LocalFileRepository will perform getting pure data from FileSystemDataSource through FileSystemDao and converting it to the data type you want without directly affecting FileSystemDataSource. (data_access_object).

🧱 Contributor

This is a project that I created to practice design skills based on design patterns. Therefore, the knowledge and implementation in this is based on my personal knowledge and experience. I would be happy if you could contribute other implementations, or newer design patterns. Thank you.

About

This repo includes all design pattern used in MyFiles, written by me for reference purposes :)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages