Refer: http://www.tutorialspoint.com/design_pattern/design_pattern_overview.htm
====== Software Design Pattern ======
**Design patterns** represent the best practices **used by experienced object-oriented software developers**. Design patterns are **solutions to general problems that software developers faced during software development**. These solutions were obtained by trial and error by numerous software developers over quite a substantial period of time.
**Types of Desing Pattern**:As per the design pattern reference book Design Patterns - Elements of Reusable Object-Oriented Software , there are 23 design patterns. These patterns can be classified in three categories: Creational, Structural and behavioral patterns
^S.N.^Name^Pattern & Description^
|1|**Creational Patterns**|These design patterns provides **way to create objects while hiding the creation logic**, rather than instantiating objects directly using new opreator. This gives program more flexibility in deciding which objects need to be created for a given use case.|
|2|**Structural Patterns**|These design patterns concern class and object composition. Concept of inheritance is used to compose interfaces and **define ways to compose objects to obtain new functionalities**.|
|3|**Behavioral Patterns**|These design patterns are specifically **concerned with communication between objects**.|
|4|**J2EE Patterns**|These design patterns are specifically **concerned with the presentation tier**. These patterns are identified by Sun Java Center.|
===== Creational Pattern: Factory Pattern =====
Factory pattern is one of most used design pattern in Java. This type of design pattern comes under creational pattern as **this pattern provides one of the best ways to create an object**.
==== Design ====
{{:other:factory_pattern_uml_diagram.jpg|}}
==== Implementation ====
- Step 1: Create an interface **Shape.java**:
public interface Shape {
void draw();
}
- Step 2: Create **concrete classes** implementing the same interface.
* Rectangle.java
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
* Square.java
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Inside Square::draw() method.");
}
}
* Circle.java
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
- Step 3: Create a Factory to generate object of concrete class based on given information **ShapeFactory.java**
public class ShapeFactory {
//use getShape method to get object of type shape
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
}
- Step 4: Use the Factory to get object of concrete class by passing an information such as type FactoryPatternDemo.java:
public class FactoryPatternDemo {
public static void main(String[] args) {
ShapeFactory shapeFactory = new ShapeFactory();
//get an object of Circle and call its draw method.
Shape shape1 = shapeFactory.getShape("CIRCLE");
//call draw method of Circle
shape1.draw();
//get an object of Rectangle and call its draw method.
Shape shape2 = shapeFactory.getShape("RECTANGLE");
//call draw method of Rectangle
shape2.draw();
//get an object of Square and call its draw method.
Shape shape3 = shapeFactory.getShape("SQUARE");
//call draw method of circle
shape3.draw();
}
}
- Step 5: Verify the output.
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
===== creational pattern: Singleton Pattern =====
This class provides a way to access its only object which can be accessed directly without need to instantiate the object of the class.Ensure a class has only one instance, and provide a global point of access to it
==== Design ====
We're going to **create a SingleObject class**. SingleObject class have its constructor as private and **have a static instance of itself**.
SingleObject class provides a static method to get its static instance to outside world. SingletonPatternDemo, our demo class will use SingleObject class to get a SingleObject object.
{{:other:singleton_pattern_uml_diagram.jpg|}}
==== Implementation ====
- Step 1: Create a Singleton Class SingleObject.java
public class SingleObject {
//create an object of SingleObject
private static SingleObject instance = new SingleObject();
//make the constructor private so that this class cannot be
//instantiated
private SingleObject(){}
//Get the only object available
public static SingleObject getInstance(){
return instance;
}
public void showMessage(){
System.out.println("Hello World!");
}
}
- Step 2: Get the only object from the singleton class SingletonPatternDemo.java
public class SingletonPatternDemo {
public static void main(String[] args) {
//illegal construct
//Compile Time Error: The constructor SingleObject() is not visible
//SingleObject object = new SingleObject();
//Get the only object available
SingleObject object = SingleObject.getInstance();
//show the message
object.showMessage();
}
}
- Step 3: Verify the output
Hello World!
===== Structural Pattern: Adapter Pattern =====
Adapter pattern works as **a bridge between two incompatible interfaces**. This type of design pattern comes under structural pattern as this pattern combines the capability of two independent interfaces.
==== Design ====
We've an interface **MediaPlayer interface** and a concrete class AudioPlayer implementing the MediaPlayer interface. AudioPlayer can **play mp3 format** audio files by default.
We're having another interface **AdvancedMediaPlayer interface** and concrete classes implementing the AdvancedMediaPlayer interface.These classes can **play vlc and mp4 format** files.
We want to **make AudioPlayer to play other formats as well**. To attain this, we've **created an adapter class MediaAdapter** which implements the MediaPlayer interface and uses AdvancedMediaPlayer objects to play the required format.\\
{{:other:adapter_pattern_uml_diagram.jpg|}}\\
{{:other:patternadapter.png|}}
==== Implementation ====
- Step 1: **Create interfaces** for Media Player and Advanced Media Player
* MediaPlayer.java
public interface MediaPlayer {
public void play(String audioType, String fileName);
}
* AdvancedMediaPlayer.java
public interface AdvancedMediaPlayer {
public void playVlc(String fileName);
public void playMp4(String fileName);
}
- Step 2: Create **concrete classes** implementing the AdvancedMediaPlayer interface
* VlcPlayer.java
public class VlcPlayer implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: "+ fileName);
}
@Override
public void playMp4(String fileName) {
//do nothing
}
}
* Mp4Player.java
public class Mp4Player implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
//do nothing
}
@Override
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: "+ fileName);
}
}
- Step 3: Create **adapter class** implementing the MediaPlayer interface MediaAdapter.java
public class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType){
if(audioType.equalsIgnoreCase("vlc") ){
advancedMusicPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")){
advancedMusicPlayer.playVlc(fileName);
}else if(audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer.playMp4(fileName);
}
}
}
- Step 4: Create **concrete class implementing the MediaPlayer interface** AudioPlayer.java
public class AudioPlayer implements MediaPlayer {
MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
//inbuilt support to play mp3 music files
if(audioType.equalsIgnoreCase("mp3")){
System.out.println("Playing mp3 file. Name: "+ fileName);
}
//mediaAdapter is providing support to play other file formats
else if(audioType.equalsIgnoreCase("vlc")
|| audioType.equalsIgnoreCase("mp4")){
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
}
else{
System.out.println("Invalid media. "+
audioType + " format not supported");
}
}
}
- Step 5: Use the AudioPlayer to **play different types of audio formats** AdapterPatternDemo.java
public class AdapterPatternDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}
- Step 6: Verify the output
Playing mp3 file. Name: beyond the horizon.mp3
Playing mp4 file. Name: alone.mp4
Playing vlc file. Name: far far away.vlc
Invalid media. avi format not supported
===== Structural Pattern: Composite Pattern =====
Composite pattern is used where we need to treat a group of objects in similar way as a single object.
==== Design ====
We've a **class Employee** which **acts as composite pattern actor class**. CompositePatternDemo, our demo class will use Employee class to add department level hierarchy and print all employees.
{{:other:composite_pattern_uml_diagram.jpg|}}
==== Implementation ====
- Step 1: Create Employee class having list of Employee objects Employee.java
import java.util.ArrayList;
import java.util.List;
public class Employee {
private String name;
private String dept;
private int salary;
private List subordinates;
// constructor
public Employee(String name,String dept, int sal) {
this.name = name;
this.dept = dept;
this.salary = sal;
subordinates = new ArrayList();
}
public void add(Employee e) {
subordinates.add(e);
}
public void remove(Employee e) {
subordinates.remove(e);
}
public List getSubordinates(){
return subordinates;
}
public String toString(){
return ("Employee :[ Name : "+ name
+", dept : "+ dept + ", salary :"
+ salary+" ]");
}
}
- Step 2: Use the Employee class to create and print employee hierarchy CompositePatternDemo.java
public class CompositePatternDemo {
public static void main(String[] args) {
Employee CEO = new Employee("John","CEO", 30000);
Employee headSales = new Employee("Robert","Head Sales", 20000);
Employee headMarketing = new Employee("Michel","Head Marketing", 20000);
Employee clerk1 = new Employee("Laura","Marketing", 10000);
Employee clerk2 = new Employee("Bob","Marketing", 10000);
Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
Employee salesExecutive2 = new Employee("Rob","Sales", 10000);
CEO.add(headSales);
CEO.add(headMarketing);
headSales.add(salesExecutive1);
headSales.add(salesExecutive2);
headMarketing.add(clerk1);
headMarketing.add(clerk2);
//print all employees of the organization
System.out.println(CEO);
for (Employee headEmployee : CEO.getSubordinates()) {
System.out.println(headEmployee);
for (Employee employee : headEmployee.getSubordinates()) {
System.out.println(employee);
}
}
}
}
- Step 3: Verify the output
Employee :[ Name : John, dept : CEO, salary :30000 ]
Employee :[ Name : Robert, dept : Head Sales, salary :20000 ]
Employee :[ Name : Richard, dept : Sales, salary :10000 ]
Employee :[ Name : Rob, dept : Sales, salary :10000 ]
Employee :[ Name : Michel, dept : Head Marketing, salary :20000 ]
Employee :[ Name : Laura, dept : Marketing, salary :10000 ]
Employee :[ Name : Bob, dept : Marketing, salary :10000 ]
===== Structural Pattern: Decorator pattern =====
Decorator pattern allows to **add new functionality an existing object without altering its structure**. This type of design pattern comes under structural pattern as this pattern **acts as a wrapper to existing class**.
==== Design ====
Below are demonstrating use of Decorator pattern via following example in which we'll **decorate a shape** with **some color without alter shape class**.
We're going to create a **Shape interface** and concrete classes implementing the Shape interface. We then create a abstract decorator **class ShapeDecorator implementing the Shape interface** and having Shape object as its instance variable.
**RedShapeDecorator** is concrete class **implementing ShapeDecorator**.
DecoratorPatternDemo, our demo class will use RedShapeDecorator to decorate Shape objects.\\
{{:other:decorator_pattern_uml_diagram.jpg|}}\\
{{:other:patterndecorator.png|}}
==== Implementation ====
- Step 1: Create an **interface Shape.java**
public interface Shape {
void draw();
}
- Step 2: Create concrete classes implementing the same interface:
* Rectangle.java
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Rectangle");
}
}
* Circle.java
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Circle");
}
}
- Step 3: Create **abstract decorator class** implementing the Shape interface **ShapeDecorator.java**
public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
public void draw(){
decoratedShape.draw();
}
}
- Step 4: Create concrete decorator class **extending the ShapeDecorator class RedShapeDecorator.java**
public class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Shape decoratedShape){
System.out.println("Border Color: Red");
}
}
- Step 5: Use the **RedShapeDecorator** to **decorate Shape objects** DecoratorPatternDemo.java
public class DecoratorPatternDemo {
public static void main(String[] args) {
Shape circle = new Circle();
Shape redCircle = new RedShapeDecorator(new Circle());
Shape redRectangle = new RedShapeDecorator(new Rectangle());
System.out.println("Circle with normal border");
circle.draw();
System.out.println("\nCircle of red border");
redCircle.draw();
System.out.println("\nRectangle of red border");
redRectangle.draw();
}
}
- Step 6: Verify the output
Circle with normal border
Shape: Circle
Circle of red border
Shape: Circle
Border Color: Red
Rectangle of red border
Shape: Rectangle
Border Color: Red
===== Behavior Pattern: Iterator Pattern =====
Iterator pattern is very commonly used design pattern in Java and .Net programming environment. This pattern is used to **get a way to access the elements of a collection object** in sequential manner **without any need to know its underlying representation**.
==== Design ====
{{:other:iterator_pattern_uml_diagram.jpg|}}\\
{{:other:iteratorpattern.png|}}
==== Implementation ====
- Step 1: Create interfaces:
* Iterator.java
public interface Iterator {
public boolean hasNext();
public Object next();
}
* Container.java
public interface Container {
public Iterator getIterator();
}
- Step 2: Create concrete class implementing the Container interface. This class has inner class NameIterator implementing the Iterator interface NameRepository.java
public class NameRepository implements Container {
public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};
@Override
public Iterator getIterator() {
return new NameIterator();
}
private class NameIterator implements Iterator {
int index;
@Override
public boolean hasNext() {
if(index < names.length){
return true;
}
return false;
}
@Override
public Object next() {
if(this.hasNext()){
return names[index++];
}
return null;
}
}
}
- Step 3: Use the NameRepository to get iterator and print names IteratorPatternDemo.java
public class IteratorPatternDemo {
public static void main(String[] args) {
NameRepository namesRepository = new NameRepository();
for(Iterator iter = namesRepository.getIterator(); iter.hasNext();){
String name = (String)iter.next();
System.out.println("Name : " + name);
}
}
}
- Step 4: Verify the output
Name : Robert
Name : John
Name : Julie
Name : Lora
===== Behavior Pattern: Observer Pattern =====
Observer pattern is used when there is one to many relationship between objects such as **if one object is modified, its depenedent objects are to be notified automatically**. Observer pattern falls under behavioral pattern category.
==== Design ====
Observer pattern uses three actor classes. **Subject, Observer and Client**. **Subject, an object having methods to attach and de-attach observers to a client object**. We've created classes Subject, Observer abstract class and concrete classes extending the abstract class the Observer.
ObserverPatternDemo, our demo class will use Subject and concrete class objects to show observer pattern in action.\\
{{:other:observer_pattern_uml_diagram.jpg|}}\\
{{:other:patternobserver.png|}}
==== Implementation ====
- Step 1: Create **Subject class** Subject.java:
import java.util.ArrayList;
import java.util.List;
public class Subject {
private List observers
= new ArrayList();
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
notifyAllObservers();
}
public void attach(Observer observer){
observers.add(observer);
}
public void notifyAllObservers(){
for (Observer observer : observers) {
observer.update();
}
}
}
- Step 2: Create Observer class Observer.java
public abstract class Observer {
protected Subject subject;
public abstract void update();
}
- Step 3: Create concrete observer classes:
* BinaryObserver.java
public class BinaryObserver extends Observer{
public BinaryObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Binary String: "
+ Integer.toBinaryString( subject.getState() ) );
}
}
* OctalObserver.java
public class OctalObserver extends Observer{
public OctalObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Octal String: "
+ Integer.toOctalString( subject.getState() ) );
}
}
* HexaObserver.java
public class HexaObserver extends Observer{
public HexaObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}
@Override
public void update() {
System.out.println( "Hex String: "
+ Integer.toHexString( subject.getState() ).toUpperCase() );
}
}
- Step 4: Use Subject and concrete observer objects ObserverPatternDemo.java
public class ObserverPatternDemo {
public static void main(String[] args) {
Subject subject = new Subject();
new HexaObserver(subject);
new OctalObserver(subject);
new BinaryObserver(subject);
System.out.println("First state change: 15");
subject.setState(15);
System.out.println("Second state change: 10");
subject.setState(10);
}
}
- Step 5: Verify the output
First state change: 15
Hex String: F
Octal String: 17
Binary String: 1111
Second state change: 10
Hex String: A
Octal String: 12
Binary String: 1010
===== Behavior Pattern:State Pattern =====
In State pattern a **class behavior changes based on its state**. This type of design pattern comes under behavior pattern.
==== Design ====
We're going to create a **State interface defining a action** and **concrete state classes implementing the State interface**. Context is a class which carries a State.
StatePatternDemo, our demo class will use Context and **state objects to demonstrate change in Context behavior based on type of state** it is in.\\
{{:other:state_pattern_uml_diagram.jpg|}}\\
{{:other:patternstate.png|}}
==== Implementation ====
- Step 1: Create an interface Image.java
public interface State {
public void doAction(Context context);
}
- Step 2: Create concrete classes implementing the same interface
* StartState.java
public class StartState implements State {
public void doAction(Context context) {
System.out.println("Player is in start state");
context.setState(this);
}
public String toString(){
return "Start State";
}
}
* StopState.java
public class StopState implements State {
public void doAction(Context context) {
System.out.println("Player is in stop state");
context.setState(this);
}
public String toString(){
return "Stop State";
}
}
- Step 3: Create Context Class Context.java
public class Context {
private State state;
public Context(){
state = null;
}
public void setState(State state){
this.state = state;
}
public State getState(){
return state;
}
}
- Step 4: Use the Context to see change in behaviour when State changes StatePatternDemo.java
public class StatePatternDemo {
public static void main(String[] args) {
Context context = new Context();
StartState startState = new StartState();
startState.doAction(context);
System.out.println(context.getState().toString());
StopState stopState = new StopState();
stopState.doAction(context);
System.out.println(context.getState().toString());
}
}
- Step 5: Verify the output
Player is in start state
Start State
Player is in stop state
Stop State
===== Model-View-Controller Pattern =====
This pattern is used to separate application's concerns:
* Model - Model **represents an object** or JAVA POJO carrying data. It can **also have logic to update controller if its data changes**.
* View - View **represents the visualization of the data** that model contains.
* Controller - Controller acts on both Model and view. It **controls the data flow into model object** and **updates the view whenever data changes**. It keeps **View and Model separate**.
==== Design ====
We're going to create a **Student object** acting as a model. **StudentView** will be a view class which can print student details on console and **StudentController** is the controller class responsible to store data in Student object and update view StudentView accordingly.
**MVCPatternDemo**, our demo class will use StudentController to **demonstrate use of MVC pattern**.\\
{{:other:mvc_pattern_uml_diagram.jpg|}}\\
{{:other:patternmvc.png|}}
==== Implementation ====
- Step 1: Create Model Student.java
public class Student {
private String rollNo;
private String name;
public String getRollNo() {
return rollNo;
}
public void setRollNo(String rollNo) {
this.rollNo = rollNo;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
- Step 2: Create View StudentView.java
public class StudentView {
public void printStudentDetails(String studentName, String studentRollNo){
System.out.println("Student: ");
System.out.println("Name: " + studentName);
System.out.println("Roll No: " + studentRollNo);
}
}
- Step 3: Create Controller StudentController.java
public class StudentController {
private Student model;
private StudentView view;
public StudentController(Student model, StudentView view){
this.model = model;
this.view = view;
}
public void setStudentName(String name){
model.setName(name);
}
public String getStudentName(){
return model.getName();
}
public void setStudentRollNo(String rollNo){
model.setRollNo(rollNo);
}
public String getStudentRollNo(){
return model.getRollNo();
}
public void updateView(){
view.printStudentDetails(model.getName(), model.getRollNo());
}
}
- Step 4: Use the StudentController methods to demonstrate MVC design pattern usage MVCPatternDemo.java
public class MVCPatternDemo {
public static void main(String[] args) {
//fetch student record based on his roll no from the database
Student model = retriveStudentFromDatabase();
//Create a view : to write student details on console
StudentView view = new StudentView();
StudentController controller = new StudentController(model, view);
controller.updateView();
//update model data
controller.setStudentName("John");
controller.updateView();
}
private static Student retriveStudentFromDatabase(){
Student student = new Student();
student.setName("Robert");
student.setRollNo("10");
return student;
}
}
- Step 5: Verify the output
Student:
Name: Robert
Roll No: 10
Student:
Name: John
Roll No: 10
===== Behavior Pattern:Command Pattern =====
==== Design ====
We've created an **interface Order** which is **acting as a command**. We've created a **Stock class** which acts **as a request**. We've concrete command classes **BuyStock and SellStock implementing Order interface** which will do **actual command processing**. A class **Broker** is created which acts **as a invoker object**. It can take order and place orders.
Broker object uses command pattern to identify which object will execute which command based on type of command. CommandPatternDemo, our demo class will use Broker class to demonstrate command pattern.
{{:other:command_pattern_uml_diagram.jpg|}}\\
{{:other:patterncommand.png|}}
==== Implementation ====
- Step 1: Create a command interface Order.java
public interface Order {
void execute();
}
- Step 2: Create a request class Stock.java
public class Stock {
private String name = "ABC";
private int quantity = 10;
public void buy(){
System.out.println("Stock [ Name: "+name+",
Quantity: " + quantity +" ] bought");
}
public void sell(){
System.out.println("Stock [ Name: "+name+",
Quantity: " + quantity +" ] sold");
}
}
- Step 3: Create concrete classes implementing the Order interface:
* BuyStock.java
public class BuyStock implements Order {
private Stock abcStock;
public BuyStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.buy();
}
}
* SellStock.java
public class SellStock implements Order {
private Stock abcStock;
public SellStock(Stock abcStock){
this.abcStock = abcStock;
}
public void execute() {
abcStock.sell();
}
}
- Step 4: Create command invoker class Broker.java
import java.util.ArrayList;
import java.util.List;
public class Broker {
private List orderList = new ArrayList();
public void takeOrder(Order order){
orderList.add(order);
}
public void placeOrders(){
for (Order order : orderList) {
order.execute();
}
orderList.clear();
}
}
- Step 5: Use the Broker class to take and execute commands CommandPatternDemo.java
public class CommandPatternDemo {
public static void main(String[] args) {
Stock abcStock = new Stock();
BuyStock buyStockOrder = new BuyStock(abcStock);
SellStock sellStockOrder = new SellStock(abcStock);
Broker broker = new Broker();
broker.takeOrder(buyStockOrder);
broker.takeOrder(sellStockOrder);
broker.placeOrders();
}
}
- Step 6: Verify the output
Stock [ Name: ABC, Quantity: 10 ] bought
Stock [ Name: ABC, Quantity: 10 ] sold
===== Behavior Pattern: Template Pattern =====
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
==== Design ====
{{:other:template_pattern_uml_diagram.jpg|}}\\
{{:other:patterntemplate.png|}}\\
==== Implementation ====
- Step 1: Create an abstract class with a template method being final Game.java
public abstract class Game {
abstract void initialize();
abstract void startPlay();
abstract void endPlay();
//template method
public final void play(){
//initialize the game
initialize();
//start game
startPlay();
//end game
endPlay();
}
}
- Step 2: Create concrete classes extending the above class
* Cricket.java
public class Cricket extends Game {
@Override
void endPlay() {
System.out.println("Cricket Game Finished!");
}
@Override
void initialize() {
System.out.println("Cricket Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Cricket Game Started. Enjoy the game!");
}
}
* Football.java
public class Football extends Game {
@Override
void endPlay() {
System.out.println("Football Game Finished!");
}
@Override
void initialize() {
System.out.println("Football Game Initialized! Start playing.");
}
@Override
void startPlay() {
System.out.println("Football Game Started. Enjoy the game!");
}
}
- Step 3: Use the Game's template method play() to demonstrate a defined way of playing game TemplatePatternDemo.java
public class TemplatePatternDemo {
public static void main(String[] args) {
Game game = new Cricket();
game.play();
System.out.println();
game = new Football();
game.play();
}
}
- Step 4: Verify the output
Cricket Game Initialized! Start playing.
Cricket Game Started. Enjoy the game!
Cricket Game Finished!
Football Game Initialized! Start playing.
Football Game Started. Enjoy the game!
Football Game Finished!