Tuesday, 17 September 2019

java Design pattern


Design principles:
SOLID Principle

1. Single Responsibility Principle

“One class should have one and only one responsibility”
We can plenty of classes in all popular Java libraries which follow single responsibility principle. For example, in log4j, we have different classes with logging methods, different classes are logging levels and so on.

In given example, we have two classes Person and Account. Both have single responsibility to store their specific information. If we want to change state of Person then we do not need to modify the class Account and vice-versa.

2. Open Closed Principle

“Software components should be open for extension, but closed for modification”
This means that our classes should be designed such a way that whenever fellow developers wants to change the flow of control in specific conditions in application, all they need to extend our class and override some functions and that’s it.
 spring framework has class DispatcherServlet. This class acts as front controller for String based web applications. 
Please note that apart from passing initialization parameters during application startup, we can override methods as well to modify the behavior of target class by extending the classes. For example, struts Action classes are extended to override the request processing logic.

 

3. Liskov’s Substitution Principle

“Derived types must be completely substitutable for their base types”
An example of LSP can be custom property editors in Spring framework. Spring provides property editors to represent properties in a different way than the object itself e.g. parsing human readable inputs from HTTP request parameters or displaying human readable values of pure java objects in view layer e.g. Currency or URL.

4. Interface Segregation Principle

“Clients should not be forced to implement unnecessary methods which they will not use”https://howtodoinjava.com/best-practices/5-class-design-principles-solid-in-java/
Take an example. Developer Alex created an interface Reportable and added two methods generateExcel() and generatedPdf(). Now client ‘A’ wants to use this interface but he intend to use reports only in PDF format and not in excel. Will he be able to use the functionality easily?
NO. He will have to implement both the methods, out of which one is extra burden put on him by designer of software. Either he will implement another method or leave it blank. This is not a good design.
So what is the solution? Solution is to create two interfaces by breaking the existing one. They should be like PdfReportable and ExcelReportable. This will give the flexibility to user to use only required functionality only.
The best place to look for IPS examples is Java AWT event handlers for handling GUI events fired from keyboard and mouse. It has different listener classes for each kind of event. We only need to write handlers for events, we wish to handle. Nothing is mandatory.
Some of the listeners are –
·         FocusListener
·         KeyListener
·         MouseMotionListener
·         MouseWheelListener
·         TextListener
·         WindowFocusListener
Anytime, we wish to handle any event, just find out corresponding listener and implement it.
MouseMotionListenerImpl.java
public class MouseMotionListenerImpl implements MouseMotionListener
{
    @Override
    public void mouseDragged(MouseEvent e) {
        //handler code
    }

    @Override
    public void mouseMoved(MouseEvent e) {
        //handler code
    }
}

5. Dependency Inversion Principle

we should design our software in such a way that various modules can be separated from each other using an abstract layer to bind them together. In spring framework, all modules are provided as separate components which can work together by simply injected dependencies in other module. 


Java Design Best Practices

8 signs of bad unit test cases

5 class design principles [S.O.L.I.D.] in java

Unit testing best practices

It’s overwhelmingly easy to write bad unit tests that add very little value to a project while inflating the cost of code changes astronomically. Learn how to write them correctly.

 

A new approach for exception handling

A new approach uses static inner classes for every new exceptional scenario. Worth reading for future software designers.

Java exception handling using inner classes

Covering some well-known and some little known practices which you must consider while handling exceptions in your next java programming assignment.

Java executor framework best practices

Some best practices which you need to keep in mind while designing your next multi-threaded application.
1.     Always run your java code against static analysis tools like PMD and FindBugs to look for deeper issues. They are very helpful in determining ugly situations which may arise in future.
2.     Always cross check and better plan a code review with senior guys to detect and possible deadlock or livelock in code during execution
  1. In multi-threaded programs, make a habit of catching errors too, not just exceptions. Sometimes unexpected things happen and Java throws an error at you, apart from an exception.
  2. Use a back-off switch, so if something goes wrong and is non-recoverable, you don’t escalate the situation by eagerly starting another loop. Instead, you need to wait until the situation goes back to normal and then start again.
  3. Please note that the whole point of executors is to abstract away the specifics of execution, so ordering is not guaranteed unless explicitly stated.

5 Reasons You Should Consider Migrating Your Legacy Systems

There are several reasons for migrating from old legacy systems to new advanced systems. Here are 5 of them.

13 best practices for writing spring configuration files

13 best practices for writing highly maintainable spring XML configurations.

 

Java Serialization – Dos and don’ts for correct serialization

1.       Java serialization incompatible changes
Deleting fields: If a field is deleted in a class, the stream written will not contain its value. When the stream is read by an earlier class, the value of the field will be set to the default value because no value is available in the stream. 
Moving classes up or down the hierarchy– This cannot be allowed since the data in the stream appears in the wrong sequence.
Changing a non-static field to static or a non-transient field to transient –  When relying on default serialization, this change is equivalent to deleting a field from the class.
Changing the declared type of a primitive field –Earlier versions of the class attempting to read the field will fail because the type of the data in the stream does not match the type of the field.
Adding the writeReplace or readResolve method to a class is incompatible if the behavior would produce an object that is incompatible with any older version of the class.

Changing a class from a non-enum type to an enum type or vice versa since the stream will contain data that is incompatible with the implementation of the available class.

Changing a class from Serializable to Externalizable or vice-versa is an incompatible change since the stream will contain data that is incompatible with the implementation of the available class.



2.       Java serialization compatible changes
Adding fields –field in the object will be initialized to the default value for its type. If class-specific initialization is needed, the class may provide a readObject method that can initialize the field to non default values.

Adding classes – ince there is no information in the stream from which to initialize the object, the class’s fields will be initialized to the default values.
Removing classes – the fields and objects corresponding to that class are read from the stream. Primitive fields are discarded, but the objects referenced by the deleted class are created, since they may be referred to later in the stream. 
Adding writeObject/readObject methods – If the version reading the stream has these methods then readObject is expected, as usual, to read the required data written to the stream by the default serialization.  It should call defaultReadObject first before reading any optional data. The writeObject method is expected as usual to call defaultWriteObject to write the required data and then may write optional data.

Removing writeObject/readObject methods – 

Adding java.io.Serializable –  This is equivalent to adding types. There will be no values in the stream for this class so its fields will be initialized to default values. The support for subclassing nonserializable classes requires that the class’s super type have a no-arg constructor and the class itself will be initialized to default values. If the no-arg constructor is not available, the InvalidClassException is thrown.

Changing the access to a field –   The access modifiers public, package, protected, and private have no effect on the ability of serialization to assign values to the fields.
Changing a field from static to non-static or transient to non transient –



3.       serialVersionUID

Always include it as a field- for example: “private static final long serialVersionUID = 7526472295622776147L; ” include this field even in the first version of the class, as a reminder of its importance.
Do not change the value of this field in future versions, unless you are knowingly making changes


4.       readObject() and writeObject() methods
Deserialization must be treated as any constructor :  validate the object state at the end of deserializing – this implies that readObject should almost always be implemented in Serializable classes, such that this validation is performed.

5.    More serialization best practices
Use javadoc’s @serial tag to denote Serializable fields.

The .ser extension is conventionally used for files representing serialized objects.

No static or transient fields undergo default serialization.

Extendable classes should not be Serializable, unless necessary.

Inner classes should rarely, if ever, implement Serializable.
Container classes should usually follow the style of Hashtable, which implements Serializable by storing keys and values, as opposed to a large hash table data structure.


6. Sample class following serialization best practices
7. Serialization and deserialization example

Music notation
Java serialization is the process of converting an object into a stream of bytes so we can do stuff like store it on disk or send it over the network. Deserialization is the reverse process – converting a stream of bytes into an object in memory.

1. Java serialVersionUID Syntax

private static final long serialVersionUID = 4L;
Serialization-deserialization-demo

Java serialization and deserialization example


Types of Design Patterns
There are mainly three types of design patterns:
These design patterns are all about class instantiation or object creation.
Creational design patterns are Factory Method, Abstract Factory, Builder, Singleton, Object Pool and Prototype.

Factory Method

related to object creation. In Factory pattern, we create object without exposing the creation logic to client and the client use the same common interface to create new type of object.

Factory pattern introduces loose coupling between classes which is the most important principle one should consider and apply while designing the application architecture.
https://howtodoinjava.files.wordpress.com/2012/10/class_diagram_of_factory_pattern_in_java1.png
Factory pattern is most suitable where there is some complex object creation steps are involved. To ensure that these steps are centralized and not exposed to composing classes, factory pattern should be used.

Abstract factory pattern 

https://howtodoinjava.files.wordpress.com/2012/10/abstract_fctory_package_diagram.png

Sequence Diagram

https://howtodoinjava.files.wordpress.com/2012/10/abstract_factory_sequence_diagram.png
Car.java
public abstract class Car {

  public Car(CarType model, Location location){
    this.model = model;
    this.location = location;
  }

  protected abstract void construct();

  private CarType model = null;
  private Location location = null;

  //getters and setters

  @Override
  public String toString() {
    return "Model- "+model + " built in "+location;
  }
}
This adds extra work of creating another enum for storing different locations.

Location.java
public enum Location {
  DEFAULT, USA, ASIA
}
All car types will also have additional location property. We are writing only for the luxury car. Same follows for small and sedan also.
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
  }
}
So far we have created basic classes. Now let’s have different car factories which is the core idea behind abstract factory pattern.
AsiaCarFactory.java
public class AsiaCarFactory
{
  public static Car buildCar(CarType model)
  {
    Car car = null;
    switch (model)
    {
      case SMALL:
      car = new SmallCar(Location.ASIA);
      break;

      case SEDAN:
      car = new SedanCar(Location.ASIA);
      break;

      case LUXURY:
      car = new LuxuryCar(Location.ASIA);
      break;

      default:
      //throw some exception
      break;
    }
    return car;
  }
}
DefaultCarFactory.java
public class DefaultCarFactory
{
  public static Car buildCar(CarType model)
  {
    Car car = null;
    switch (model)
    {
      case SMALL:
      car = new SmallCar(Location.DEFAULT);
      break;

      case SEDAN:
      car = new SedanCar(Location.DEFAULT);
      break;

      case LUXURY:
      car = new LuxuryCar(Location.DEFAULT);
      break;

      default:
      //throw some exception
      break;
    }
    return car;
  }
}

USACarFactory.java
public class USACarFactory
{
  public static Car buildCar(CarType model)
  {
    Car car = null;
    switch (model)
    {
      case SMALL:
      car = new SmallCar(Location.USA);
      break;

      case SEDAN:
      car = new SedanCar(Location.USA);
      break;

      case LUXURY:
      car = new LuxuryCar(Location.USA);
      break;

      default:
      //throw some exception
      break;
    }
  return car;
  }
}
Well, now we have all 3 different Car factories. Now, we have to abstract the way these factories are accessed.
CarFactory.java
public class CarFactory
{
  private CarFactory() {
    //Prevent instantiation
  }

  public static Car buildCar(CarType type)
  {
    Car car = null;
    Location location = Location.ASIA; //Read location property somewhere from configuration
    //Use location specific car factory
    switch(location)
    {
      case USA:
        car = USACarFactory.buildCar(type);
        break;
      case ASIA:
        car = AsiaCarFactory.buildCar(type);
        break;
      default:
        car = DefaultCarFactory.buildCar(type);
    }
  return car;
  }
}
We are done with writing code. Now, let’s test the factories and cars.
TestFactoryPattern.java
public class TestFactoryPattern
{
  public static void main(String[] args)
  {
    System.out.println(CarFactory.buildCar(CarType.SMALL));
    System.out.println(CarFactory.buildCar(CarType.SEDAN));
    System.out.println(CarFactory.buildCar(CarType.LUXURY));
  }
}

Program output:
Console
Output: (Default location is Asia)

Building small car
Model- SMALL built in ASIA

Building sedan car
Model- SEDAN built in ASIA

Building luxury car
Model- LUXURY built in ASIA


Prototype design pattern

prototype is a template of any object before the actual object is constructed. In this design pattern, an instance of actual object (i.e. prototype) is created on starting, and thereafter whenever a new instance is required, this prototype is cloned to have another instance.

Prototype Design Participants
1) Prototype : This is the prototype of actual object.
2) Prototype registry : This is used as registry service to have all prototypes accessible using simple string parameters.
3) Client : Client will be responsible for using registry service to access prototype instances.

prototype-pattern-class-diagram

Builder Pattern

The builder pattern, as name implies, is an alternative way to construct complex objects. This should be used only when you want to build different immutable objects using same object building process.
In normal practice, if you want to make a immutable User class, then you must pass all five information as parameters to constructor. It will look like this:
public User (String firstName, String lastName, int age, String phone, String address){
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    this.phone = phone;
    this.address = address;
}
Very good. Now what if only firstName and lastName are mandatory and rest 3 fields are optional. Problem !! We need more constructors.
public User (String firstName, String lastName, int age, String phone){ ... }
public User (String firstName, String lastName, String phone, String address){ ...  }
public User (String firstName, String lastName, int age){ ...   }
public User (String firstName, String lastName){ ...    }
We will need some more like above. Still can manage? Now let’s introduce our sixth attribute i.e. salary. Now it is problem.
One way it to create more constructors, and another is to loose the immutability and introduce setter methods. You choose any of both options, you loose something, right?
Here, builder pattern will help you to consume additional attributes while retaining the immutability of Use class.
And below is the way, we will use the UserBuilder in our code:

Singleton

where an application wants to have one and only one instance of any class

Singleton with eager initialization

This is a design pattern where an instance of a class is created much before it is actually required. 
public class EagerSingleton {
    private static volatile EagerSingleton instance = new EagerSingleton();

    // private constructor
    private EagerSingleton() {
    }

    public static EagerSingleton getInstance() {
        return instance;
    }
}
The above method works fine, but it has one drawback. The instance is created irrespective of it is required in runtime or not. 

2. Singleton with lazy initialization

In computer programming, lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process, until the first time it is needed. 

3. Singleton with static block initialization

If you have an idea of the class loading sequence, you can use the fact that static blocks are executed during the loading of a class, even before the constructor is called.
The above code has one drawback. Suppose there are 5 static fields in a class and the application code needs to access only 2 or 3, for which instance creation is not required at all. So, if we use this static initialization, we will have one instance created though it is required or not.

4. Singleton with bill pugh solution

Bill Pugh was main force behind the java memory model changes. His principle “Initialization-on-demand holder idiom” also uses the static block idea, but in a different way. It suggest to use static inner class.

5. Singleton using Enum

This type of implementation employs the use of enum. Enum, as written in the java docs, provided implicit support for thread safety and only one instance is guaranteed.

6. Add readResolve() to Singleton Objects

Our singleton class is:
Let’s say your application is distributed and it frequently serializes objects into the file system, only to read them later when required. Please note that de-serialization always creates a new instance. Let’s understand using an example:

Let’s serialize this class and de-serialize it after making some changes:
Unfortunately, both variables have different values of the variable “i”. Clearly, there are two instances of our class. So, again we are in the same problem of multiple instances in our application.
To solve this issue, we need to include a readResolve() method in our DemoSingleton class. This method will be invoked when you will de-serialize the object. Inside of this method, you must return the existing instance to ensure a single instance application wide.

7. Add serialVersionUId to singleton objects

Untill now, we have solved both of the problems of synchronization and serialization. Now, we are just one step away from a correct and complete implementation. The only missing part is a serial version id.
This is required in cases where your class structure changes between serialization and deserialization. A changed class structure will cause the JVM to give an exception in the de-serializing process.
java.io.InvalidClassException: singleton.DemoSingleton; local class incompatible: stream classdesc serialVersionUID = 5026910492258526905, local class serialVersionUID =3597984220566440782
at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
at java.io.ObjectInputStream.readClassDesc(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at singleton.SerializationTest.main(SerializationTest.java:24)
This problem can be solved only by adding a unique serial version id to the class. It will prevent the compiler from throwing the exception by telling it that both classes are same, and will load the available instance variables only.


2. Structural
These design patterns are about organizing different classes and objects to form larger structures and provide new functionality.
Structural design patterns are Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Private Class Data and Proxy.
Adapter Design Pattern
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
  • Wrap an existing class with a new interface.
  • Impedance match an old component to a new system
One reason has been the tribulation of designing something new, while reusing something old. There is always something not quite right between the old and the new. 
Adapter is about creating an intermediary abstraction that translates, or maps, the old component to the new system.

Check list

  1. Identify the players: the component(s) that want to be accommodated (i.e. the client), and the component that needs to adapt (i.e. the adaptee).
  2. Identify the interface that the client requires.
  3. Design a "wrapper" class that can "impedance match" the adaptee to the client.
  4. The adapter/wrapper class "has a" instance of the adaptee class.
  5. The adapter/wrapper class "maps" the client interface to the adaptee interface.
  6. The client uses (is coupled to) the new interface


source code example


  1. Identify the desired interface.
  2. Design a "wrapper" class that can "impedance match" the old to the new.
  3. The adapter/wrapper class "has a" instance of the legacy class.
  4. The adapter/wrapper class "maps" (or delegates) to the legacy object.
  5. The client uses (is coupled to) the new interface.
interface Bird
{
    // birds implement Bird interface that allows
    // them to fly and make sounds adaptee interface
    public void fly();
    public void makeSound();
}







class Sparrow implements Bird
{
    // a concrete implementation of bird
    public void fly()
    {
        System.out.println("Flying");
    }
    public void makeSound()
    {
        System.out.println("Chirp Chirp");
    }
}
interface ToyDuck
{
    // target interface
    // toyducks dont fly they just make
    // squeaking sound
    public void squeak();
}
  
class PlasticToyDuck implements ToyDuck
{
    public void squeak()
    {
        System.out.println("Squeak");
    }
}
class BirdAdapter implements ToyDuck
{
    // You need to implement the interface your
    // client expects to use.
    Bird bird;
    public BirdAdapter(Bird bird)
    {
        // we need reference to the object we
        // are adapting
        this.bird = bird;
    }
  
    public void squeak()
    {
        // translate the methods appropriately
        bird.makeSound();
    }
}
class Main
{
    public static void main(String args[])
    {
        Sparrow sparrow = new Sparrow();
        ToyDuck toyDuck = new PlasticToyDuck();
  
        // Wrap a bird in a birdAdapter so that it 
        // behaves like toy duck
        ToyDuck birdAdapter = new BirdAdapter(sparrow);
  
        System.out.println("Sparrow...");
        sparrow.fly();
        sparrow.makeSound();
  
        System.out.println("ToyDuck...");
        toyDuck.squeak();
  
        // toy duck behaving like a bird 
        System.out.println("BirdAdapter...");
        birdAdapter.squeak();
    }
}




3. Behavioral
Behavioral patterns are about identifying common communication patterns between objects and realize these patterns.
Chain of responsibility, Command, Interpreter, Iterator, Mediator, Memento, Null Object, Observer, State, Strategy, Template method, Visitor

Strategy Pattern
As always we will learn this pattern by defining a problem and using strategy pattern to solve it. 
Suppose we are building a game “Street Fighter”. For simplicity assume that a character may have four moves that is kick, punch, roll and jump. Every character has kick and punch moves, but roll and jump are optional.
How would you model your classes? 
Suppose initially you use inheritance and abstract out the common features in a Fighterclass and let other characters subclass Fighter class.
Fighter class will we have default implementation of normal actions. Any character with specialized move can override that action in its subclass. Class diagram would be as follows:
fighter1
What are the problems with above design?
What if a character doesn’t perform jump move? It still inherits the jump behavior from superclass. Although you can override jump to do nothing in that case but you may have to do so for many existing classes and take care of that for future classes too. 

What about an Interface?
Take a look at the following design:
fighter2
It’s much cleaner. We took out some actions (which some characters might not perform) out of Fighterclass and made interfaces for them.
That way only characters that are supposed to jump will implement the JumpBehavior.
What are the problems with above design?
The main problem with the above design is code reuse. Since there is no default implementation of jump and roll behavior we may have code duplicity. You may have to rewrite the same jump behavior over and over in many subclasses.

How can we avoid this?
What if we made JumpBehavior and RollBehavior classes instead of interface? Well then we would have to use multiple inheritance that is not supported in many languages due to many problems associated with it.
Here strategy pattern comes to our rescue. We will learn what the strategy pattern is and then apply it to solve our problem.
Definition:
Wikipedia defines strategy pattern as:
“In computer programming, the strategy pattern (also known as the policy pattern) is a software design pattern that enables an algorithm’s behavior to be selected at runtime. The strategy pattern
·         defines a family of algorithms,
·         encapsulates each algorithm, and
·         makes the algorithms interchangeable within that family.”
Untitled
Here we rely on composition instead of inheritance for reuse. The context would be the class that would require changing behaviors. We can change behavior dynamically. Strategy is implemented as interface so that we can change behavior without affecting our context.

Advantages:
1.    A family of algorithms can be defined as a class hierarchy and can be used interchangeably to alter application behavior without changing its architecture.
2.    By encapsulating the algorithm separately, new algorithms complying with the same interface can be easily introduced.
3.    The application can switch strategies at run-time.
4.    Strategy enables the clients to choose the required algorithm, without using a “switch” statement or a series of “if-else” statements.
5.    Data structures used for implementing the algorithm are completely encapsulated in Strategy classes. Therefore, the implementation of an algorithm can be changed without affecting the Context class.
Disadvantages:
1.    The application must be aware of all the strategies to select the right one for the right situation.
2.    Context and the Strategy classes normally communicate through the interface specified by the abstract Strategy base class. Strategy base class must expose interface for all the required behaviours, which some concrete Strategy classes might not implement.
3.    In most cases, the application configures the Context with the required Strategy object. Therefore, the application needs to create and maintain two objects in place of one.


https://cdn.journaldev.com/wp-content/uploads/2013/07/Strategy-Pattern.png
Strategy pattern is also known as Policy Pattern. We define multiple algorithms and let client application pass the algorithm to be used as a parameter. One of the best example of strategy pattern is Collections.sort() method that takes Comparator parameter. Based on the different implementations of Comparator interfaces, the Objects are getting sorted in different ways.
PaymentStrategy.java
package com.journaldev.design.strategy;

public interface PaymentStrategy {

                public void pay(int amount);
}



CreditCardStrategy.java


package com.journaldev.design.strategy;

public class CreditCardStrategy implements PaymentStrategy {

                private String name;
                private String cardNumber;
                private String cvv;
                private String dateOfExpiry;
               
                public CreditCardStrategy(String nm, String ccNum, String cvv, String expiryDate){
                                this.name=nm;
                                this.cardNumber=ccNum;
                                this.cvv=cvv;
                                this.dateOfExpiry=expiryDate;
                }
                @Override
                public void pay(int amount) {
                                System.out.println(amount +" paid with credit/debit card");
                }

}

PaypalStrategy.java
package com.journaldev.design.strategy;

public class PaypalStrategy implements PaymentStrategy {

                private String emailId;
                private String password;
               
                public PaypalStrategy(String email, String pwd){
                                this.emailId=email;
                                this.password=pwd;
                }
               
                @Override
                public void pay(int amount) {
                                System.out.println(amount + " paid using Paypal.");
                }

}


Now our strategy pattern example algorithms are ready. We can implement Shopping Cart and payment method will require input as Payment strategy.
Item.java

package com.journaldev.design.strategy;

public class Item {

                private String upcCode;
                private int price;
               
                public Item(String upc, int cost){
                                this.upcCode=upc;
                                this.price=cost;
                }

                public String getUpcCode() {
                                return upcCode;
                }

                public int getPrice() {
                                return price;
                }
               
}


ShoppingCart.java

package com.journaldev.design.strategy;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

public class ShoppingCart {

                //List of items
                List<Item> items;
               
                public ShoppingCart(){
                                this.items=new ArrayList<Item>();
                }
               
                public void addItem(Item item){
                                this.items.add(item);
                }
               
                public void removeItem(Item item){
                                this.items.remove(item);
                }
               
                public int calculateTotal(){
                                int sum = 0;
                                for(Item item : items){
                                                sum += item.getPrice();
                                }
                                return sum;
                }
               
                public void pay(PaymentStrategy paymentMethod){
                                int amount = calculateTotal();
                                paymentMethod.pay(amount);
                }
}


Decorator Pattern

Definition:
The decorator pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
piz5
·         Each component can be used on its own or may be wrapped by a decorator.
·         Each decorator has an instance variable that holds the reference to component it decorates(HAS-A relationship).
·         The ConcreteComponent is the object we are going to dynamically decorate.

Advantages:
·         The decorator pattern can be used to make it possible to extend (decorate) the functionality of a certain object at runtime.
·         The decorator pattern is an alternative to subclassing. Subclassing adds behavior at compile time, and the change affects all instances of the original class; decorating can provide new behavior at runtime for individual objects.
·         Decorator offers a pay-as-you-go approach to adding responsibilities. Instead of trying to support all foreseeable features in a complex, customizable class, you can define a simple class and add functionality incrementally with Decorator objects.
Disadvantages:
·         Decorators can complicate the process of instantiating the component because you not only have to instantiate the component, but wrap it in a number of decorators.
·         It can be complicated to have decorators keep track of other decorators, because to look back into multiple layers of the decorator chain starts to push the decorator pattern beyond its true intent.

No comments:

Post a Comment

Note: only a member of this blog may post a comment.