Total Pageviews

Showing posts with label Design Pattern. Show all posts
Showing posts with label Design Pattern. Show all posts

2019/03/11

[Java] [Design Pattern] An example for Template Method Pattern

Here has four steps to demonstrate template method pattern:

1. Create an abstract class with a template method being final.
package com.example.pattern.template;

public abstract class Game {

    abstract void initializeGame();
    abstract void playGame();
    abstract void endGame();

    /**
     * template method
     */
    public final void play() {
        initializeGame();
        playGame();
        endGame();
    }

}

2. Create concrete classes extending the above class.
package com.example.pattern.template;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class FishingStrike extends Game {

    @Override
    void initializeGame() {
        log.debug("Fishing Strike initialized!");
    }

    @Override
    void playGame() {
        log.debug("Fishing Strike started! Enjoy the game!");
    }

    @Override
    void endGame() {
        log.debug("Fishing Strike finished! See you!");
    }
}


package com.example.pattern.template;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class MiniGolfKing extends Game {

    @Override
    void initializeGame() {
        log.debug("Mini Golf King initialized!");
    }

    @Override
    void playGame() {
        log.debug("Mini Golf King started! Enjoy the game!");
    }

    @Override
    void endGame() {
        log.debug("Mini Golf King finished! See you!");
    }
}


3. Create a demo class to use the Game's template method play() to demonstrate a defined way of playing game.
package com.example.pattern.template;

import org.springframework.stereotype.Component;

@Component
public class TemplatePatternDemo {

    /**
     * play fishing strike game
     */
    public void playFishingStrike() {
        Game fishingStrike = new FishingStrike();
        fishingStrike.play();
    }

    /**
     * play mini golf king game
     */
    public void playMiniGolfKing() {
        Game miniGolfKing = new MiniGolfKing();
        miniGolfKing.play();
    }

}


4. Autowired TemplatePatternDemo to play execute methods and verify output
package com.example.test;

import com.example.pattern.template.TemplatePatternDemo;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = "com.example")
public class TestApplication {

    public static void main(String[] args) {
        SpringApplication.run(TestApplication.class, args);
    }

    @Bean
    CommandLineRunner run(TemplatePatternDemo demo) {
        return args -> {
            demo.playFishingStrike();
            demo.playMiniGolfKing();
        };
    }
}


[main] c.e.pattern.template.FishingStrike       : Fishing Strike initialized!
[main] c.e.pattern.template.FishingStrike       : Fishing Strike started! Enjoy the game!
[main] c.e.pattern.template.FishingStrike       : Fishing Strike finished! See you!
[main] c.example.pattern.template.MiniGolfKing  : Mini Golf King initialized!
[main] c.example.pattern.template.MiniGolfKing  : Mini Golf King started! Enjoy the game!
[main] c.example.pattern.template.MiniGolfKing  : Mini Golf King finished! See you!




2017/06/10

[Design Pattern] Builder Pattern

Definition of Builder Pattern

  • The builder pattern, as name implies, is an alternative way to construct complex objects. 
  • A builder pattern is more like fluent interface. A fluent interface is normally implemented by using method cascading (or method chaining).
  • Builder pattern aims to “Separate the construction of a complex object from its representation so that the same construction process can create different representations.”

A complete Java builder pattern example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package albert.practice.designpattern.builder;

import java.util.regex.Pattern;

import lombok.Getter;
import lombok.ToString;

@Getter
@ToString
public class User {

    private final String firstName;
    private final String lastName;
    private final Integer age;
    private final String phone;
    private final String email;

    private User(UserBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.phone = builder.phone;
        this.email = builder.email;
    }

    public static class UserBuilder {
        private String firstName;
        private String lastName;
        private Integer age;
        private String phone;
        private String email;

        public UserBuilder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public UserBuilder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }

        public UserBuilder age(Integer age) {
            this.age = age;
            return this;
        }

        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }

        public UserBuilder email(String email) {
            this.email = email;
            return this;
        }

        public User build() {
            User user = new User(this);

            // Do some basic validations to check
            if (!isEmailValid(user.getEmail())) {
                throw new RuntimeException(user.getEmail() + " is invalid Email format!");
            }

            return user;
        }

        public Boolean isEmailValid(String email) {
            Boolean isValid = Boolean.FALSE;
            Pattern EMAIL_PATTERN = Pattern.compile("^\\w+\\.*\\w+@(\\w+\\.){1,5}[a-zA-Z]{2,3}$");
            if (EMAIL_PATTERN.matcher(email).matches()) {
                isValid = Boolean.TRUE;
            }
            return isValid;
        }

    }
}


Example to use above builder pattern to create a User object
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package albert.practice.designpattern.builder;

import albert.practice.designpattern.builder.User.UserBuilder;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class BuilderTest {
    public static void main(String[] args) {
        User albert = new UserBuilder()
                .lastName("Kuo")
                .firstName("Albert")
                .phone("1234567890")
                .age(30)
                .email("test@gmail.com")
                .build();
        log.debug(" user1 = " + albert.toString());

        User mandy = new UserBuilder()
                .lastName("Yeh")
                .firstName("Mandy")
                .email("yeh@gmail.com")
                .build();
        log.debug(" user2 = " + mandy.toString());
    }
}



Benefits and Advantages

  • The number of lines of code increase at least to double in builder pattern, but the effort pays off in terms of design flexibility and much more readable code. The parameters to the constructor are reduced and are provided in highly readable method calls.
  • The constructor is private, which means that this class can not be directly instantiated from the client code.
  • The class is once again immutable. All attributes are final and they’re set on the constructor. Additionally, only provide getters for them.
  • The builder uses the Fluent Interface idiom to make the client code more readable.


Conclusion
Using builder pattern for constructing objects when having a lot of parameters, especially if many of these parameters are null and when many of them share the same data type. A developer might feel that the extra code to implement a Builder might not justify its benefits for a small number of parameters, especially if the few parameters are required and of different types. In such cases, it might be considered desirable to use traditional constructors or, if immutability is not desired, use a no-argument constructor and require the client to know to call the necessary "set" methods.


Reference
[1] http://www.javaworld.com/article/2074938/core-java/too-many-parameters-in-java-methods-part-3-builder-pattern.html?page=2
[2] http://howtodoinjava.com/design-patterns/creational/builder-pattern-in-java/

2017/03/08

[Design Pattern] Command Pattern

在 97 Things Every Programmer Should Know 一書中提到:
雖然在一般遇到的案例裡,使用 if - then - else 比多型更實用些,但絕大多數用 polymorphism 的寫作風格會讓程式碼更精簡、更易讀,且更少脆弱的程式碼。所以在我們的程式碼裡,要是錯過使用 polymorphism 的機會,便會逐漸增加  if - then - else 敘述句的數量。試試 command  pattern 吧

假設我有一個機器人物件,他會執行前進、後退、左轉與右轉,這四種指令

package albert.practice.designpattern.command;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@AllArgsConstructor
@Data
@Slf4j
public class Robot {

    private String robotName;

    public void goAhead() {
        log.debug(robotName + " 前進 !");
    }

    public void turnLeft() {
        log.debug(robotName + " 左轉 !");
    }

    public void turnRight() {
        log.debug(robotName + " 右轉 !");
    }

    public void turnBack() {
        log.debug(robotName + " 後退 !");
    }
}


另外建立一個 enumeration 來判斷,此次呼叫要執行哪一個指令
package albert.practice.designpattern.command;

public enum CommandEnum {
    GO_HEAD, TURN_BACK, TURN_RIGHT, TURN_LEFT;
}


建立機器人物件與執行指令如下:
package albert.practice.designpattern.command;

public class RobotTestClient {

    public static void main(String[] args) {
        Robot robot = new Robot("瓦力");

        RobotTestClient client = new RobotTestClient();
        client.executeRobot(robot, CommandEnum.GO_HEAD);
        client.executeRobot(robot, CommandEnum.TURN_LEFT);
        client.executeRobot(robot, CommandEnum.TURN_RIGHT);        
    }

    public void executeRobot(Robot robot, CommandEnum command) {
        if (CommandEnum.GO_HEAD == command) {
            robot.goAhead();
        } else if (CommandEnum.TURN_BACK == command) {
            robot.turnBack();
        } else if (CommandEnum.TURN_LEFT == command) {
            robot.turnLeft();
        } else if (CommandEnum.TURN_RIGHT == command) {
            robot.turnRight();
        }
    }

}



在上述的程式碼就會發現,如果指令越來越多,就會有越來越多的 if-else 判斷式,此時就可以套用 command pattern

首先,先建立 Command interface
package albert.practice.designpattern.command;

public interface Command {
    void execute();
}



然後,分別建立四個指令的 classes,並實作 Command interface
前進指令:
package albert.practice.designpattern.command;

public class GoAheadCommand implements Command {

    private Robot robot;

    public GoAheadCommand(Robot robot) {
        super();
        this.robot = robot;
    }

    @Override
    public void execute() {
        this.robot.goAhead();
    }

}


後退指令:
package albert.practice.designpattern.command;

public class TurnBackCommand implements Command {
    private Robot robot;

    public TurnBackCommand(Robot robot) {
        super();
        this.robot = robot;
    }

    @Override
    public void execute() {
        this.robot.turnBack();
    }

}



向左轉指令:

package albert.practice.designpattern.command;

public class TurnLeftCommand implements Command {
    private Robot robot;

    public TurnLeftCommand(Robot robot) {
        super();
        this.robot = robot;
    }

    @Override
    public void execute() {
        this.robot.turnLeft();
    }

}



向右轉指令:
package albert.practice.designpattern.command;

public class TurnRightCommand implements Command {
    private Robot robot;

    public TurnRightCommand(Robot robot) {
        super();
        this.robot = robot;
    }

    @Override
    public void execute() {
        this.robot.turnRight();
    }

}



建立機器人物件與操作指令,程式修改如下:

package albert.practice.designpattern.command;

public class RobotTestClient {

    public static void main(String[] args) {
        Robot robot = new Robot("瓦力");
        new GoAheadCommand(robot).execute();
        new TurnLeftCommand(robot).execute();
        new TurnRightCommand(robot).execute();
    }

}



2017/02/04

[Design Pattern] Strategy Pattern

Assume I have a data exporter which can export data to PDF, XLS or HTML format. It can export data to different format depends on your demand.

Firstly, creating a strategy interface:
package albert.practice.designpattern.strategy;

public interface ExportStrategy {

    void exportData(String data);
    
}


Secondly, creating concrete classes implements strategy interface.
package albert.practice.designpattern.strategy;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class ExcelExporter implements ExportStrategy {

    @Override
    public void exportData(String data) {
        log.debug("exporting " + data + " into excel file.");
    }

}



package albert.practice.designpattern.strategy;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class HtmlExporter implements ExportStrategy {

    @Override
    public void exportData(String data) {
        log.debug("exporting " + data + " into html file.");
    }

}



package albert.practice.designpattern.strategy;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class PdfExporter implements ExportStrategy {

    @Override
    public void exportData(String data) {
        log.debug("exporting " + data + " into pdf file.");
    }

}


The DataExport class will export data depends on client's demands.

package albert.practice.designpattern.strategy;

public class DataExport {

    public static void main(String[] args) {
        String data = "[test data]";
        
        DataExport exporter = new DataExport();
        exporter.exportData(FileTypeEnum.XLS, data);
        exporter.exportData(FileTypeEnum.PDF, data);
        exporter.exportData(FileTypeEnum.HTML, data);
    }

    public void exportData(FileTypeEnum fileType, String data) {
        ExportStrategy exporter = null;
        if (FileTypeEnum.XLS == fileType) {
            exporter = new ExcelExporter();
        } else if (FileTypeEnum.PDF == fileType) {
            exporter = new PdfExporter();
        } else if (FileTypeEnum.HTML == fileType) {
            exporter = new HtmlExporter();
        }
        exporter.exportData(data);
    }

}




We create objects which represent various export strategies, but we still expose if-else logic in client. Therefore, we create an ExportStrategy class which will change the executing algorithm of the context object (i.e. PdfExporter, HtmlExporter, and ExcelExporter).
package albert.practice.designpattern.strategy;

import lombok.Data;

@Data
public class ExporterContext {
    
    private String data;
    
    public void doExport(ExportStrategy strategy) {
        strategy.exportData(this.data);
    }
    
}



And the DataExport will be modified as bellows:

package albert.practice.designpattern.strategy;

public class DataExport {

    public static void main(String[] args) {
        String data = "[test data]";
        
        ExporterContext context = new ExporterContext();
        context.setData(data);
        context.doExport(new HtmlExporter());
        context.doExport(new ExcelExporter());
        context.doExport(new PdfExporter());
    }

}



To sum up, we create a ExportStrategy interface which define an exportData action and concrete strategy classes (i.e. PdfExporter, ExcelExporter, HtmlExporter) implementing the ExportStrategy interface. ExporterContext is a class which uses a Strategy.
DataExport, our demo class, use Context and strategy objects to demonstrate change in Context behaviour based on strategy  (i.e. PdfExporter, ExcelExporter, HtmlExporter) it uses.


2017/01/09

[Design Pattern] Factory Pattern

Assume I have a juice store, which provide apple juice, orange juice and kiwi juice. As I accept customer's order, I will make juice and deliver juice to customer.

Therefore, I will do make juice and deliver juice no matter which juices are ordered.
package albert.practice.designpattern.factory;

public interface Juice {
    void makeJuice();
    void deliverJuice();
}


Each juice will implement Juice interface, and implement its own logic in each class.
Here is apple juice:

package albert.practice.designpattern.factory;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class AppleJuice implements Juice {

    @Override
    public void makeJuice() {
      log.debug("making APPLE juice.");
    }

    @Override
    public void deliverJuice() {
        log.debug("deliver APPLE juice to customer.");
    }

}



Here is orange juice:

package albert.practice.designpattern.factory;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class OrangeJuice implements Juice {

    @Override
    public void makeJuice() {
        log.debug("making ORANGE juice.");
    }

    @Override
    public void deliverJuice() {
        log.debug("deliver ORANGE juice to customer.");        
    }

}



Here is kiwi juice:
package albert.practice.designpattern.factory;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class KiwiJuice implements Juice {

    @Override
    public void makeJuice() {
        log.debug("making KIWI juice.");
    }

    @Override
    public void deliverJuice() {
        log.debug("deliver KIWI juice to customer.");        
    }

}


I also create a fruit enumeration to tell which juice I will make:
package albert.practice.designpattern.factory;

public enum FruitEnum {
    APPLE, ORANGE, KIWI;
}


And I create a JuiceStore to process customers' order. The processOrder method is used to create apple, orange or kiwi object depends on customer's order.
package albert.practice.designpattern.factory;

public class JuiceStore {

    public static void main(String[] args) {
        JuiceStore test = new JuiceStore();
        test.processOrder(FruitEnum.KIWI);
        test.processOrder(FruitEnum.APPLE);
        test.processOrder(FruitEnum.ORANGE);
    }

    public void processOrder(FruitEnum fruit) {
        Juice juice = null;
        if (FruitEnum.APPLE == fruit) {
            juice = new AppleJuice();
        } else if (FruitEnum.ORANGE == fruit) {
            juice = new OrangeJuice();
        } else if (FruitEnum.KIWI == fruit) {
            juice = new KiwiJuice();
        }
        juice.makeJuice();
        juice.deliverJuice();
    }

}


It seems good so far. But if we would like to create object without exposing the if-else creating logic to client, we need to apply factory pattern to refactor the existing architecture.


Therefore, we need to create a JuiceFactory to generate object of concrete class based on given fruit.
package albert.practice.designpattern.factory;

public class JuiceFactory {

    public Juice getJuice(FruitEnum fruitEnum) {
        Juice juice = null;
        if (FruitEnum.APPLE == fruitEnum) {
            juice = new AppleJuice();
        } else if (FruitEnum.ORANGE == fruitEnum) {
            juice = new OrangeJuice();
        } else if (FruitEnum.KIWI == fruitEnum) {
            juice = new KiwiJuice();
        }
        return juice;
    }

}



We can see the updated JuiceStore class, the creating logic had been hide in JuiceFactory, we only need to tell JuiceFactory which fruit I would like to make:

package albert.practice.designpattern.factory;

public class JuiceStore {

    public static void main(String[] args) {
        JuiceFactory factory = new JuiceFactory();
        
        Juice apple = factory.getJuice(FruitEnum.APPLE);
        apple.makeJuice();
        apple.deliverJuice();
        
        Juice orange = factory.getJuice(FruitEnum.ORANGE);
        orange.makeJuice();
        orange.deliverJuice();
        
        Juice kiwi = factory.getJuice(FruitEnum.KIWI);
        kiwi.makeJuice();
        kiwi.deliverJuice();
    }
}


We can see JuiceStore asks JuiceFactory to create object based on its demands, and JuiceStore will use its object to make juice and deliver juice.




2008/09/19

Spring + JPA + TOPLink + DAO Step by Step

  1. Spring + JPA + TopLink + DAO Architecture
  2. Spring/Persistence Config File
  3. Implement DAO – CRUD
  4. Implement ServiceBean
  5. Implement Client Side Code

http://www.slideshare.net/junyuo/spring-toplinkjap-dao-step-by-step-presentation

2008/09/03

Spring + JPA + DAO Step by Step

Spring + JPA + DAO Step by Step
  1. Spring + JPA + DAO Architecture
  2. Spring Config File
  3. Implement DAO – CRUD 
  4. Implement ServiceBean
  5. Implement Client Side Code