Design Patterns That Use Interfaces in Java

Design patterns - Solutions to some prominent & frequent problems, one faces while designing softwares.

  • "Evolved" not "Discovered".
  • Provides guidelines for solving a particular problem in particular way in some particular context. No strictness on implementation.
  • Using DPs, code becomes more flexible, reusable and maintainable.
  • Gang of Four (GoF) Design Patterns - standard 23 DPs.

3 different kinds of design patterns are there:

  • Creational Patterns : Deals with object creation.
  • Structural Patterns : Deals with the composition of objects & classes.
  • Behavioral Patterns : Focuses on interactions between objects.

Also a 4th category: J2EE Patterns which specifically deals with presentation tier.

basics

Creational Patterns

creational-patterns

Singleton Pattern

This pattern puts restrictions on the instantiation of classes & ensures that only 1 instance of the class is available in the JVM at any point of time.

  • Used for logging, thread pools, driver objects and caching.
  • Used in core java classes like java.lang.RunTime etc.

Concepts:

  • Private constructor for restricting the object creation from outside class.
  • The only single instance of the class is a private static variable.
  • Public static method for exposing this only single instance to the outside world.
                          public              class              Singleton              {              private              static              Singleton              instance              ;              private              Singleton              (){}              public              static              Singleton              getInstance              (){              if              (              instance              ==              null              ){              instance              =              new              Singleton              ();              }              return              instance              ;              }              }                      

But, this approach fails for multi-threading environment. There are chances that 2 or more threads will create & get the different instances of the same singleton class.

                          public              class              ThreadSafeSingleton              {              private              static              ThreadSafeSingleton              instance              ;              private              ThreadSafeSingleton              (){}              public              static              synchronized              ThreadSafeSingleton              getInstance              (){              if              (              instance              ==              null              ){              instance              =              new              ThreadSafeSingleton              ();              }              return              instance              ;              }              }                      

Factory Pattern

Native approach for object creation is usage of constructors, but factory pattern provides alternative way for this.

  • Used when for a superclass -> multiple sub-classes are there and based on some business logic, one of the sub-class is returned.
  • This pattern takes out the responsibility of instantiation from the client program to the factory class.

  • Used when the exact types and dependencies of the objects your code should work with is not known beforehand.
  • Factory pattern makes our code more robust, less coupled and easy to extend

Concepts:

  • Factory class for creation of object of desired type based on the business logic.

Real-life example is a Logistic App, initially, a single transport mechanism was of land so Trucks were used & all logistics function were dependent on Truck class but later on while addition of sea & air transport, this poses problems in scaling the app.

Button.java

                          public              interface              Button              {              void              render              ();              }                      

WindowsButton.java

                          public              class              WindowsButton              implements              Button              {              @Override              public              void              render              ()              {}              }                      

HtmlButton.java

                          public              class              HtmlButton              implements              Button              {              @Override              public              void              render              ()              {}              }                      

ButtonFactory.java : Factory class

                          public              class              ButtonFactory              {              public              Button              getButton              ()              {              if              (              System              .              getProperty              (              "usage.property"              ).              equals              (              "browser"              ))              return              new              HtmlButton              ();              else              return              new              WindowsButton              ();              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              ButtonFactory              buttonFactory              =              new              ButtonFactory              ();              Button              button              =              buttonFactory              .              getButton              ();              button              .              render              ();              }              }                      

Abstract Factory Pattern

This is another layer of abstraction over the Factory pattern.

  • AbstractFactory returns the Factory of classes, each of these factory will return one of the sub-classes.
  • This is basically Factory pattern applied over the Factory pattern implementation.

Real life example is: Honda builds SportsCar & LuxuryCar for 2 locations: USA & India. Based on location, Cars specification varies for all 2 subclasses of car like steering wheel side. Here AbstractFactory comes to our rescue.

Car.java

                          public              abstract              class              Car              {              private              CarType              model              =              null              ;              private              Location              location              =              null              ;              public              Car              (              CarType              model              ,              Location              location              ){              this              .              model              =              model              ;              this              .              location              =              location              ;              }              //getters and setters              protected              abstract              void              construct              ();              }                      

SportCar.java

                          public              class              SportCar              extends              Car              {              public              SportCar              (              Location              location              )              {              super              (              CarType              .              SPORTS              ,              location              );              construct              ();              }              @Override              protected              void              construct              ()              {              System              .              out              .              println              (              "Building Sports car"              );              //add accessories              }              }                      

LuxuryCar.java

                          public              class              LuxuryCar              extends              Car              {              public              LuxuryCar              (              Location              location              )              {              super              (              CarType              .              LUXURY              ,              location              );              construct              ();              }              @Override              protected              void              construct              ()              {              System              .              out              .              println              (              "Building Luxury car"              );              //add accessories              }              }                      

Location.java

                          public              enum              Location              {              USA              ,              ASIA              }                      

CarType.java

                          public              enum              CarType              {              SPORTS              ,              LUXURY              }                      

CarFactory.java

                          public              class              CarFactory              {              private              CarFactory              ()              {}              public              static              Car              buildCar              (              CarType              type              )              {              Car              car              =              null              ;              Location              location              =              System              .              getProperty              (              "location.info"              );              switch              (              location              )              {              case              USA:              car              =              USACarFactory              .              buildCar              (              type              );              break              ;              case              ASIA:              car              =              AsiaCarFactory              .              buildCar              (              type              );              break              ;              }              return              car              ;              }              }                      

USACarFactory.java

                          public              class              USACarFactory              {              public              static              Car              buildCar              (              CarType              model              )              {              Car              car              =              null              ;              switch              (              model              )              {              case              SPORTS:              car              =              new              SportCar              (              Location              .              USA              );              break              ;              case              LUXURY:              car              =              new              LuxuryCar              (              Location              .              USA              );              break              ;              }              return              car              ;              }              }                      

AsiaCarFactory.java

                          public              class              USACarFactory              {              public              static              Car              buildCar              (              CarType              model              )              {              Car              car              =              null              ;              switch              (              model              )              {              case              SPORTS:              car              =              new              SportCar              (              Location              .              ASIA              );              break              ;              case              LUXURY:              car              =              new              LuxuryCar              (              Location              .              ASIA              );              break              ;              default              :              }              return              car              ;              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              CarFactory              .              buildCar              (              CarType              .              SPORTS              );              CarFactory              .              buildCar              (              CarType              .              LUXURY              );              }              }                      

Builder Pattern

This pattern helps in constructing complex objects in a step-by-step manner & the final step returns the object.

  • Objects are having lot many attributes & having separate constructors for invoking these attributes for object creation is really cumbersome.
  • StringBuilder & StringBuffer in java uses Builder DP.

builder-dp

Concepts

  • Builder class is a static nested class inside the main object class.
  • Builder class must have a public parameterized constructor with all mandatory data members.
  • Builder class should have setters for all optional data members & should return Builder object.
  • build() method is required which returns the final object to the runner.

Mobile.java

                          public              class              Mobile              {              private              String              RAM              ;              private              String              Size              ;              private              String              Camera              ;              boolean              is4GEnabled              ;              // GETTERS for these 5 private members              private              Mobile              (              MobileBuilder              builder              )              {              this              .              RAM              =              builder              .              RAM              ;              this              .              Size              =              builder              .              Size              ;              this              .              Camera              =              builder              .              Camera              ;              this              .              is4GEnabled              =              builder              .              is4GEnabled              ;              }              public              static              class              MobileBuilder              {              private              String              RAM              ;              private              String              Size              ;              private              String              Camera              ;              boolean              is4GEnabled              ;              public              MobileBuilder              (              String              RAM              ,              String              Size              )              {              this              .              RAM              =              RAM              ;              this              .              Size              =              Size              ;              }              public              MobileBuilder              setCamera              (              String              Camera              )              {              this              .              Camera              =              Camera              ;              return              this              ;              }              public              MobileBuilder              setIs4GEnabled              (              boolean              is4GEnabled              )              {              this              .              is4GEnabled              =              is4GEnabled              ;              return              this              ;              }              public              Mobile              build              ()              {              return              new              Mobile              (              this              );              }              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              Mobile              mobile1              =              new              Mobile              .              MobileBuilder              (              "4 GB"              ,              "6 inch"              ).              setCamera              (              "12px"              ).              setIs4GEnabled              (              true              ).              build              ();              Mobile              mobile2              =              new              Mobile              .              MobileBuilder              (              "2 GB"              ,              "4.2 inch"              ).              setIs4GEnabled              (              false              ).              build              ();              }              }                      

Prototype Pattern

Prototype is a template of the actual object to be constructed later. In java, Prototyping means cloning or replicating an object.

  • Whether deep copy or shallow copy, depends totally on the business needs.
  • Useful when large number of instances of classes are required, which are all nearly same.
  • This DP also supplements cases when we require exact copies of existing objects but don't want to be dependent on their classes.

If the cost of object creation is large & creation process is resource-intensive, we use cloning.

Issues with normal approach If we have to exactly copy an existing object natively, we create a new object of the same class, traverse all fields of existing object & copy values to the new object. Here, catch is that maybe some fields are private & couldn't be accessed/copied.

Concepts

  • An interface/class implementing Cloneable having abstract clone() method declared.
  • Prototype registry for holding the prominent prototypes available to us.
  • Separate Prototype models which inherits the base interface & implements clone() method in them.

SolrCore.java

                          public              interface              SolrCore              extends              Cloneable              {              public              SolrCore              clone              ()              throws              CloneNotSupportedException              ;              }                      

Intent.java

                          public              class              Intent              implements              SolrCore              {              private              String              name              =              null              ;              @Override              public              Intent              clone              ()              throws              CloneNotSupportedException              {              return              (              Intent              )              super              .              clone              ();              }              }                      

Mapping.java

                          public              class              Mapping              implements              SolrCore              {              private              String              name              =              null              ;              @Override              public              Mapping              clone              ()              throws              CloneNotSupportedException              {              return              (              Mapping              )              super              .              clone              ();              }              }                      

Mcat.java

                          public              class              Mcat              implements              SolrCore              {              private              String              name              =              null              ;              @Override              public              Mcat              clone              ()              throws              CloneNotSupportedException              {              return              (              Mcat              )              super              .              clone              ();              }              }                      

CoreDirectory.java

                          public              class              CoreDirectory              {              public              static              class              CoreName              {              public              static              final              String              INTENT              =              "intent"              ;              public              static              final              String              MCAT              =              "mcat"              ;              public              static              final              String              MAPPING              =              "mapping"              ;              }              private              static              java              .              util              .              Map              <              String              ,              SolrCore              >              cores              =              new              java              .              util              .              HashMap              <>();              static              {              cores              .              put              (              CoreName              .              INTENT              ,              new              Intent              ());              cores              .              put              (              CoreName              .              MCAT              ,              new              Mcat              ());              cores              .              put              (              CoreName              .              MAPPING              ,              new              Mapping              ());              }              public              static              SolrCore              getInstance              (              final              String              s              )              throws              CloneNotSupportedException              {              return              ((              SolrCore              )              cores              .              get              (              s              )).              clone              ();              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              try              {              String              mappingCore1              =              SolrCore              .              getInstance              (              CoreName              .              MAPPING              ).              toString              ();              String              intentCore1              =              SolrCore              .              getInstance              (              CoreName              .              INTENT              ).              toString              ();              String              mappingCore2              =              SolrCore              .              getInstance              (              CoreName              .              MAPPING              ).              toString              ();              }              catch              (              CloneNotSupportedException              e              )              {              e              .              printStackTrace              ();              }              }              }                      

Structural Patterns

structural-pattern

Adapter Pattern

Allows objects with imcompatible interfaces to collaborate.

  • Helps creating a middle-layer class that serves as translator between the legacy code & new code.
  • Arrays.asList() is a quite famous adapter used.
  • Also known as Wrapper Pattern
  • 2 ways of implementing adapter patter:
    • Class adapter which uses inheritence
    • Object adapter which uses composition

issues solution

RoundHole.java

                          public              class              RoundHole              {              private              double              radius              ;              public              RoundHole              (              double              radius              )              {              this              .              radius              =              radius              ;              }              public              boolean              fits              (              RoundPeg              rpeg              )              {              if              (              this              .              radius              >=              rpeg              .              getRadius              ())              return              true              ;              else              return              false              ;              }              }                      

RoundPeg.java

                          public              class              RoundPeg              {              private              double              radius              ;              public              RoundPeg              (              double              radius              )              {              this              .              radius              =              radius              ;              }              public              double              getRadius              ()              {              return              this              .              radius              ;              }              }                      

SquarePeg.java

                          public              class              SquarePeg              {              private              double              side              ;              public              SquarePeg              (              double              side              )              {              this              .              side              =              side              ;              }              public              double              getSide              ()              {              return              this              .              side              ;              }              }                      

SquarePegAdapter.java

                          public              class              SquarePegAdapter              extends              RoundPeg              {              private              SquarePeg              sqpeg              ;              public              SquarePegAdapter              (              SquarePeg              sqpeg              )              {              this              .              sqpeg              =              sqpeg              ;              }              @Override              public              double              getRadius              ()              {              return              Math              .              sqrt              (              Math              .              pow              (              sqpeg              .              getSide              ()/              2              ,              2              )*              2              );              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              RoundHole              hole              =              new              RoundHole              (              5              );              RoundPeg              rpeg              =              new              RoundPeg              (              5              );              hole              .              fits              (              rpeg              );              // true              SquarePeg              sqpeg              =              new              SquarePeg              (              6              );              hole              .              fits              (              sqpeg              );              // compilation error              SquarePegAdapter              sqpegAdapter              =              new              SquarePegAdapter              (              sqpeg              );              hole              .              fits              (              sqpegAdapter              );              // false              }              }                      

Bridge Pattern

Used for decoupling abstraction from its implementation so that both can vary independently.

  • Used when the system needs to be extended in several orthogonal dimensions.
  • Used when we wish to switch the implementation at run-time.
  • Used for applications requiring platform independence.

bridge

Composite Pattern

Used mainly for the cases when objects form a tree-like hierarchy. In this hierarchy, each node is either a composite or a leaf node.

  • Provides 2 basic element types which share common interface: simple leaves & complex containers. These containers can further contain simple leaves & more containers making this a tree structre.
  • Using this pattern, simple as well complex elements are treated uniformly.

composite

FileSystemObject.java

                          public              interface              FileSystemObject              {              public              abstract              void              print              ();              }                      

File.java

                          public              class              File              extends              FileSystemObject              {              private              String              fileName              ;              public              File              (              String              fileName              )              {              this              .              fileName              =              fileName              ;              }              @Override              public              void              print              ()              {              Sout              (              fileName              );              }              }                      

Folder.java

                          public              class              Folder              extends              FileSystemObject              {              private              String              folderPath              ;              private              List              <              String              >              childrens              ;              public              Folder              (              String              folderPath              )              {              this              .              folderPath              =              folderPath              ;              this              .              childrens              =              new              ArrayList              <>();              }              public              add              (              FileSystemObject              fobj              )              {              this              .              childrens              .              add              (              fobj              );              }              @Override              public              void              print              ()              {              Sout              (              folderPath              );              for              (              FileSystemObject              fobj:              childrens              )              {              fobj              .              print              ();              }              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              FileSystemObject              file1              =              new              File              (              "model-v1.bin"              );              FileSystemObject              file2              =              new              File              (              "model-v2.bin"              );              FileSystemObject              file3              =              new              File              (              "dataset.csv"              );              FileSystemObject              folder1              =              new              Folder              (              "/ml"              );              FileSystemObject              folder2              =              new              Folder              (              "/dataset"              );              FileSystemObject              folder3              =              new              Folder              (              "/models"              );              folder2              .              add              (              file3              );              folder3              .              add              (              file1              );              folder3              .              add              (              file2              );              folder1              .              add              (              folder2              );              folder1              .              add              (              folder3              );              folder1              .              print              ();              }              }                      

Decorator Pattern

Used to extend the behavior of an instance at runtime. This modification doesn't impact the other instances.

  • Provides alternative to the native approach of subclassing for functionality extensions.
  • Also called as wrapper design pattern just like adapter dp.
  • Decorator dp lets us attach these new behaviors to objects by placing these objects inside special wrapper objects (decorators) that contain these behaviors.

Concepts

  • Component interface
  • Component implementation which extends component interface
  • Decorator which extends component interface & posses HAS-A relation with component implementation
  • Concrete decorators which extend Decorator & adds extra functionalities.

DataSource.java

                          public              interface              DataSource              {              void              writeData              (              String              data              );              String              readData              ();              }                      

FileDataSource.java

                          public              class              FileDataSource              implements              DataSource              {              private              String              name              ;              public              FileDataSource              (              String              name              )              {              this              .              name              =              name              ;              }              @Override              public              void              writeData              (              String              data              )              {              SOUT              (              "Writing data to file"              );              }              @Override              public              String              readData              ()              {              SOUT              (              "Reading data from file"              );              }              }                      

DataSourceDecorator.java

                          public              class              DataSourceDecorator              implements              DataSource              {              private              DataSource              wrappee              ;              DataSourceDecorator              (              DataSource              source              )              {              this              .              wrappee              =              source              ;              }              @Override              public              void              writeData              (              String              data              )              {              wrappee              .              writeData              (              data              );              }              @Override              public              String              readData              ()              {              return              wrappee              .              readData              ();              }              }                      

EncryptionDecorator.java

                          public              class              EncryptionDecorator              extends              DataSourceDecorator              {              public              EncryptionDecorator              (              DataSource              source              )              {              super              (              source              );              }              @Override              public              void              writeData              (              String              data              )              {              super              .              writeData              (              encode              (              data              ));              }              @Override              public              String              readData              ()              {              return              decode              (              super              .              readData              ());              }              }                      

CompressionDecorator.java

                          public              class              CompressionDecorator              extends              DataSourceDecorator              {              public              CompressionDecorator              (              DataSource              source              )              {              super              (              source              );              }              @Override              public              void              writeData              (              String              data              )              {              super              .              writeData              (              compress              (              data              ));              }              @Override              public              String              readData              ()              {              return              decompress              (              super              .              readData              ());              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              DataSourceDecorator              encoded              =              new              CompressionDecorator              (              new              EncryptionDecorator              (              new              FileDataSource              (              "input.txt"              )));              DataSource              plain              =              new              FileDataSource              (              "input.txt"              );              SOUT              (              plain              .              readData              ());              SOUT              (              encoded              .              readData              ());              }              }                      

Facade Pattern

Used for providing simplified interface to set of complex subsystems.

  • Is appropriate when we have a complex subsystems, which we desire to expose in a simplistic manner.
  • It hides the internal complexities from the outer world.
  • Also decouples the code making it easier to modify/rectify the subsystems without affecting the external client facing interfaces.

facade

MCATService.java

                          public              class              MCATService              {              public              List              <              String              >              suggestMCATs              (              String              searchQuery              )              {              String              modifiedSearchQuery              =              new              SearchQueryFormatter              .              clean              (              searchQuery              );              List              <              String              >              mcats              =              new              SolrMappingLogic              .              getTopMappings              (              modifiedSearchQuery              );              mcats              .              addAll              (              new              SolrMCATLogic              .              getExactMCATs              (              modifiedSearchQuery              ));              mcats              .              addAll              (              new              SolrMCATLogic              .              getSimilarMCATs              (              mcats              .              get              (              0              )));              mcats              =              new              BusinessLogic              .              reorganise              (              mcats              );              }              }                      

We have several subsystems in place namely, SearchQueryFormatter.java, SolrMappingLogic.java, SolrMCATLogic.java, BusinessLogic.java etc but MCATService will act as facade to us.

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              List              <              String              >              mcats              =              new              MCATService              .              suggestMCATs              (              "Lg washing machine 4kg"              );              }              }                      

Due to decoupling between the interface & implementation, its easy to modify/rectify/change the implementation.

Flyweight Pattern

Used in scenarios where lots of similar objects are spawned in the system. Since, each of these objects consumes memory which is crucial for low storage devices like mobiles or embedded systems, Flyweight pattern is highly useful.

  • We try to fit more objects in the available RAM by sharing common data between these objects rather than keeping that data in each object.
  • Flyweight is a shared object which can be used in multiple contexts simultaneously.

Concepts

  • Number of objects created should be huge
  • Object properties can be divided into intrinsic & extrinsic. Intrinsic properties are part of the flyweight class & extrinsic properties are set by the client code.

without-flyweight

with-flyweight

Proxy Pattern

Used in scenarios when we require to represent the actual service object with a simpler one. Proxy object serves as placeholder for the actual service objects.

Types of proxies:

  • Virtual proxy used for lazy initialisation. If the actual service object is too heavy & memory-hungry to be created.
  • Protection proxy used for access control. If the actual service object requires some sort of authentication.
  • Remote proxy used for remote handling & connection establishment stuff.
  • Logging & Caching proxy used for logging & request/data caching purposes.

CommandExecutor.java

                          public              interface              CommandExecutor              {              public              void              runCommand              (              String              command              ,              String              user              );              }                      

CommandExecutorImpl.java

                          public              class              CommandExecutorImpl              extends              CommandExecutor              {              @Override              public              void              runCommand              (              String              command              ,              String              user              )              {              Runtime              .              getRuntime              ().              exec              (              command              );              }              }                      

CommandExecutorProxy.java

                          public              class              CommandExecutorProxy              extends              CommandExecutorImpl              {              @Override              public              void              runCommand              (              String              command              ,              String              user              )              {              if              (              user              .              equals              (              "admin"              ))              {              super              .              runCommand              (              command              );              }              else              Sout              (              "Permission Denied"              );              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              new              CommandExecutorProxy              .              runCommand              (              "ls"              ,              "admin"              );              new              CommandExecutorProxy              .              runCommand              (              "rm"              ,              "jalaz"              );              }              }                      

Behavioral Patterns

Chain of responsibility

Used in scenarios when a client's request is passed through a chain of handlers. Each handler upon receiving the request decides whether to process it or pass it to the next handler.

  • Java Exception handling with multiple catch blocks is an excellent example.
  • Customer servicing support is a good real life example.
  • Use COR when these handlers are to be decided at run-time.

cor

Dispenser.java

                          public              interface              Dispenser              {              void              setNextDispencer              (              Dispenser              next              );              void              dispense              (              Integer              amount              );              }                      

Rupee2000Dispenser

                          public              class              Rupee2000Dispenser              implements              Dispenser              {              private              Dispenser              next              =              null              ;              @Override              public              void              setNextDispencer              (              Dispenser              next              )              {              this              .              next              =              next              ;              }              @Override              public              void              dispense              (              Integer              amount              )              {              int              num              =              amount              /              2000              ;              int              remainder              =              amount              %              2000              ;              System              .              out              .              println              (              "Dispensing "              +              num              +              " 2000 note"              );              if              (              remainder              !=              0              )              {              if              (              next              !=              null              )              this              .              next              .              dispense              (              remainder              );              else              Sout              (              "Couldn't dispense remaining amount"              );              }              }              }                      

Rupee500Dispenser

                          public              class              Rupee500Dispenser              implements              Dispenser              {              private              Dispenser              next              =              null              ;              @Override              public              void              setNextDispencer              (              Dispenser              next              )              {              this              .              next              =              next              ;              }              @Override              public              void              dispense              (              Integer              amount              )              {              int              num              =              amount              /              500              ;              int              remainder              =              amount              %              500              ;              System              .              out              .              println              (              "Dispensing "              +              num              +              " 500 note"              );              if              (              remainder              !=              0              )              {              if              (              next              !=              null              )              this              .              next              .              dispense              (              remainder              );              else              Sout              (              "Couldn't dispense remaining amount"              );              }              }              }                      

Rupee100Dispenser

                          public              class              Rupee100Dispenser              implements              Dispenser              {              private              Dispenser              next              =              null              ;              @Override              public              void              setNextDispencer              (              Dispenser              next              )              {              this              .              next              =              next              ;              }              @Override              public              void              dispense              (              Integer              amount              )              {              int              num              =              amount              /              100              ;              int              remainder              =              amount              %              100              ;              System              .              out              .              println              (              "Dispensing "              +              num              +              " 100 note"              );              if              (              remainder              !=              0              )              {              if              (              next              !=              null              )              this              .              next              .              dispense              (              remainder              );              else              Sout              (              "Couldn't dispense remaining amount"              );              }              }              }                      

ATMDispenseChain.java

                          public              class              ATMDispenseChain              {              public              ATMDispenseChain              ()              {              private              Dispenser              dispenser              ;              public              ATMDispenseChain              (){              dispenser              =              new              Rupee2000Dispenser              ();              dispenser              .              setNextDispencer              (              new              Rupee500Dispenser              ().              setNextDispencer              (              new              Rupee100Dispenser              ()));              }              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              ATMDispenseChain              atmdispenser              =              new              ATMDispenseChain              ();              atmdispenser              .              dispense              (              2600              );              atmdispenser              .              dispense              (              3300              );              }              }                      

Command Pattern

Used to abstract business logic into discrete actions called commands.

  • Achieves loose coupling between 2 classes: Invoker class calls method on Receiver class to perform business operation called Command.
  • Runnable in java uses command DP.

FileSystemReceiver.java

                          public              interface              FileSystemReceiver              {              void              openFile              ();              void              closeFile              ();              }                      

LinuxFileSystemReceiver.java

                          public              class              LinuxFileSystemReceiver              implements              FileSystemReceiver              {              @Override              public              void              openFile              ()              {              System              .              out              .              println              (              "Opening file in Linux"              );              }              @Override              public              void              closeFile              ()              {              System              .              out              .              println              (              "Closing file in Linux"              );              }              }                      

WindowsFileSystemReceiver.java

                          public              class              WindowsFileSystemReceiver              implements              FileSystemReceiver              {              @Override              public              void              openFile              ()              {              System              .              out              .              println              (              "Opening file in Windows"              );              }              @Override              public              void              closeFile              ()              {              System              .              out              .              println              (              "Closing file in Windows"              );              }              }                      

Command.java

                          public              interface              Command              {              void              run              ();              }                      

OpenFileCommand.java

                          public              class              OpenFileCommand              implements              Command              {              private              FileSystemReceiver              fileSystem              ;              public              OpenFileCommand              (              FileSystemReceiver              fs              ){              this              .              fileSystem              =              fs              ;              }              @Override              public              void              run              ()              {              this              .              fileSystem              .              openFile              ();              }              }                      

CloseFileCommand.java

                          public              class              CloseFileCommand              implements              Command              {              private              FileSystemReceiver              fileSystem              ;              public              CloseFileCommand              (              FileSystemReceiver              fs              ){              this              .              fileSystem              =              fs              ;              }              @Override              public              void              run              ()              {              this              .              fileSystem              .              closeFile              ();              }              }                      
                          public              class              FileInvoker              {              public              Command              command              ;              public              FileInvoker              (              Command              c              )              {              this              .              command              =              c              ;              }              public              void              execute              ()              {              this              .              command              .              run              ();              }              }                      

FileSystemClient.java

                          public              class              FileSystemClient              {              public              static              void              main              (              String              []              args              )              {              FileSystemReceiver              fs              ;              if              (              System              .              getProperty              (              "os.name"              ).              contains              (              "Windows"              ))              {              fs              =              new              WindowsFileSystemReceiver              ();              }              else              {              fs              =              new              UnixFileSystemReceiver              ();              }              OpenFileCommand              openFileCommand              =              new              OpenFileCommand              (              fs              );              FileInvoker              file              =              new              FileInvoker              (              openFileCommand              );              file              .              execute              ();              CloseFileCommand              closeFileCommand              =              new              CloseFileCommand              (              fs              );              FileInvoker              file              =              new              FileInvoker              (              closeFileCommand              );              file              .              execute              ();              }              }                      

Interpreter Pattern

Used for defining a grammatical representation for a language and provides an interpreter to deal with this grammar

  • Not much prevelant design pattern
  • Used in java.util.Pattern class.
  • Useful for creating syntax tree of the grammer.

Iterator Pattern

Lets us traverse elements of a group of objects (collection) without exposing the underlying representations (list, map, set etc.)

  • Different kinds of iterators can be provided as per our requirements.
  • Use Iterator DP, when collection has complex data structure under the hood & we wish to hide its complexity from the clients.

iterator-pattern

Constituents: :

  • Iterator
  • Aggregate or Collection
  • ConcreteIterator

Channel.java

                          public              class              Channel              {              private              String              name              ;              private              String              type              ;              public              Channel              (              String              name              ,              String              type              ){              this              .              number              =              name              ;              this              .              type              =              type              ;              }              public              String              getName              ()              {              return              name              ;              }              public              String              getType              ()              {              return              type              ;              }              @Override              public              String              toString              (){              return              "Name="              +              name              +              ", Type="              +              type              ;              }              }                      

ChannelCollection.java

                          public              interface              ChannelCollection              {              public              void              addChannel              (              Channel              c              );              public              void              removeChannel              (              Channel              c              );              public              ChannelIterator              iterator              (              String              type              );              }                      

ChannelIterator.java

                          public              interface              ChannelIterator              {              public              boolean              hasNext              ();              public              Channel              next              ();              }                      

ChannelCollectionImpl.java

                          public              class              ChannelCollectionImpl              implements              ChannelCollection              {              private              List              <              Channel              >              channelsList              =              new              ArrayList              <>();              public              void              addChannel              (              Channel              c              )              {              this              .              channelsList              .              add              (              c              );              }              public              void              removeChannel              (              Channel              c              )              {              this              .              channelsList              .              remove              (              c              );              }              @Override              public              ChannelIterator              iterator              (              String              type              )              {              return              new              ChannelIteratorImpl              (              type              ,              this              .              channelsList              );              }              }                      

ChannelIteratorImpl.java

                          public              class              ChannelIteratorImpl              implements              ChannelIterator              {              private              String              type              ;              private              List              <              Channel              >              channelsList              ;              private              Integer              position              ;              public              ChannelIteratorImpl              (              String              type              ,              List              <              Channel              >              channelsList              )              {              this              .              type              =              type              ;              this              .              channelsList              =              channelsList              ;              this              .              position              =              0              ;              }              @Override              public              boolean              hasNext              ()              {              while              (              position              <              channelsList              .              size              ())              {              Channel              c              =              channelsList              .              get              (              position              );              if              (              c              .              getType              ().              equals              (              type              )              ||              type              .              equals              (              "ALL"              ))              return              true              ;              else              position              ++;              }              return              false              ;              }              @Override              public              Channel              next              ()              {              Channel              c              =              channelsList              .              get              (              position              );              position              ++;              return              c              ;              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              args              [])              {              ChannelCollection              channels              =              new              ChannelIteratorImpl              ();              channels              .              addChannel              (              new              Channel              (              "ABP News"              ,              "News"              ));              channels              .              addChannel              (              new              Channel              (              "MTV"              ,              "Music"              ));              channels              .              addChannel              (              new              Channel              (              "IndiaTV"              ,              "News"              ));              channels              .              addChannel              (              new              Channel              (              "Aaj Tak"              ,              "News"              ));              channels              .              addChannel              (              new              Channel              (              "Mastii"              ,              "Music"              ));              channels              .              addChannel              (              new              Channel              (              "B4U"              ,              "Music"              ));              channels              .              addChannel              (              new              Channel              (              "Zee News"              ,              "News"              ));              channels              .              addChannel              (              new              Channel              (              "NDTV"              ,              "News"              ));              ChannelIterator              newsChannelIterator              =              channels              .              iterator              (              "News"              );              ChannelIterator              musicChannelIterator              =              channels              .              iterator              (              "Music"              );              ChannelIterator              allChannelIterator              =              channels              .              iterator              (              "All"              );              while              (              newsChannelIterator              .              hasNext              ())              {              Channel              c              =              newsChannelIterator              .              next              ();              SOUT              (              c              .              toString              ());              }              while              (              musicChannelIterator              .              hasNext              ())              {              Channel              c              =              musicChannelIterator              .              next              ();              SOUT              (              c              .              toString              ());              }              while              (              allChannelIterator              .              hasNext              ())              {              Channel              c              =              allChannelIterator              .              next              ();              SOUT              (              c              .              toString              ());              }              }              }                      

Mediator Pattern

Used to provide a centralised communication medium to objects.

  • Reduces chaotic dependencies between object by restricting direct communicatio between them & forces them to collaborate only via Mediator object.
  • ATC at airport is a real-time great example for Mediator DP.
  • Fewer the dependencies a class carries, easier is to modify & maintain that class.
  • Objects communicating via mediator are called Colleague objects.
  • Colleagues are not aware of each other's existence, thus enabling loose coupling.

Constituents :

  • Mediator – Interface for communication between Colleagues.
  • Colleague – Interface for Colleagues.
  • ConcreteColleague – Individual object which communicates with each other via Mediator.

ATC.java

                          public              class              ATC              {              private              List              <              String              >              airportList              =              new              ArrayList              <>();              private              isAirStripFree              =              true              ;              public              void              allowTakeOff              (              String              flightId              )              {              if              (              isAirStripFree              )              airportList              .              remove              (              flightId              );              }              public              void              allowLanding              (              String              flightId              )              {              if              (              isAirStripFree              )              airportList              .              add              (              flightId              );              }              }                      

Flight.java

                          public              interface              Flight              {              String              flightId              ;              ATC              controller              ;              public              Flight              (              String              id              ,              ATC              atc              )              {              flightId              =              id              ;              controller              =              atc              ;              }              public              void              seekTakeOff              ();              public              void              seekLanding              ();              }                      

AirlinesFlight.java

                          public              class              AirlinesFlight              implements              Flight              {              public              AirlinesFlight              (              String              id              ,              ATC              atc              )              {              super              (              id              ,              atc              );              }              public              void              seekTakeOff              ()              {              controller              .              allowTakeOff              (              flightId              );              }              public              void              seekLanding              ()              {              controller              .              allowLanding              (              flightId              );              }              }                      

CargoFlight.java

                          public              class              CargoFlight              implements              Flight              {              public              CargoFlight              (              String              id              ,              ATC              atc              )              {              super              (              id              ,              atc              );              }              public              void              seekTakeOff              ()              {              controller              .              allowTakeOff              (              flightId              );              }              public              void              seekLanding              ()              {              controller              .              allowLanding              (              flightId              );              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              args              [])              {              ATC              atc              =              new              ATC              ();              Flight              spicejetBLU_DLI              =              new              AirlinesFlight              (              "SP121"              ,              atc              );              Flight              dtdcBLU_KUK              =              new              CargoFlight              (              "DTDC37"              ,              atc              );              Flight              goairCHD_BLU              =              new              AirlinesFlight              (              "GA763"              ,              atc              );              goairCHD_BLU              .              seekLanding              ();              dtdcBLU_KUK              .              seekTakeOff              ();              goairCHD_BLU              .              seekTakeOff              ();              spicejetBLU_DLI              .              seekTakeOff              ();              }              }                      

Memento Pattern

Used to restore state of an object to a previous state. Also called as snapshot pattern.

  • Used in IDEs for creating snapshots of project in development.
  • Used in undo/redo operations.
  • Used in such applications in which object's state is continuously changing and the user may decide to rollback or undo the changes at any point.

Constituents :

  • Originator – Creates & rolls back a Memento.
  • Caretaker – Manages & keeps track of multiple Mementos.
  • Memento – Lock box that is written and read by the Originator, and shepherded by the Caretaker.
    • Is an Immutable object so that once created, its state couldn't be changed.

Article.java

                          public              class              Article              {              private              long              id              ;              private              String              title              ;              private              String              content              ;              public              Article              (              long              id              ,              String              title              )              {              this              .              id              =              id              ;              this              .              title              =              title              ;              }              //Setters and Getters              public              ArticleMemento              createMemento              ()              {              return              new              ArticleMemento              (              id              ,              title              ,              content              );              }              public              void              restore              (              ArticleMemento              m              )              {              this              .              id              =              m              .              getId              ();              this              .              title              =              m              .              getTitle              ();              this              .              content              =              m              .              getContent              ();              }              @Override              public              String              toString              ()              {              return              "Article [id="              +              id              +              ", title="              +              title              +              ", content="              +              content              +              "]"              ;              }              }                      

ArticleMemento.java

                          public              final              class              ArticleMemento              {              private              final              long              id              ;              private              final              String              title              ;              private              final              String              content              ;              public              ArticleMemento              (              long              id              ,              String              title              ,              String              content              )              {              this              .              id              =              id              ;              this              .              title              =              title              ;              this              .              content              =              content              ;              }              // Getters for 3 variables              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              Article              article              =              new              Article              (              1              ,              "AWS"              );              article              .              setContent              (              "EC2 is Elastic Compute Cloud"              );              SOUT              (              article              );              ArticleMemento              memento              =              article              .              createMemento              ();              article              .              setContent              (              "S3 is Simple Storage Service"              );              SOUT              (              article              );              article              .              restore              (              memento              );              SOUT              (              article              );              }              }                      

OUTPUT

            Article              [              id              =1,              title              =AWS,              content              =EC2 is Elastic Compute Cloud] Article              [              id              =1,              title              =AWS,              content              =S3 is Simple Storage Service] Article              [              id              =1,              title              =AWS,              content              =EC2 is Elastic Compute Cloud]                      

Observer Pattern

Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. Also called as publish-subscribe pattern.

  • In observer pattern, there are many observers (subscriber objects) that are observing a particular subject (publisher object).
  • Helps in making the objects loosely coupled.
  • Defines a subscription mechanism to notify multiple objects about any events that happen to the object they're observing.
  • Used when changes in one object state may require changing other objects.
  • Used in real-time like newspaper subscription, push notifications, database triggered updates etc.
  • Model-View-Controller (MVC) frameworks also use Observer pattern where Model is the Subject and Views are observers that can register to get notified of any change to the model.

Constituents :

  • Subject – Interface defining the operations for attaching and de-attaching Observers to Subject.
  • ConcreteSubject – concrete Subject class. It maintain the state of the object and when a change in the state occurs it notifies the attached Observers.
  • Observer – Interface defining the operations that are used for notify this object.
  • ConcreteObserver – concrete Observer implementations.

Subject.java

                          public              interface              Subject              {              public              void              attach              (              Observer              o              );              public              void              detach              (              Observer              o              );              public              void              notifyUpdate              (              Message              m              );              }                      

MessagePublisher.java

                          public              class              MessagePublisher              implements              Subject              {              private              List              <              Observer              >              observers              =              new              ArrayList              <>();              @Override              public              void              attach              (              Observer              o              )              {              observers              .              add              (              o              );              }              @Override              public              void              detach              (              Observer              o              )              {              observers              .              remove              (              o              );              }              @Override              public              void              notifyUpdate              (              Message              m              )              {              for              (              Observer              o:              observers              )              {              o              .              update              (              m              );              }              }              }                      

Observer.java

                          public              interface              Observer              {              public              void              update              (              Message              m              );              }                      

MessageSubscriber.java

                          public              class              MessageSubscriber              implements              Observer              {              String              subscriptionId              ;              public              MessageSubscriber              (              String              subscriptionId              )              {              this              .              subscriptionId              =              subscriptionId              ;              }              @Override              public              void              update              (              String              message              )              {              SOUT              (              "MessageSubscriber :: "              +              subscriptionId              +              " | "              +              message              );              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              MessageSubscriber              s1              =              new              MessageSubscriber              (              "1"              );              MessageSubscriber              s1              =              new              MessageSubscriber              (              "2"              );              MessageSubscriber              s1              =              new              MessageSubscriber              (              "3"              );              MessagePublisher              p              =              new              MessagePublisher              ();              p              .              attach              (              s1              );              p              .              attach              (              s2              );              p              .              notifyUpdate              (              new              Message              (              "First Message"              ));              //s1 and s2 will receive the update              p              .              detach              (              s1              );              p              .              attach              (              s3              );              p              .              notifyUpdate              (              new              Message              (              "Second Message"              ));              //s2 and s3 will receive the update              }              }                      

State Pattern

Lets an object alter its behavior when its internal state changes. It appears as if the object changed its class.

  • For every possible state of an object, there is a separate concrete class.
  • Each concrete state object will have logic to accept/reject state transition request.
  • Java.Thread is an example of state pattern.

Constituents :

  • State – Interface define operations which each state must handle.
  • Concrete States – classes which contain the state specific behavior.
  • Context – Defines an interface to client to interact.

state-dp

DocumentState.java

                          public              interface              PackageState              {              public              void              updateState              (              DeliveryContext              ctx              );              }                      

Ordered.java

                          public              class              Ordered              implements              PackageState              {              @Override              public              void              updateState              (              DeliveryContext              ctx              )              {              SOUT              (              "Package: Ordered !!"              );              ctx              .              setCurrentState              (              new              Shipped              ());              }              }                      

Shipped.java

                          public              class              Shipped              implements              PackageState              {              @Override              public              void              updateState              (              DeliveryContext              ctx              )              {              SOUT              (              "Package: Shipped !!"              );              ctx              .              setCurrentState              (              new              Delivered              ());              }              }                      

Delivered.java

                          public              class              Delivered              implements              PackageState              {              @Override              public              void              updateState              (              DeliveryContext              ctx              )              {              SOUT              (              "Package: Delivered !!"              );              }              }                      

DeliveryContext.java

                          public              class              DeliveryContext              {              private              PackageState              currentState              ;              private              String              packageId              ;              public              DeliveryContext              (              PackageState              currentState              ,              String              packageId              )              {              this              .              currentState              =              currentState              ;              this              .              packageId              =              packageId              ;              }              public              void              update              ()              {              currentState              .              updateState              (              this              );              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              DeliveryContext              ctx              =              new              DeliveryContext              (              new              Ordered              (),              "Realme ear phones"              );              ctx              .              update              ();              // Ordered              ctx              .              update              ();              // Shipped              ctx              .              update              ();              // Delivered              }              }                      

Strategy Pattern

Used when we choose a specific implementation of task in run time – out of multiple other implementations for same task.

  • Involves removing the algorithm from its host class and putting it in separate class, so that there might be different strategies, which can be selected in runtime.
  • Allows to add new algorithm without modifying existing algorithms or context class.

strategy-dp

UDGOrderingStrategy.java

                          public              interface              UDGOrderingStrategy              {              public              List              <              String              >              reorder              (              List              <              String              >);              }                      

UDGSearchContext.java

                          public              class              UDGSearchContext              {              UDGOrderingStrategy              strategy              ;              public              void              setStrategy              (              UDGOrderingStrategy              strategy              )              {              this              .              strategy              =              strategy              ;              }              public              use              (              List              <              String              >              usergroups              )              {              strategy              .              reorder              (              usergroups              );              }              }                      

SupplierUsageStrategy.java

                          public              class              SupplierUsageStrategy              implements              UDGOrderingStrategy              {              public              List              <              String              >              reorder              (              List              <              String              >              usergroups              )              {              SOUT              (              "Reordering usergroups on supplier usage"              );              return              usergroups              ;              }              }                      

TextMatchingStrategy.java

                          public              class              TextMatchingStrategy              implements              UDGOrderingStrategy              {              public              List              <              String              >              reorder              (              List              <              String              >              usergroups              )              {              SOUT              (              "Reordering usergroups on text matching"              );              return              usergroups              ;              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              []              args              )              {              UDGSearchContext              context              =              new              UDGSearchContext              ();              List              <              String              >              usergroups              =              {              "lg washing machine"              ,              "automatic washing machine"              ,              "home washing machine"              ,              "industrial washing machine"              };              context              .              setStrategy              (              new              SupplierUsageStrategy              ());              context              .              use              (              usergroups              );              context              .              setStrategy              (              new              TextMatchingStrategy              ());              context              .              use              (              usergroups              );              }              }                      

Template method Pattern

Used to create a method stub (sequence & default methods) and deferring some of the steps of implementation to the subclasses.

  • Used for defining fixed sequencial steps for any alogirithmic process. This basic skeleton can't be overridden in sub classes.
  • Template method must be final so that, any changes in the underlying methods & their sequence in forbidden. Here, buildhouse() is a template method.
  • All default functions must be final so that, no change can be done in subclasses.
  • All such functions which needs to be implemented in subclasses must be abstract.

House.java

                          public              abstract              class              House              {              public              final              void              buildhouse              ()              {              constructBase              ();              constructWalls              ();              paintHouse              ();              }              public              abstract              void              constructWalls              ();              private              final              void              constructBase              ()              {              SOUT              (              "Base has been constructed."              );              }              private              final              void              paintHouse              ()              {              SOUT              (              "House has been painted."              );              }              }                      

ConcreteHouse.java

                          public              class              ConcreteHouse              extends              House              {              @Override              public              void              constructWalls              ()              {              SOUT              (              "Concrete halls has been constructed."              );              }              }                      

GlassHouse.java

                          public              class              GlassHouse              extends              House              {              @Override              public              void              constructWalls              ()              {              SOUT              (              "Glass halls has been constructed."              );              }              }                      

Runner.java

                          public              class              Runner              {              public              static              void              main              (              String              args              [])              {              House              house              =              null              ;              house              =              new              ConcreteHouse              ();              house              .              buildhouse              ();              house              =              new              GlassHouse              ();              house              .              buildhouse              ();              }              }                      

Visitor Pattern

Used when we wish to add new behavior to an existing hierarchy of classes but without modifying their source codes.

  • Separates the algorithm from the data structure on which it operates upon.
  • Double dispatch mechanism is used.

Constituents :

  • Vistor – Used for adding the additional behavior. (LoggingVisitor.java)
  • ConcreteVisitor – (CatalinaLogging.java, KibanaLogging.java)
  • Visitable – The data structure on which some additional behavior is added using Visitor. (QueryFormatter.java)
  • ConcreteVisitable – (MCATSearchQueryFormatter.java, UserGroupSearchQueryFormatter.java)

QueryFormatter.java

                          public              abstract              class              QueryFormatter              {              public              final              void              removeLocations              (              String              searchQuery              ){              }              public              final              void              removeMUs              (              String              searchQuery              ){              }              public              void              logResults              (              LoggingVisitor              v              );              }                      

MCATSearchQueryFormatter.java

                          public              class              MCATSearchQueryFormatter              extends              QueryFormatter              {              public              void              logResults              (              LoggingVisitor              v              )              {              v              .              visit              (              this              );              }              }                      

UserGroupSearchQueryFormatter.java

                          public              class              UserGroupSearchQueryFormatter              extends              QueryFormatter              {              public              void              logResults              (              LoggingVisitor              v              )              {              v              .              visit              (              this              );              }              }                      

LoggingVisitor.java

                          public              interface              LoggingVisitor              {              public              void              visit              (              MCATSearchQueryFormatter              mcatsearch              );              public              void              visit              (              UserGroupSearchQueryFormatter              usergroupsearch              );              }                      

CatalinaLogging.java

                          public              class              CatalinaLogging              extends              LoggingVisitor              {              @Override              public              void              visit              (              MCATSearchQueryFormatter              mcatsearch              )              {              SOUT              (              "Catalina logging configured for MCAT Search API"              );              }              @Override              public              void              visit              (              UserGroupSearchQueryFormatter              usergroupsearch              )              {              SOUT              (              "Catalina logging configured for UserGroup Search API"              );              }              }                      

KibanaLogging.java

                          public              class              KibanaLogging              extends              LoggingVisitor              {              @Override              public              void              visit              (              MCATSearchQueryFormatter              mcatsearch              )              {              SOUT              (              "Kibana logging configured for MCAT Search API"              );              }              @Override              public              void              visit              (              UserGroupSearchQueryFormatter              usergroupsearch              )              {              SOUT              (              "Kibana logging configured for UserGroup Search API"              );              }              }                      

Here, both Search APIs are already functioning data objects. We have added logging to these using Visitors.

How to do in java Journal Dev Refactoring Guru


Design Principles

SOLID Principles are the 5 most recommended design principles.

  • Forms the fundamental guidlines for building OOPs applications which are robust, extensible & maintainable.
  • Is an acronym

S.O.L.I.D

  • Single Responsibility :
    • One class should have one and only one responsibility.
    • Also called as Separation of Concerns.
  • Open Closed :
    • SW components should be open for extensions, but closed for modifications.
  • Liskov's Substitution :
    • Supplements Open Closed.
    • Derived types must be completely substitutable for their base types.
    • Extremely helpful in run-time polymorphism.
  • Interface Segregation :
    • Clients should not be forced to implement unnecessary methods which they will not use.
    • If such needs looks inevitable, break that interface into separate interfaces.
  • Dependency Inversion :
    • Depend on abstractions, not on concretions.
    • Software should be designed in such a way that various modules can be separated from each other using an abstract layer to bind them together.
    • Bean configuration is a classic example.

Miscellaneous Design Patterns

DAO Design Pattern

  • DAO stands for Data Access Object
  • Used to separate the data persistence logic in a separate layer.

dao

Advantages:

  • Any change required in persistence mechanism affects only the DAO layer. Either we store our data in in-memory DB, no-sql DB or Files.
  • Much easier to write unit tests & mock.
  • Emphasises working with interfaces rather than implementation.

MVC Pattern

  • MVC stands for Model View Controller
  • Used to separate the logic of different layers in a program in independent units. Part of the Separation of Concern principle.
  • Provides a clear-cut separation between domain objects which represents real-world entities and the presentation layer we see on the screen.
  • Domain objects should be completely independent and should work without a View layer as well.

mvc

Advantes:

  • Allows rapid application development. Parallel teams may work upon {Views}, {Models & Controllers}.
  • Since, view mechanism is totally independent of service controllers. Its quite easy to port views to PWAs, Angular, React etc.

Dependency Injection Pattern

  • Allows in removing the hard-coded dependencies.
  • Moves the dependency resolution from compile-time to runtime.
  • Dependency Injection in Java is a way to achieve Inversion of control (IoC) in our application by moving objects binding from compile time to runtime.
  • We can achieve IoC through Factory Pattern, Template Method Design Pattern & Strategy Pattern too.

Design Patterns That Use Interfaces in Java

Source: https://jaykay12.github.io/tech/design-patterns/

0 Response to "Design Patterns That Use Interfaces in Java"

Enregistrer un commentaire

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel