├── .gitignore
├── README.md
├── p01_singleton
├── README.md
├── singleton-classes.png
└── src
│ └── com
│ └── jdc
│ └── registration
│ ├── BusinessAction.java
│ ├── RegistrationApp.java
│ ├── RegistrationController.java
│ ├── actions
│ ├── CreateStudentAction.java
│ ├── DeleteStudentAction.java
│ └── ShowStudentAction.java
│ ├── model
│ ├── Student.java
│ └── StudentRegistry.java
│ └── utils
│ └── Inputs.java
├── p02_factory_method
├── .gitignore
├── README.md
├── class-diagram.png
└── src
│ └── com
│ └── jdc
│ └── factory
│ └── demo
│ ├── GradeSpecificStudentFactory.java
│ ├── Student.java
│ ├── StudentDemo.java
│ └── StudentFactory.java
├── p03_builder
├── .gitignore
├── README.md
├── class-diagram.png
└── src
│ └── com
│ └── jdc
│ └── builder
│ └── demo
│ ├── BuilderDemo.java
│ └── Student.java
├── p04_abstract_factory
├── .gitignore
├── README.md
├── class-diagram.png
└── src
│ └── com
│ └── jdc
│ └── gui
│ ├── BaseComponent.java
│ ├── Button.java
│ ├── Component.java
│ ├── ComponentsFactory.java
│ ├── Dialog.java
│ ├── GuiApp.java
│ ├── GuiAppMainForMac.java
│ ├── GuiAppMainForWindow.java
│ ├── mac
│ ├── MacButton.java
│ ├── MacComponentFactory.java
│ └── MacDialog.java
│ └── windows
│ ├── WindowButton.java
│ ├── WindowComponentFactory.java
│ └── WindowDialog.java
├── p05_prototype
├── .gitignore
├── README.md
├── class-diagram.png
└── src
│ └── com
│ └── jdc
│ └── prototype
│ ├── Circle.java
│ ├── EditorApp.java
│ ├── Shape.java
│ ├── Square.java
│ ├── ToolBox.java
│ └── Triangle.java
├── p06_adapter
├── .gitignore
├── README.md
├── class-diagram.png
├── src
│ └── com
│ │ └── jdc
│ │ ├── adapter
│ │ ├── AdapterDemo.java
│ │ └── StudentTableViewAdapter.java
│ │ ├── component
│ │ └── TableView.java
│ │ └── model
│ │ ├── Student.java
│ │ └── StudentModel.java
└── students.txt
├── p07_decorator
├── .gitignore
├── README.md
├── class-diagram.png
└── src
│ └── com
│ └── jdc
│ └── coffee
│ └── shop
│ ├── AppMain.java
│ ├── Coffee.java
│ ├── CoffeeMaker.java
│ ├── CoffeeMakerDecorator.java
│ ├── IceDecorator.java
│ ├── Maker.java
│ └── SugarDecorator.java
├── p08_proxy
├── .gitignore
├── README.md
├── class-design.png
└── src
│ └── com
│ └── jdc
│ └── proxy
│ ├── SearchEngine.java
│ ├── SearchEngineDemo.java
│ ├── SearchService.java
│ ├── SearchServicePorxy.java
│ └── dynamic
│ └── DynamicProxyDemo.java
├── p09_bridge
├── .gitignore
├── README.md
├── class-design-1.png
├── class-design-2.png
├── courses.txt
├── src
│ └── com
│ │ └── jdc
│ │ └── bridge
│ │ ├── BridgeDemo.java
│ │ ├── component
│ │ ├── DataModel.java
│ │ ├── HorizontalTableView.java
│ │ ├── TableView.java
│ │ └── VerticalTableView.java
│ │ └── model
│ │ ├── Course.java
│ │ ├── CourseDataModel.java
│ │ ├── Student.java
│ │ └── StudentDataModel.java
└── students.txt
└── p10_facade
├── .gitignore
├── README.md
├── system-diagram-1.png
├── system-diagram-2.png
└── system-diagram-3.png
/.gitignore:
--------------------------------------------------------------------------------
1 | .classpath
2 | .project
3 | /*/bin/**/*
4 | /*/.settings/*
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Learning Design Patterns
2 |
3 | Software တွေကို ရေးသားကြတဲ့အခါ ကြုံတွေ့ရတတ်တဲ့ ပြဿနာလေးတွေရှိတတ်ကြပါတယ်။ ဒီနေ့ ကျွန်တော်တို့ ကြုံတွေ့နေကြရတဲ့ ပြဿနာတွေကလဲ အရင်တုန်းကထဲက ကြုံတွေ့ဘူးပြီးသား ပြဿနာတွေက များပါတယ်။
4 |
5 | အရင်လူတွေက အဆိုပြပါဿနာတွေနဲ့ ကြုံတွေ့တဲ့အခါ ဘယ်လို Object Design တွေနဲ့ ဖြေရှင်းခဲ့ကြတယ် ဆိုတာတွေဟာ ရှိပြီးသားဖြစ်ပါတယ်။ ပြဿနာ Pattern အလိုက် ဖြေရှင်းနိုင်တဲ့ Object Design တွေကတော့ OO Design Patterns တွေပဲ ဖြစ်ပါတယ်။
6 |
7 | တစ်ခုသတိထားဖို့လိုတာကတော့ Design Patterns တွေဟာ အရာရာတိုင်းကို ဖြေရှင်းနိုင်တာမဟုတ်ပါဘူး။ ပြဿနာ Pattern နဲ့ ကိုက်ညီတဲ့ Design Pattern တွေကို မှန်မှန်ကန်ကန် ရွေးချယ် အသုံးပြုနိုင်ဖို့လိုအပ်မယ် ထင်ပါတယ်။
8 |
9 | ကျွန်တော်တို့ JDC မှာတော့ OOP ကို လေ့လာပြီးတာနဲ့ Design Pattern တွေအကြောင်းကို လေ့လာစေပါတယ်။ ရည်ရွယ်ချက်ကတော့ Object Design တွေကို ဒီလိုလဲ သုံးလို့ရတယ် ဆိုတာကို မြင်စေချင်လို့ ဖြစ်ပါတယ်။
10 |
11 | ဒီ Repository ကတော့ One Stop Bootcamp Batch 3 မှာ Design Pattern အကြောင်း သင်ကြားတုန်းက အသုံးပြုခဲ့တဲ့ နမူနာ Project များကို စုစည်းထားတဲ့ Repository ဖြစ်ပါတယ်။ နမူနာတွေကိုတော့ Java Language ကိုပဲ အသုံးပြုရေးသားထားတာ ဖြစ်ပါတယ်။
12 |
13 |
14 | ## Creational Patterns
15 |
16 | Object တွေကို တည်ဆောက်တဲ့ အပိုင်းနဲ့ ပတ်သက်တဲ့ Design Patterns တွေဖြစ်ကြပါတယ်။
17 |
18 | 1. [Singleton Pattern](p01_singleton)
19 | 2. [Factory Method Pattern](p02_factory_method)
20 | 3. [Builder Pattern](p03_builder)
21 | 4. [Abstract Factory Pattern](p04_abstract_factory)
22 | 5. [Prototype Pattern](p05_prototype)
23 |
24 | ## Structural Patterns
25 |
26 | Object တွေရဲ့ ဖွဲ့စည်းတည်ဆောက်ပုံနဲ့ပတ်သက်တဲ့ Design Pattern တွေဖြစ်ကြပါတယ်။
27 |
28 | 1. [Adapter Pattern](p06_adapter)
29 | 2. [Decorator Pattern](p07_decorator)
30 | 3. [Proxy Pattern](p08_proxy)
31 | 4. [Bridge Pattern](p09_bridge)
32 | 5. [Facade Pattern](p10_facade)
33 | 6. Composite Pattern
34 | 7. Flyweight Pattern
35 |
36 | ## Behavioral Patterns
37 |
38 | Object တွေရဲ့ လုပ်ဆောင်ပုံနဲ့ပတ်သက်တဲ့ Design Pattern တွေဖြစ်ကြပါတယ်။
39 |
40 | 1. Template Method Pattern
41 | 2. Iterator Pattern
42 | 3. Visitor Pattern
43 | 4. Observer Pattern
44 | 5. Command Pattern
45 | 6. Mediator Pattern
46 | 7. State Pattern
47 | 8. Stategy Pattern
48 | 9. Chain of Responsibility Pattern
49 | 10. Memento Pattern
50 | 11. Interpreter Pattern
51 |
--------------------------------------------------------------------------------
/p01_singleton/README.md:
--------------------------------------------------------------------------------
1 | ## Singleton Pattern
2 |
3 | Object တွေကို တည်ဆောက်ပေးနိုင်တဲ့ Creational Pattern အမျိုးအစားဖြစ်ပြီး၊ တစ်ခုထည်းသော Object အဖြစ်ရေးသားအသုံးပြုလိုတဲ့အခါမှာ ရေးသားနိုင်ပါတယ်။
4 |
5 |
6 |
7 | အထက်ပါနမူနာ Program ထဲမှာ StudentRegistry Class ဟာ Student Object တွေကို သိမ်းပေးထားဖို့အတွက် အသုံးပြုနေပါတယ်။ တဖန် CreateStudentAction, DeleteStudentAction, ShowStudentAction Business Object တွေမှာ StudentRegistry Object ကို အသုံးပြုပြီး Business Action တွေကို လုပ်ဆောင်စေပါတယ်။
8 |
9 | အထက်ပါအနေအထားမျိုးမှာ Business Action တစ်ခုအတွက် StudentRegistry Object တစ်ခုကို သွားသုံးမိနေရင် Student Data တွေကို Business Action တွေအကြားမှာ Sinchronize လုပ်နိုင်မှာမဟုတ်တော့ပါဘူး။ StudentRegistry ကို တစ်ခုထဲသော Object ကို Create လုပ်နိုင်တဲ့ Class ဖြစ်အောင် တည်ဆောက်ထားဖို့လိုပါတယ်။
10 |
11 |
12 | ### Implementations
13 |
14 | - Object ကို ဆောက်ချင်တိုင်းဆောက်လို့မရအောင် Constructor ကို Private အဖြစ်လုပ်ဆောင်ထားသင့်ပါတယ်
15 | - တစ်ခုထဲသော Object ဖြစ်အောင် Private Static Field အနေနဲ့ သတ်မှတ်ရေးသားထားရပါမယ်
16 | - အသုံးပြုလိုတဲ့အခါမှာ ရယူနိုင်ဖို့အတွက် Public Static Method တစ်ခုကို ရေးသားထားပြီး Private Static Field က Null ဖြစ်နေရင် Object ဆောက်ပြီး နောက်ဆုံးမှာ တစ်ခုထဲသော Object ကို Return ပြန်ပေးရပါမယ်
17 |
18 | ```
19 | public class StudentRegistry {
20 |
21 | private List list;
22 |
23 | // 1 Make Private Constructor
24 | private StudentRegistry() {
25 | list = new ArrayList<>();
26 | }
27 |
28 | // 2 Make Online One Object
29 | private static StudentRegistry instance;
30 |
31 | // 3 Create Public Accessor and instantiate when need
32 | public static StudentRegistry getInstance() {
33 | if (null == instance) {
34 | instance = new StudentRegistry();
35 | }
36 | return instance;
37 | }
38 |
39 | // Business Method
40 |
41 | }
42 | ```
43 |
44 |
--------------------------------------------------------------------------------
/p01_singleton/singleton-classes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minlwin/design-patterns/d7f6b79cf6f9cc807c63609906b635f1175b2a3a/p01_singleton/singleton-classes.png
--------------------------------------------------------------------------------
/p01_singleton/src/com/jdc/registration/BusinessAction.java:
--------------------------------------------------------------------------------
1 | package com.jdc.registration;
2 |
3 | public interface BusinessAction {
4 |
5 | String title();
6 | void doAction();
7 | }
8 |
--------------------------------------------------------------------------------
/p01_singleton/src/com/jdc/registration/RegistrationApp.java:
--------------------------------------------------------------------------------
1 | package com.jdc.registration;
2 |
3 | import java.util.List;
4 |
5 | import com.jdc.registration.actions.CreateStudentAction;
6 | import com.jdc.registration.actions.DeleteStudentAction;
7 | import com.jdc.registration.actions.ShowStudentAction;
8 |
9 | public class RegistrationApp {
10 |
11 | public static void main(String[] args) {
12 |
13 | // Welcome Message
14 | System.out.println("========================");
15 | System.out.println("Registraion Application");
16 | System.out.println("========================");
17 |
18 | // Launch Application
19 | var controller = new RegistrationController(
20 | List.of(new CreateStudentAction(), new ShowStudentAction(), new DeleteStudentAction()));
21 | controller.launch();
22 |
23 | // Thanks Message
24 | System.out.println("========================");
25 | System.out.println("See you!");
26 | System.out.println("========================");
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/p01_singleton/src/com/jdc/registration/RegistrationController.java:
--------------------------------------------------------------------------------
1 | package com.jdc.registration;
2 |
3 | import static com.jdc.registration.utils.Inputs.readInt;
4 | import static com.jdc.registration.utils.Inputs.readString;
5 |
6 | import java.util.List;
7 |
8 | public class RegistrationController {
9 |
10 | private List actions;
11 |
12 | public RegistrationController(List actions) {
13 | super();
14 | this.actions = actions;
15 | }
16 |
17 | public void launch() {
18 |
19 | while (true) {
20 | try {
21 | showActions();
22 | int actionId = readUserAction();
23 | var action = actions.get(actionId);
24 | action.doAction();
25 |
26 | System.out.println();
27 | if (!wantToDoAgain()) {
28 | System.out.println();
29 | break;
30 | }
31 | } catch (ArrayIndexOutOfBoundsException | NumberFormatException e) {
32 | System.out.println("Please enter valid menu id.");
33 | }
34 |
35 | }
36 | }
37 |
38 | private boolean wantToDoAgain() {
39 | var result = readString("Do again(Y/Others)");
40 | return "y".equalsIgnoreCase(result);
41 | }
42 |
43 | private int readUserAction() {
44 | return readInt("Enter Action Id") - 1;
45 | }
46 |
47 | private void showActions() {
48 | for (var i = 0; i < actions.size(); i++) {
49 | System.out.printf("%d: %s%n", i + 1, actions.get(i).title());
50 | }
51 | System.out.println();
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/p01_singleton/src/com/jdc/registration/actions/CreateStudentAction.java:
--------------------------------------------------------------------------------
1 | package com.jdc.registration.actions;
2 |
3 | import com.jdc.registration.BusinessAction;
4 | import com.jdc.registration.model.Student;
5 | import com.jdc.registration.model.StudentRegistry;
6 | import com.jdc.registration.utils.Inputs;
7 |
8 | public class CreateStudentAction implements BusinessAction {
9 |
10 | private StudentRegistry registory;
11 |
12 | public CreateStudentAction() {
13 | registory = StudentRegistry.getInstance();
14 | }
15 |
16 | @Override
17 | public String title() {
18 | return "Create New Student";
19 | }
20 |
21 | @Override
22 | public void doAction() {
23 |
24 | var student = new Student();
25 | student.setName(Inputs.readString("Enter Name"));
26 | student.setPhone(Inputs.readString("Enter Phone"));
27 | student.setEmail(Inputs.readString("Enter Email"));
28 |
29 | var result = registory.addStudent(student);
30 | System.out.println("There are %d students in our applcation.".formatted(result));
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/p01_singleton/src/com/jdc/registration/actions/DeleteStudentAction.java:
--------------------------------------------------------------------------------
1 | package com.jdc.registration.actions;
2 |
3 | import com.jdc.registration.BusinessAction;
4 | import com.jdc.registration.model.StudentRegistry;
5 | import com.jdc.registration.utils.Inputs;
6 |
7 | public class DeleteStudentAction implements BusinessAction {
8 |
9 | @Override
10 | public String title() {
11 | return "Delete Student";
12 | }
13 |
14 | @Override
15 | public void doAction() {
16 | var id = Inputs.readInt("Enter Id");
17 | var result = StudentRegistry.getInstance().delete(id);
18 | System.out.println("There are %d students in our applcation.".formatted(result));
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/p01_singleton/src/com/jdc/registration/actions/ShowStudentAction.java:
--------------------------------------------------------------------------------
1 | package com.jdc.registration.actions;
2 |
3 | import java.util.List;
4 |
5 | import com.jdc.registration.BusinessAction;
6 | import com.jdc.registration.model.Student;
7 | import com.jdc.registration.model.StudentRegistry;
8 |
9 | public class ShowStudentAction implements BusinessAction {
10 |
11 | private StudentRegistry registory;
12 |
13 | public ShowStudentAction() {
14 | registory = StudentRegistry.getInstance();
15 | }
16 |
17 | @Override
18 | public String title() {
19 | return "Show Students";
20 | }
21 |
22 | @Override
23 | public void doAction() {
24 | List students = registory.getAllStudents();
25 |
26 | printLine();
27 | printRow("Id", "Name", "Phone", "Email");
28 | printLine();
29 |
30 | for (int i = 0; i < students.size(); i++) {
31 | var student = students.get(i);
32 | printRow(i + 1, student.getName(), student.getPhone(), student.getEmail());
33 | }
34 | printLine();
35 | }
36 |
37 | private void printRow(Object col1, Object col2, Object col3, Object col4) {
38 | System.out.printf("%-3s%-16s%-16s%-20s%n", col1, col2, col3, col4);
39 | }
40 |
41 | private void printLine() {
42 | System.out.println("%55s".formatted("").replaceAll(" ", "-"));
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/p01_singleton/src/com/jdc/registration/model/Student.java:
--------------------------------------------------------------------------------
1 | package com.jdc.registration.model;
2 |
3 | public class Student {
4 |
5 | private String name;
6 | private String phone;
7 | private String email;
8 |
9 | public String getName() {
10 | return name;
11 | }
12 |
13 | public void setName(String name) {
14 | this.name = name;
15 | }
16 |
17 | public String getPhone() {
18 | return phone;
19 | }
20 |
21 | public void setPhone(String phone) {
22 | this.phone = phone;
23 | }
24 |
25 | public String getEmail() {
26 | return email;
27 | }
28 |
29 | public void setEmail(String email) {
30 | this.email = email;
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/p01_singleton/src/com/jdc/registration/model/StudentRegistry.java:
--------------------------------------------------------------------------------
1 | package com.jdc.registration.model;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class StudentRegistry {
7 |
8 | private static StudentRegistry instance;
9 |
10 | private List list;
11 |
12 | private StudentRegistry() {
13 | list = new ArrayList<>();
14 | }
15 |
16 | public static StudentRegistry getInstance() {
17 | if (null == instance) {
18 | instance = new StudentRegistry();
19 | }
20 | return instance;
21 | }
22 |
23 | public List getAllStudents() {
24 | return new ArrayList<>(list);
25 | }
26 |
27 | public int addStudent(Student student) {
28 | list.add(student);
29 | return list.size();
30 | }
31 |
32 | public int delete(int id) {
33 | list.remove(id - 1);
34 | return list.size();
35 | }
36 |
37 | public Student findById(int id) {
38 | return list.get(id - 1);
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/p01_singleton/src/com/jdc/registration/utils/Inputs.java:
--------------------------------------------------------------------------------
1 | package com.jdc.registration.utils;
2 |
3 | import java.util.Scanner;
4 |
5 | public class Inputs {
6 |
7 | private static final Scanner scanner = new Scanner(System.in);
8 |
9 | public static int readInt(String message) {
10 | var str = readString(message);
11 | return Integer.parseInt(str);
12 | }
13 |
14 | public static String readString(String message) {
15 | System.out.printf("%-20s : ", message);
16 | return scanner.nextLine();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/p02_factory_method/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/p02_factory_method/README.md:
--------------------------------------------------------------------------------
1 | ## Factory Method Pattern
2 |
3 | Object တွေကို တည်ဆောက်ရာမှာ အသုံးပြုနိုင်တဲ့ creational pattern အမျိုးအစားဖြစ်ပါတယ်။
4 |
5 | များသောအားဖြင့် Object တွေကို တည်ဆောက်တဲ့နေရာမှာ Constructor တွေကို အသုံးပြုလေ့ရှိကြပါတယ်။ Class တစ်ခုကနေ Object တစ်ခုကို ပုံစံအမျိုးမျိုးနဲ့ တည်ဆောက်လိုတဲ့အခါမျိုးတွေမှာ Constructor တွေကို Overload လုပ်ပြီးရေးသားလေ့ရှိကြပါတယ်။ Constructor တွေမှာ အခြေခံအားဖြင့် အားနဲချက် နှစ်ခုရှိပါတယ်။
6 |
7 | - Constructor Name ဟာ Class Name နဲ့ တူအောင်ရေးရမှာ ဖြစ်လို့ Constructor Name ကိုကြည့်ပြီး Object တစ်ခုကို ဘယ်လိုတည်ဆောက်နေတာလဲ ဆိုတာကို နားလည်လွယ်အောင် ရေးသားလို့ မရနိုင်ဘူး
8 | - Argument List တူတဲ့ Constructor တွေကို ရေးသားလို့မရနိုင်ဘူး
9 |
10 |
11 |
12 | Factory Method ဆိုတာကတော့ Object တွေကို Return ပြန်ပေးနိုင်တဲ့ Method တွေပဲ ဖြစ်ပါတယ်။ Method ဖြစ်တဲ့အတွက် နားလည်လွယ်တဲ့ Method Name တွေကို ရေးသားပြီး ဘယ်လိုမျိုးတည်ဆောက်နေတာလဲ ဆိုတာကို နားလည်လွယ်အောင် ရေးသားဖေါ်ပြနိုင်ပါတယ်။ ထို့အပြင် Method Name မတူပဲ Argument List တူတဲ့ Method တွေကိုလဲ ရေးသားနိုင်မှာ ဖြစ်ပါတယ်။
13 |
14 | ### Implementations
15 |
16 | - တည်ဆောက်လိုတဲ့ Method ကို Return Type အနေနဲ့ ရေးသားထားရပါမယ်
17 | - Method Name ကို Object ကို ဘယ်လိုတည်ဆောက်တာလဲ ဆိုတာကို နားလည်တဲ့ နာမည် ပေးထားသင့်ပါတယ်
18 | - လိုအပ်သလို Method Argument တွေကို ရယူနိုင်ပါတယ်
19 | - Static Method ပဲဖြစ်ဖြစ် Instance Method ပဲဖြစ်ဖြစ် Factory Method အနေနဲ့ အသုံးပြုနိုင်ပါတယ်
20 |
21 | #### Static Factory Methods
22 |
23 | ```
24 | public class StudentFactory {
25 |
26 | public static Student generateByNameAndPhone(String name, String phone) {
27 | var student = new Student();
28 | student.setName(name);
29 | student.setPhone(phone);
30 | return student;
31 | }
32 |
33 | public static Student generateByNameAndEmail(String name, String email) {
34 | var student = new Student();
35 | student.setName(name);
36 | student.setEmail(email);
37 | return student;
38 | }
39 | }
40 | ```
41 |
42 | Factory ထဲမှာ သီးခြား State တွေကို ထားပြီး သုံးစရာမလိုဘူးဆိုရင် Static Method တွေကိုလဲ Factory Method အနေနဲ့ အသုံးပြုနိုင်ပါတယ်။
43 |
44 | #### Instance Factory Methods
45 |
46 | ```
47 | public class GradeSpecificStudentFactory {
48 |
49 | private String className;
50 |
51 | public GradeSpecificStudentFactory(String className) {
52 | this.className = className;
53 | }
54 |
55 | public Student withName(String name) {
56 | var student = new Student();
57 | student.setName(name);
58 | student.setClassName(className);
59 | return student;
60 | }
61 | }
62 | ```
63 |
64 | အထက်ပါနမူနာထဲကလို Factory တွေမှာ ကိုယ်ပိုင် State တွေကို ထားပြီး အသုံးပြုချင်တယ် ဆိုရင်တော့ Instance Factory Method တွေကို ရေးသားအသုံးပြုရမှာ ဖြစ်ပါတယ်။
--------------------------------------------------------------------------------
/p02_factory_method/class-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minlwin/design-patterns/d7f6b79cf6f9cc807c63609906b635f1175b2a3a/p02_factory_method/class-diagram.png
--------------------------------------------------------------------------------
/p02_factory_method/src/com/jdc/factory/demo/GradeSpecificStudentFactory.java:
--------------------------------------------------------------------------------
1 | package com.jdc.factory.demo;
2 |
3 | public class GradeSpecificStudentFactory {
4 |
5 | private String className;
6 |
7 | public GradeSpecificStudentFactory(String className) {
8 | this.className = className;
9 | }
10 |
11 | public Student withName(String name) {
12 | var student = new Student();
13 | student.setName(name);
14 | student.setClassName(className);
15 | return student;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/p02_factory_method/src/com/jdc/factory/demo/Student.java:
--------------------------------------------------------------------------------
1 | package com.jdc.factory.demo;
2 |
3 | public class Student {
4 |
5 | private int id;
6 | private String name;
7 | private String phone;
8 | private String email;
9 | private String className;
10 | private String remark;
11 |
12 | public int getId() {
13 | return id;
14 | }
15 |
16 | public void setId(int id) {
17 | this.id = id;
18 | }
19 |
20 | public String getName() {
21 | return name;
22 | }
23 |
24 | public void setName(String name) {
25 | this.name = name;
26 | }
27 |
28 | public String getPhone() {
29 | return phone;
30 | }
31 |
32 | public void setPhone(String phone) {
33 | this.phone = phone;
34 | }
35 |
36 | public String getEmail() {
37 | return email;
38 | }
39 |
40 | public void setEmail(String email) {
41 | this.email = email;
42 | }
43 |
44 | public String getClassName() {
45 | return className;
46 | }
47 |
48 | public void setClassName(String className) {
49 | this.className = className;
50 | }
51 |
52 | public String getRemark() {
53 | return remark;
54 | }
55 |
56 | public void setRemark(String remark) {
57 | this.remark = remark;
58 | }
59 |
60 | @Override
61 | public String toString() {
62 | return "Student [id=" + id + ", name=" + name + ", phone=" + phone + ", email=" + email + ", className="
63 | + className + ", remark=" + remark + "]";
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/p02_factory_method/src/com/jdc/factory/demo/StudentDemo.java:
--------------------------------------------------------------------------------
1 | package com.jdc.factory.demo;
2 |
3 | public class StudentDemo {
4 |
5 | public static void main(String[] args) {
6 |
7 | // Static Factory Method
8 | var student1 = StudentFactory.generateByNameAndPhone("Aung Aung", "0918181717");
9 | System.out.println(student1);
10 |
11 | var student2 = StudentFactory.generateByNameAndEmail("Thidar", "thidar@gmail.com");
12 | System.out.println(student2);
13 |
14 | // Instance Factory Method
15 | var gradeOneFactory = new GradeSpecificStudentFactory("Grade One");
16 | var student3 = gradeOneFactory.withName("Nilar");
17 | System.out.println(student3);
18 |
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/p02_factory_method/src/com/jdc/factory/demo/StudentFactory.java:
--------------------------------------------------------------------------------
1 | package com.jdc.factory.demo;
2 |
3 | public class StudentFactory {
4 |
5 | public static Student generateByNameAndPhone(String name, String phone) {
6 | var student = new Student();
7 | student.setName(name);
8 | student.setPhone(phone);
9 | return student;
10 | }
11 |
12 | public static Student generateByNameAndEmail(String name, String email) {
13 | var student = new Student();
14 | student.setName(name);
15 | student.setEmail(email);
16 | return student;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/p03_builder/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/p03_builder/README.md:
--------------------------------------------------------------------------------
1 | ## Builder Pattern
2 |
3 | Object တစ်ခုမှာ State များစွာပါဝင်ပြီး ပုံစံအမျိုးမျိုးနဲ့ Object ကို Create လုပ်လိုတဲ့အခါမျိုးတွေမှာ Factory Method ကို သာ အသုံးပြုရရင် Method တွေအများကြီး ရေးသားထားရတော့မှာ ဖြစ်ပါတယ်။ ထိုအခါမျိုးတွေမှာ Builder Pattern လေးကို ရွေးချယ် အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။
4 |
5 |
6 |
7 | ### Implementations
8 |
9 | - Builder Pattern ကို အသုံးပြုတော့မယ်ဆိုရင် Target Class ကနေ Constructor ကို အသုံးပြုပြီး Object မဆောက်နိုင်အောင် Constructor ကို Private လုပ်ထားတာကောင်းမယ် ထင်ပါတယ်
10 | - Target Class ထဲမှာ Builder Class ကို Static Nested Class အနေနဲ့ ရေးသားထားပြီး build() Method ကနေ Target Object ကို တည်ဆောက်ပေးနိုင်အောင် ရေးသားထားဖို့လိုအပ်ပါတယ်
11 | - Builder Class ထဲမှာ Target Class နဲ့ တူညီတဲ့ Fields တွေကို ရေးသားထားရန်လိုအပ်ပြီး build() လုပ်တဲ့အခါမှာ Builder ထဲက State တွေနဲ့ Target Object ကို တည်ဆောက်ပေးရပါမယ်
12 | - Builder ရဲ့ State တွေကို ပြောင်းနိုင်တဲ့ Method တွေရဲ့ name ကို State Name နဲ့ တူအောင် ရေးထားတာ ဘယ်လို State ကို Set လုပ်နေတယ် ဆိုတာကို နားလည်ရလွယ်ကူစေပါတယ်
13 |
14 |
15 | ```
16 | public class Student {
17 |
18 | private int id;
19 | private String name;
20 | private String phone;
21 | private String email;
22 | private String remark;
23 | private String grade;
24 |
25 | // Private Constructor for Target Class
26 | private Student(int id, String name, String phone, String email, String remark, String grade) {
27 | super();
28 | this.id = id;
29 | this.name = name;
30 | this.phone = phone;
31 | this.email = email;
32 | this.remark = remark;
33 | this.grade = grade;
34 | }
35 |
36 | public static Builder builder() {
37 | return new Builder();
38 | }
39 |
40 | public static class Builder {
41 |
42 | // Same Fields as Target Class
43 | private int id;
44 | private String name;
45 | private String phone;
46 | private String email;
47 | private String remark;
48 | private String grade;
49 |
50 | private Builder() {
51 | }
52 |
53 | // build method to create target object
54 | public Student build() {
55 | return new Student(id, name, phone, email, remark, grade);
56 | }
57 |
58 | public Builder id(int id) {
59 | this.id = id;
60 | return this;
61 | }
62 |
63 | public Builder name(String name) {
64 | this.name = name;
65 | return this;
66 | }
67 |
68 | public Builder phone(String phone) {
69 | this.phone = phone;
70 | return this;
71 | }
72 |
73 | public Builder email(String email) {
74 | this.email = email;
75 | return this;
76 | }
77 |
78 | public Builder remark(String remark) {
79 | this.remark = remark;
80 | return this;
81 | }
82 |
83 | public Builder grade(String grade) {
84 | this.grade = grade;
85 | return this;
86 | }
87 | }
88 |
89 | // Getter & Setters
90 |
91 | }
92 | ```
93 |
94 | - State တွေကို Set လုပ်နေတဲ့ Method တွေရဲ့ Return Value ကို Builder ကိုယ်တိုင်ကို သတ်မှတ်ထားခြင်းအားဖြင့် State Change Method တွေကို Chain တစ်ခုအနေနဲ့ ရေးသားသွားနိုင်မှာဖြစ်ပါတယ်
95 |
96 | ```
97 | public static void main(String[] args) {
98 |
99 | var student = Student.builder()
100 | .name("Aung Aung")
101 | .phone("091827272")
102 | .email("aung@gmail.com")
103 | .grade("Grade 10").build();
104 |
105 | System.out.println(student);
106 | }
107 | ```
--------------------------------------------------------------------------------
/p03_builder/class-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minlwin/design-patterns/d7f6b79cf6f9cc807c63609906b635f1175b2a3a/p03_builder/class-diagram.png
--------------------------------------------------------------------------------
/p03_builder/src/com/jdc/builder/demo/BuilderDemo.java:
--------------------------------------------------------------------------------
1 | package com.jdc.builder.demo;
2 |
3 | public class BuilderDemo {
4 |
5 | public static void main(String[] args) {
6 |
7 | var student = Student.builder()
8 | .name("Aung Aung")
9 | .phone("091827272")
10 | .email("aung@gmail.com")
11 | .grade("Grade 10").build();
12 |
13 | System.out.println(student);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/p03_builder/src/com/jdc/builder/demo/Student.java:
--------------------------------------------------------------------------------
1 | package com.jdc.builder.demo;
2 |
3 | public class Student {
4 |
5 | private int id;
6 | private String name;
7 | private String phone;
8 | private String email;
9 | private String remark;
10 | private String grade;
11 |
12 | public static Builder builder() {
13 | return new Builder();
14 | }
15 |
16 | public static class Builder {
17 |
18 | private int id;
19 | private String name;
20 | private String phone;
21 | private String email;
22 | private String remark;
23 | private String grade;
24 |
25 | private Builder() {
26 | }
27 |
28 | public Student build() {
29 | return new Student(id, name, phone, email, remark, grade);
30 | }
31 |
32 | public Builder id(int id) {
33 | this.id = id;
34 | return this;
35 | }
36 |
37 | public Builder name(String name) {
38 | this.name = name;
39 | return this;
40 | }
41 |
42 | public Builder phone(String phone) {
43 | this.phone = phone;
44 | return this;
45 | }
46 |
47 | public Builder email(String email) {
48 | this.email = email;
49 | return this;
50 | }
51 |
52 | public Builder remark(String remark) {
53 | this.remark = remark;
54 | return this;
55 | }
56 |
57 | public Builder grade(String grade) {
58 | this.grade = grade;
59 | return this;
60 | }
61 | }
62 |
63 | private Student(int id, String name, String phone, String email, String remark, String grade) {
64 | super();
65 | this.id = id;
66 | this.name = name;
67 | this.phone = phone;
68 | this.email = email;
69 | this.remark = remark;
70 | this.grade = grade;
71 | }
72 |
73 | public int getId() {
74 | return id;
75 | }
76 |
77 | public void setId(int id) {
78 | this.id = id;
79 | }
80 |
81 | public String getName() {
82 | return name;
83 | }
84 |
85 | public void setName(String name) {
86 | this.name = name;
87 | }
88 |
89 | public String getPhone() {
90 | return phone;
91 | }
92 |
93 | public void setPhone(String phone) {
94 | this.phone = phone;
95 | }
96 |
97 | public String getEmail() {
98 | return email;
99 | }
100 |
101 | public void setEmail(String email) {
102 | this.email = email;
103 | }
104 |
105 | public String getRemark() {
106 | return remark;
107 | }
108 |
109 | public void setRemark(String remark) {
110 | this.remark = remark;
111 | }
112 |
113 | public String getGrade() {
114 | return grade;
115 | }
116 |
117 | public void setGrade(String grade) {
118 | this.grade = grade;
119 | }
120 |
121 | @Override
122 | public String toString() {
123 | return "Student [id=" + id + ", name=" + name + ", phone=" + phone + ", email=" + email + ", remark=" + remark
124 | + ", grade=" + grade + "]";
125 | }
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/p04_abstract_factory/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/p04_abstract_factory/README.md:
--------------------------------------------------------------------------------
1 | ## Abstract Factory Pattern
2 |
3 | Application တစ်ခုကို ရေးသားတဲ့ အခါ Component Group တွေကို Family အလိုက် အသုံးပြုလိုတဲ့ အခါမျိုးမှာ Abstract Factory Pattern ကို ရွေးချယ် အသုံးပြုသင့်ပါတယ်။
4 |
5 |
6 |
7 |
8 | အထက်ပါနမူနာထဲက GuiApp မှာ Button နှင့် Dialog များကို အသုံးပြုနေပြီး Family အလိုက် Implementation Class တွေလဲ ရေးသားထားပြီး၊ Family အလိုက် Dialog တွေ Button တွေကို အသုံးပြုနိုင်ဖို့လိုအပ်ပါတယ်။
9 |
10 | ComponentsFactory Class ကို Abstract Factory အနေနဲ့ ရေးသားထားပြီး၊ လိုအပ်တဲ့ Component တွေကို Create လုပ်ပေးဖို့အတွက် Abstract Factory Method တွေကို ရေးသားထားပါတယ်။ Family အလိုက် Component တွေကို Create လုပ်နိုင်ဖို့အတွက် Concrete Implementation တွေအဖြစ် MacComponentsFactory နှင့် WindowsComponentsFactory တို့ကို ရေးသားထားပါတယ်။
11 |
12 | MacComponentsFactory ကနေ MacButton နှင့် MacDialog တို့ကို Generate လုပ်ပေးနိုင်ပြီး၊ WindowsComponentsFactory ကနေ WindowsButton နှင့် WindowsDialog ကို Generate လုပ်ပေးနေပါတယ်။ GuiApp ကို Windows Family အနေနဲ့ အသုံးပြုလိုချင်ရင် WindowsComponentsFactory နှင့်တွဲဖက် အသုံးပြုနိုင်ပြီး၊ Mac Family အနေနဲ့ အသုံးပြုလိုပါက MacComponentsFactory နှင့် တွဲဖက် အသုံးပြုနိုင်ပါတယ်။
13 |
14 | Abstract Factory Pattern ကတော့ Family အလိုက် Product တွေကို တည်ဆောက်ပေးနိုင်တဲ့ Design Pattern တစ်ခုဖြစ်ပါတယ်။
15 |
16 | ### Implementations
17 |
18 | - Product တွေနဲ့ Factory Class တွေကို Abstraction ဖြစ်အောင် Interface ဒါမှမဟုတ် Abstract Class ကို အသုံးပြုရေးသားနိုင်ပါတယ်
19 | - Product တွေမှာလဲ Family အလိုက် Implementation တွေရှိကြပါတယ်
20 | - Abstract Factory ထဲမှာ Product တွေကို တည်ဆောက်ဖို့အတွက် Abstract Method တွေကို ရေးသားထားရပါမယ်
21 | - Family အလိုက် Factory Class တွေက Abstract Factory ကို Implements / Extends လုပ်ပြီး Factory Method တွေကို Override လုပ်တဲ့အခါမှာ Family အလိုက် Product တွေကို Create လုပ်ပေးဖို့လိုအပ်ပါတယ်
22 | - Abstract Factory Pattern ကို အသုံးပြုခြင်းအားဖြင့် Client နှင့် Product Details Implementation တွေ၊ Factory တွေကို Decouple လုပ်ပေးနိုင်ပြီး Reusability ကိုမြင့်မားအောင် ဆောင်ရွက်ပေးနိုင်မှာ ဖြစ်ပါတယ်
23 |
24 | Abstract Factory
25 |
26 | ```
27 | public interface ComponentsFactory {
28 |
29 | Button createButton();
30 | Dialog createDialog();
31 | }
32 | ```
33 |
34 |
35 | Concrete Factory Class
36 |
37 | ```
38 | public class MacComponentFactory implements ComponentsFactory{
39 |
40 | @Override
41 | public Button createButton() {
42 | return new MacButton();
43 | }
44 |
45 | @Override
46 | public Dialog createDialog() {
47 | return new MacDialog();
48 | }
49 | }
50 | ```
51 |
52 | Client Class
53 |
54 | ```
55 | public class GuiApp implements Component{
56 |
57 | private Button button;
58 | private Dialog dialog;
59 |
60 | public GuiApp(ComponentsFactory factory) {
61 | this.button = factory.createButton();
62 | this.dialog = factory.createDialog();
63 | }
64 |
65 | @Override
66 | public void draw() {
67 | dialog.draw();
68 | button.draw();
69 | }
70 |
71 | }
72 | ```
73 |
74 | Usage
75 |
76 | ```
77 | public class GuiAppMainForMac {
78 |
79 | public static void main(String[] args) {
80 |
81 | var app = new GuiApp(new MacComponentFactory());
82 | app.draw();
83 | }
84 | }
85 | ```
86 |
--------------------------------------------------------------------------------
/p04_abstract_factory/class-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minlwin/design-patterns/d7f6b79cf6f9cc807c63609906b635f1175b2a3a/p04_abstract_factory/class-diagram.png
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/BaseComponent.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui;
2 |
3 | public abstract class BaseComponent implements Component{
4 |
5 | private String type;
6 |
7 | public BaseComponent(String type) {
8 | this.type = type;
9 | }
10 |
11 | public String getType() {
12 | return type;
13 | }
14 |
15 | @Override
16 | public void draw() {
17 | System.out.println("Type Family is %s.".formatted(type));
18 | System.out.println("Drawing Component");
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/Button.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui;
2 |
3 | public abstract class Button extends BaseComponent{
4 |
5 | public Button(String type) {
6 | super(type);
7 | }
8 |
9 | @Override
10 | public void draw() {
11 | super.draw();
12 |
13 | System.out.println("Drawing Button");
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/Component.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui;
2 |
3 | public interface Component {
4 |
5 | void draw();
6 | }
7 |
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/ComponentsFactory.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui;
2 |
3 | public interface ComponentsFactory {
4 |
5 | Button createButton();
6 | Dialog createDialog();
7 | }
8 |
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/Dialog.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui;
2 |
3 | public abstract class Dialog extends BaseComponent{
4 |
5 | public Dialog(String type) {
6 | super(type);
7 | }
8 |
9 | @Override
10 | public void draw() {
11 | super.draw();
12 |
13 | System.out.println("Drawing Dialog");
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/GuiApp.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui;
2 |
3 | public class GuiApp implements Component{
4 |
5 | private Button button;
6 | private Dialog dialog;
7 |
8 | public GuiApp(ComponentsFactory factory) {
9 | this.button = factory.createButton();
10 | this.dialog = factory.createDialog();
11 | }
12 |
13 | @Override
14 | public void draw() {
15 | dialog.draw();
16 | button.draw();
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/GuiAppMainForMac.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui;
2 |
3 | import com.jdc.gui.mac.MacComponentFactory;
4 |
5 | public class GuiAppMainForMac {
6 |
7 | public static void main(String[] args) {
8 |
9 | var app = new GuiApp(new MacComponentFactory());
10 | app.draw();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/GuiAppMainForWindow.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui;
2 |
3 | import com.jdc.gui.windows.WindowComponentFactory;
4 |
5 | public class GuiAppMainForWindow {
6 |
7 | public static void main(String[] args) {
8 | var app = new GuiApp(new WindowComponentFactory());
9 | app.draw();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/mac/MacButton.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui.mac;
2 |
3 | import com.jdc.gui.Button;
4 |
5 | public class MacButton extends Button{
6 |
7 | public MacButton() {
8 | super("Mac OS");
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/mac/MacComponentFactory.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui.mac;
2 |
3 | import com.jdc.gui.Button;
4 | import com.jdc.gui.ComponentsFactory;
5 | import com.jdc.gui.Dialog;
6 |
7 | public class MacComponentFactory implements ComponentsFactory{
8 |
9 | @Override
10 | public Button createButton() {
11 | return new MacButton();
12 | }
13 |
14 | @Override
15 | public Dialog createDialog() {
16 | return new MacDialog();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/mac/MacDialog.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui.mac;
2 |
3 | import com.jdc.gui.Dialog;
4 |
5 | public class MacDialog extends Dialog{
6 |
7 | public MacDialog() {
8 | super("Mac OS");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/windows/WindowButton.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui.windows;
2 |
3 | import com.jdc.gui.Button;
4 |
5 | public class WindowButton extends Button{
6 |
7 | public WindowButton() {
8 | super("Windows");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/windows/WindowComponentFactory.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui.windows;
2 |
3 | import com.jdc.gui.Button;
4 | import com.jdc.gui.ComponentsFactory;
5 | import com.jdc.gui.Dialog;
6 |
7 | public class WindowComponentFactory implements ComponentsFactory{
8 |
9 | @Override
10 | public Button createButton() {
11 | return new WindowButton();
12 | }
13 |
14 | @Override
15 | public Dialog createDialog() {
16 | return new WindowDialog();
17 | }
18 |
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/p04_abstract_factory/src/com/jdc/gui/windows/WindowDialog.java:
--------------------------------------------------------------------------------
1 | package com.jdc.gui.windows;
2 |
3 | import com.jdc.gui.Dialog;
4 |
5 | public class WindowDialog extends Dialog{
6 |
7 | public WindowDialog() {
8 | super("Windows");
9 | }
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/p05_prototype/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/p05_prototype/README.md:
--------------------------------------------------------------------------------
1 | ## Prototype Pattern
2 |
3 | ရှိပြီးသား Object တစ်ခုကနေ နောက်ထပ် Object အသစ်တစ်ခုကို တည်ဆောက်လိုတဲ့ အခါမျိုးတွေမှာ Prototype Design Pattern ကို အသုံးပြုနိုင်ပါတယ်။ Object တစ်ခုကို တည်ဆောက်ဖို့အတွက် Resource တွေအများကြီးသုံးရမယ်၊ အချိန်တွေကြာနေနိုင်တယ် ဆိုရင် Object တစ်ခုကို ကြိုတင်တည်ဆောက်ထားပြီး အသုံးလိုတဲ့ အခါတိုင်းမှာ ကြိုဆောက်ထားတဲ့ Object ကို Copy ကူးပြီး နောက်ထပ် Object တစ်ခုကို တည်ဆောက်ပြီး အသုံးပြုသွားနိုင်မှာ ဖြစ်ပါတယ်။
4 |
5 |
6 |
7 | အထက်ပါနမူနာကတော့ GuiApp တစ်ခုကို နမူနာယူပြီး ရေးသားထားတာ ဖြစ်ပါတယ်။ Application ထဲမှာ ToolBox တစ်ခုပါဝင်ပြီး Circle, Square, Triangle Shape တွေကို ပြသထားပါတယ်။ အဲ့ဒီ Shape တွေကို Click နှိပ်ပြီး သက်ဆိုရင်ရာ Shape ကို Create လုပ်ပြီး Editor ထဲမှာ Shape ကို နေရာချပေးတဲ့ အလုပ်ကို လုပ်နိုင်မှာ ဖြစ်ပါတယ်။
8 |
9 | ဒီနေရာမှာ Shape တွေကို Create လုပ်ရတာကြာပြီး သုံးချင်တဲ့ Shape တွေဟာ ToolBox ထဲမှာကြိုရှိနေတယ်လို့ ဆိုကြပါစို့။ ဒီနေရာမှာ ရှိပြီးသား Shape ကို Copy ကူးသွားပြီး Object အသစ်တစ်ခုကို တည်ဆောက်ပေးလိုက်မယ် ဆိုတာကတော့ Prototype Pattern ရဲ့ Approach ပဲ ဖြစ်ပါတယ်။
10 |
11 | ### Implementations
12 |
13 | - Prototype အနေနဲ့ Abstract Class Shape ကို အသုံးပြုပြီး Object တစ်ခုကိုတည်ဆောက်ဖို့အတွက် copy() ဆိုတဲ့ Method တစ်ခုကို ရေးသားထားဖို့လိုပါတယ်
14 | - Copy ကူးဖို့ Method ကို Abstract Method အနေနဲ့ ရေးသားနိုင်ဖို့ Prototype ကို Abstract Class ဒါမှမဟုတ် Interface ကို အသုံးပြုရေးသားနိုင်ပါတယ်
15 | - ဒီနေရာမှာတော့ Same Type ကို Argument ကို ရယူနေတဲ့ Constructor တစ်ခုကို Child Class တွေမှာ ရေးသားစေချင်တဲ့အတွက် Abstract Class ကို အသုံးပြုရေးသားထားတာ ဖြစ်ပါတယ်
16 | - Concrete Prototype တွေအနေနဲ့ Circle, Triangle, Square တို့ကို ရေးသားထားပြီး copy() Method ကို Implement လုပ်ပြီးရေးသားထားပါတယ်
17 |
18 | Prototype Class
19 |
20 | ```
21 | public abstract class Shape {
22 |
23 | protected String name;
24 |
25 | // Constructor for new object
26 | public Shape(String name) {
27 | this.name = name;
28 | }
29 |
30 | // Constructor for copied object
31 | public Shape(Shape shape) {
32 | this.name = shape.name;
33 | }
34 |
35 | public abstract void draw();
36 | public abstract Shape copy();
37 | }
38 | ```
39 |
40 | Concrete Prototype Class
41 |
42 | ```
43 | public class Circle extends Shape{
44 |
45 | private double radius;
46 |
47 | public Circle(double radius) {
48 | super("Circle");
49 | this.radius = radius;
50 | }
51 |
52 | public Circle(Circle other) {
53 | super(other);
54 | this.radius = other.radius;
55 | }
56 |
57 | @Override
58 | public void draw() {
59 | System.out.println("Drawing %s with radius %f.".formatted(name, radius));
60 | }
61 |
62 | @Override
63 | public Shape copy() {
64 | return new Circle(this);
65 | }
66 |
67 | }
68 | ```
69 |
70 | Client Class
71 |
72 | ```
73 | public class ToolBox {
74 |
75 | private Shape triangle;
76 | private Shape circle;
77 | private Shape square;
78 |
79 | public ToolBox(Triangle triangle, Circle circle, Square square) {
80 | super();
81 | this.triangle = triangle;
82 | this.circle = circle;
83 | this.square = square;
84 | }
85 |
86 | public Shape getTriangle() {
87 | return triangle.copy();
88 | }
89 |
90 | public Shape getCircle() {
91 | return circle.copy();
92 | }
93 |
94 | public Shape getSquare() {
95 | return square.copy();
96 | }
97 |
98 | }
99 | ```
--------------------------------------------------------------------------------
/p05_prototype/class-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minlwin/design-patterns/d7f6b79cf6f9cc807c63609906b635f1175b2a3a/p05_prototype/class-diagram.png
--------------------------------------------------------------------------------
/p05_prototype/src/com/jdc/prototype/Circle.java:
--------------------------------------------------------------------------------
1 | package com.jdc.prototype;
2 |
3 | public class Circle extends Shape{
4 |
5 | private double radius;
6 |
7 | public Circle(double radius) {
8 | super("Circle");
9 | this.radius = radius;
10 | }
11 |
12 | public Circle(Circle other) {
13 | super(other);
14 | this.radius = other.radius;
15 | }
16 |
17 | @Override
18 | public void draw() {
19 | System.out.println("Drawing %s with radius %f.".formatted(name, radius));
20 | }
21 |
22 | @Override
23 | public Shape copy() {
24 | return new Circle(this);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/p05_prototype/src/com/jdc/prototype/EditorApp.java:
--------------------------------------------------------------------------------
1 | package com.jdc.prototype;
2 |
3 | public class EditorApp {
4 |
5 | public static void main(String[] args) {
6 |
7 | var triangle = new Triangle(20, 10);
8 | var circle = new Circle(15);
9 | var square = new Square(20);
10 |
11 | var toolBox = new ToolBox(triangle, circle, square);
12 |
13 | toolBox.getCircle().draw();
14 | toolBox.getSquare().draw();
15 | toolBox.getTriangle().draw();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/p05_prototype/src/com/jdc/prototype/Shape.java:
--------------------------------------------------------------------------------
1 | package com.jdc.prototype;
2 |
3 | public abstract class Shape {
4 |
5 | protected String name;
6 |
7 | // Constructor for new object
8 | public Shape(String name) {
9 | this.name = name;
10 | }
11 |
12 | // Constructor for copied object
13 | public Shape(Shape shape) {
14 | this.name = shape.name;
15 | }
16 |
17 | public abstract void draw();
18 | public abstract Shape copy();
19 | }
20 |
--------------------------------------------------------------------------------
/p05_prototype/src/com/jdc/prototype/Square.java:
--------------------------------------------------------------------------------
1 | package com.jdc.prototype;
2 |
3 | public class Square extends Shape{
4 |
5 | private double side;
6 |
7 | public Square(double side) {
8 | super("Square");
9 | this.side = side;
10 | }
11 |
12 | public Square(Square other) {
13 | super(other);
14 | this.side = other.side;
15 | }
16 |
17 | @Override
18 | public void draw() {
19 | System.out.println("Drawing %s with side %f.".formatted(name, side));
20 | }
21 |
22 | @Override
23 | public Shape copy() {
24 | return new Square(this);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/p05_prototype/src/com/jdc/prototype/ToolBox.java:
--------------------------------------------------------------------------------
1 | package com.jdc.prototype;
2 |
3 | public class ToolBox {
4 |
5 | private Shape triangle;
6 | private Shape circle;
7 | private Shape square;
8 |
9 | public ToolBox(Triangle triangle, Circle circle, Square square) {
10 | super();
11 | this.triangle = triangle;
12 | this.circle = circle;
13 | this.square = square;
14 | }
15 |
16 | public Shape getTriangle() {
17 | return triangle.copy();
18 | }
19 |
20 | public Shape getCircle() {
21 | return circle.copy();
22 | }
23 |
24 | public Shape getSquare() {
25 | return square.copy();
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/p05_prototype/src/com/jdc/prototype/Triangle.java:
--------------------------------------------------------------------------------
1 | package com.jdc.prototype;
2 |
3 | public class Triangle extends Shape{
4 |
5 | private double base;
6 | private double height;
7 |
8 | public Triangle(double base, double height) {
9 | super("Triangle");
10 | this.base = base;
11 | this.height = height;
12 | }
13 |
14 | public Triangle(Triangle other) {
15 | super(other);
16 | this.base = other.base;
17 | this.height = other.height;
18 | }
19 |
20 | @Override
21 | public void draw() {
22 | System.out.println("Drawing %s with base %f and height %f."
23 | .formatted(name, base, height));
24 | }
25 |
26 | @Override
27 | public Shape copy() {
28 | return new Triangle(this);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/p06_adapter/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/p06_adapter/README.md:
--------------------------------------------------------------------------------
1 | ## Adapter Pattern
2 |
3 | Adapter Pattern ကတော့ Structural Design Pattern တွေထဲက Pattern တစ်ခုဖြစ်ပါတယ်။ အပြင်လောကမှာလဲ ကျွန်တော်တို့က Adapter တွေကို အသုံးပြုနေကြတာမို့လို့ နားလည်ရလွယ်ကူမယ်နဲ့ တူပါတယ်။
4 |
5 | ဆိုကြပါစို့။ ကျွန်တော်အသုံးပြုနေတဲ့ Computer ရဲ့ အားသွင်းကြိုးရဲ့ Plug ခေါင်းဟာ Three Pin ခေါင်းဖြစ်နေပြီး၊ ရှိနေတဲ့ Plug ပေါက်ဟာ Two Pin Plug ပေါက်ဖြစ်နေရင် ဘာလုပ်ကြမလဲ။ Three Pin to Three Pin Adapter လေးကို ကြားထဲမှာခံပြီး အသုံးပြုသွားကြမှာ ဖြစ်ပါတယ်။
6 |
7 | Adapter Pattern ရဲ့ သဘောတရားကလဲ ဒီလိုပါပဲ။ ရေးသားထားတဲ့ Component တစ်ခုကို ကျွန်တော်တို့က အသုံးပြုချင်တယ်။ ဒါပေမဲ့ ကျွန်တောတို့မှာရှိတဲ့ Data တွေက Component က သုံးချင်တဲ့ ပုံစံရှိမနေဘူးဆိုရင်၊ ကြားထဲမှာ Adapter လေးတစ်ခုကို ရေးပြီး သုံးလို့ရအောင် လုပ်သွားရမှာ ဖြစ်ပါတယ်။
8 |
9 |
10 |
11 | အထက်ပါနမူနာထဲမှာတော့ Console ပေါ်မှာ Table တွေကို ဖေါ်ပြဖို့အတွက် TableView Class တစ်ခုကို ရေးသားထားပါတယ်။ TableView ဟာ ဘယ်လို Data မျိုးကိုမဆို Table အနေနဲ့ ဖေါ်ပြဖို့လိုတဲ့အတွက် Implementation အပိုင်းကိုတော့ ရေးသားထားပြီး Data တွေကိုတော့ Abstraction ဖြစ်အောင် ရေးသားထားပါတယ်။ TableView ရဲ့ Data တွေကို ကိုယ်စားပြုတာကတော့ DataModel ဆိုတဲ့ Interface ဖြစ်ပါတယ်။ DataModel Interface ကို Implement လုပ်ထားတဲ့ Class တိုင်းကို TableView ရဲ့ Data အနေနဲ့ အသုံးပြုနိုင်မှာ ဖြစ်ပါတယ်။
12 |
13 | တဖန် ကျွန်တော်တို့မှာရှိတာက File ထဲက Data တွေကို Read လုပ်ပြီး Student Object တွေအနေနဲ့ ရယူပေးနိုင်တဲ့ StudentModel Class ရှိပါတယ်။ StudentModel ရဲ့ getAll() Method ကနေ Student List ကို ရယူနိုင်ပါတယ်။
14 |
15 | Student List ကို TableView နဲ့ တွဲပြီး အသုံးပြုချင်ပါတယ်။ ဒါပေမဲ့ TableView ကနေ Student List ကို တိုက်ရိုက် အသုံးပြုလို့မရပါဘူး။ ဒီနေရာမှာ StudentTableViewAdapter လေးကို ခံပြီး သုံးသွားမယ်ဆိုတာကတော့ Adapter Pattern ရဲ့ Approach ပဲဖြစ်ပါတယ်။
16 |
17 | ### Implementation
18 |
19 | - StudentTableViewAdapter ကို DataModel Interface ကို Implement လုပ်ပြီးရေးသားပါမယ်
20 | - StudentTableViewAdapter ရဲ့ Member အနေနဲ့ Student List ကိုအသုံးပြုပါတယ်
21 | - DataModel ကနေ Inheritance လုပ်လို့ရလာတဲ့ Method တွေကို Override လုပ်တဲ့ နေရာမှာ Student List ကို အသုံးပြုပြီး ရေးသားပေးပါမယ်
22 |
23 | ဒီနည်းအားဖြင့် Student List ကို TableView ရဲ့ DataModel အနေနဲ့ အသုံးပြုသွားတာ ဖြစ်ပါတယ်။
24 |
25 | Target Interface
26 |
27 | ```
28 | public static interface DataModel {
29 | String title();
30 | int size();
31 | List headers();
32 | List row(int index);
33 | }
34 | ```
35 |
36 | Client Class
37 |
38 | ```
39 | public class TableView {
40 |
41 | public static interface DataModel {
42 | String title();
43 | int size();
44 | List headers();
45 | List row(int index);
46 | }
47 |
48 | // Target as a member
49 | private DataModel model;
50 |
51 | private int rowLength;
52 | private List colLengths;
53 |
54 | public TableView(DataModel model) {
55 | super();
56 | this.model = model;
57 |
58 | var headerLengths = model.headers().stream()
59 | .map(header -> header.length() + 4).toList();
60 | colLengths = new ArrayList<>(headerLengths);
61 |
62 | // Loop for each row
63 | for(var rowNum = 0; rowNum < model.size(); rowNum ++) {
64 | var rowData = model.row(rowNum);
65 |
66 | // Loop for each column of row
67 | for(var colNum = 0; colNum < rowData.size(); colNum ++) {
68 |
69 | var originalLength = colLengths.get(colNum);
70 | var colLength = rowData.get(colNum).length() + 4;
71 |
72 | if(originalLength < colLength) {
73 | colLengths.set(colNum, colLength);
74 | }
75 | }
76 | }
77 |
78 | rowLength = colLengths.stream().mapToInt(a -> a).sum();
79 | }
80 |
81 | public void draw() {
82 | printTitle();
83 |
84 | printHeader();
85 |
86 | printRows();
87 | }
88 |
89 | // Private Methods
90 |
91 | }
92 | ```
93 |
94 | Adapter Class
95 |
96 | ```
97 | public class StudentTableViewAdapter implements DataModel{
98 |
99 | private List list;
100 |
101 | public StudentTableViewAdapter(List list) {
102 | super();
103 | this.list = list;
104 | }
105 |
106 | @Override
107 | public String title() {
108 | return "Student Table";
109 | }
110 |
111 | @Override
112 | public int size() {
113 | return list.size();
114 | }
115 |
116 | @Override
117 | public List headers() {
118 | return List.of("ID", "NAME", "PHONE", "EMAIL");
119 | }
120 |
121 | @Override
122 | public List row(int index) {
123 | var student = list.get(index);
124 | return List.of(
125 | String.valueOf(student.getId()),
126 | student.getName(),
127 | student.getPhone(),
128 | student.getEmail());
129 | }
130 |
131 | }
132 | ```
133 |
134 | Using Adapter
135 |
136 | ```
137 | public class AdapterDemo {
138 |
139 | public static void main(String[] args) {
140 |
141 | var model = new StudentModel("students.txt");
142 |
143 | // Adaptee
144 | var studentList = model.getAll();
145 |
146 | // Adapter
147 | var adapter = new StudentTableViewAdapter(studentList);
148 |
149 | // Client
150 | var tableView = new TableView(adapter);
151 |
152 | tableView.draw();
153 | }
154 | }
155 | ```
--------------------------------------------------------------------------------
/p06_adapter/class-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minlwin/design-patterns/d7f6b79cf6f9cc807c63609906b635f1175b2a3a/p06_adapter/class-diagram.png
--------------------------------------------------------------------------------
/p06_adapter/src/com/jdc/adapter/AdapterDemo.java:
--------------------------------------------------------------------------------
1 | package com.jdc.adapter;
2 |
3 | import com.jdc.component.TableView;
4 | import com.jdc.model.StudentModel;
5 |
6 | public class AdapterDemo {
7 |
8 | public static void main(String[] args) {
9 |
10 | var model = new StudentModel("students.txt");
11 |
12 | // Adaptee
13 | var studentList = model.getAll();
14 |
15 | // Adapter
16 | var adapter = new StudentTableViewAdapter(studentList);
17 |
18 | // Client
19 | var tableView = new TableView(adapter);
20 |
21 | tableView.draw();
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/p06_adapter/src/com/jdc/adapter/StudentTableViewAdapter.java:
--------------------------------------------------------------------------------
1 | package com.jdc.adapter;
2 |
3 | import java.util.List;
4 |
5 | import com.jdc.component.TableView.DataModel;
6 | import com.jdc.model.Student;
7 |
8 | public class StudentTableViewAdapter implements DataModel{
9 |
10 | private List list;
11 |
12 | public StudentTableViewAdapter(List list) {
13 | super();
14 | this.list = list;
15 | }
16 |
17 | @Override
18 | public String title() {
19 | return "Student Table";
20 | }
21 |
22 | @Override
23 | public int size() {
24 | return list.size();
25 | }
26 |
27 | @Override
28 | public List headers() {
29 | return List.of("ID", "NAME", "PHONE", "EMAIL");
30 | }
31 |
32 | @Override
33 | public List row(int index) {
34 | var student = list.get(index);
35 | return List.of(
36 | String.valueOf(student.getId()),
37 | student.getName(),
38 | student.getPhone(),
39 | student.getEmail());
40 | }
41 |
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/p06_adapter/src/com/jdc/component/TableView.java:
--------------------------------------------------------------------------------
1 | package com.jdc.component;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public class TableView {
7 |
8 | public static interface DataModel {
9 | String title();
10 | int size();
11 | List headers();
12 | List row(int index);
13 | }
14 |
15 | private DataModel model;
16 |
17 | private int rowLength;
18 | private List colLengths;
19 |
20 | public TableView(DataModel model) {
21 | super();
22 | this.model = model;
23 |
24 | var headerLengths = model.headers().stream()
25 | .map(header -> header.length() + 4).toList();
26 | colLengths = new ArrayList<>(headerLengths);
27 |
28 | // Loop for each row
29 | for(var rowNum = 0; rowNum < model.size(); rowNum ++) {
30 | var rowData = model.row(rowNum);
31 |
32 | // Loop for each column of row
33 | for(var colNum = 0; colNum < rowData.size(); colNum ++) {
34 |
35 | var originalLength = colLengths.get(colNum);
36 | var colLength = rowData.get(colNum).length() + 4;
37 |
38 | if(originalLength < colLength) {
39 | colLengths.set(colNum, colLength);
40 | }
41 | }
42 | }
43 |
44 | rowLength = colLengths.stream().mapToInt(a -> a).sum();
45 | }
46 |
47 | public void draw() {
48 | printTitle();
49 |
50 | printHeader();
51 |
52 | printRows();
53 | }
54 |
55 | private void printTitle() {
56 | System.out.println(model.title());
57 | printLine();
58 | }
59 |
60 | private void printHeader() {
61 | var headers = model.headers();
62 | printRow(headers);
63 | }
64 |
65 | private void printRows() {
66 |
67 | for(var i = 0; i < model.size(); i ++) {
68 | var rowData = model.row(i);
69 | printRow(rowData);
70 | }
71 | }
72 |
73 | private void printRow(List rowData) {
74 | for(var i = 0; i < rowData.size(); i ++) {
75 | var colLength = colLengths.get(i);
76 | var colValue = rowData.get(i);
77 | System.out.print("%%-%ds".formatted(colLength).formatted(colValue));
78 | }
79 | System.out.println();
80 | printLine();
81 | }
82 |
83 | private void printLine() {
84 | System.out.println("%%%ds".formatted(rowLength).formatted("").replaceAll(" ", "-"));
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/p06_adapter/src/com/jdc/model/Student.java:
--------------------------------------------------------------------------------
1 | package com.jdc.model;
2 |
3 | public class Student {
4 |
5 | private int id;
6 | private String name;
7 | private String phone;
8 | private String email;
9 |
10 | public Student(String line) {
11 | var array = line.split("\t");
12 | id = Integer.parseInt(array[0]);
13 | name = array[1];
14 | phone = array[2];
15 | email = array[3];
16 | }
17 |
18 | public int getId() {
19 | return id;
20 | }
21 |
22 | public void setId(int id) {
23 | this.id = id;
24 | }
25 |
26 | public String getName() {
27 | return name;
28 | }
29 |
30 | public void setName(String name) {
31 | this.name = name;
32 | }
33 |
34 | public String getPhone() {
35 | return phone;
36 | }
37 |
38 | public void setPhone(String phone) {
39 | this.phone = phone;
40 | }
41 |
42 | public String getEmail() {
43 | return email;
44 | }
45 |
46 | public void setEmail(String email) {
47 | this.email = email;
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/p06_adapter/src/com/jdc/model/StudentModel.java:
--------------------------------------------------------------------------------
1 | package com.jdc.model;
2 |
3 | import java.io.IOException;
4 | import java.nio.file.Files;
5 | import java.nio.file.Paths;
6 | import java.util.List;
7 |
8 | public class StudentModel {
9 |
10 | private List list;
11 |
12 | public StudentModel(String fileName) {
13 |
14 | try {
15 | list = Files.lines(Paths.get(fileName))
16 | .map(Student::new)
17 | .toList();
18 | } catch (IOException e) {
19 | e.printStackTrace();
20 | }
21 |
22 | }
23 |
24 | public List getAll() {
25 | return this.list;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/p06_adapter/students.txt:
--------------------------------------------------------------------------------
1 | 1 Aung Aung 09181717111 aung@gmail.com
2 | 2 Maung Maung 09373838444 maung@gmail.com
3 | 3 Thidar 09874747474 thidar@gmail.com
4 | 4 Thuzar 09383736333 thuzar@gmail.com
5 | 5 Thandar 09283737474 thandar@gmail.com
--------------------------------------------------------------------------------
/p07_decorator/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/p07_decorator/README.md:
--------------------------------------------------------------------------------
1 | ## Decorator Pattern
2 |
3 | Decorator Pattern ဆိုတာက Structural Design Pattern အမျိုးအစား Design Pattern တစ်ခုဖြစ်ပြီး ရှိပြီးသား Component တစ်ခုရဲ့ Function တွေကို Modify လုပ်လိုတဲ့အခါမှာ အသုံးပြုနိုင်တဲ့ Pattern တစ်ခုဖြစ်ပါတယ်။
4 |
5 | Decorator လေးတွေကို ကျွန်တော်တို့ အပြင်လောကမှာလဲ တွေ့မြင်နေကြဖြစ်ပါတယ်။ ကျွန်တော်တို့ Coffee ဆိုင်တစ်ဆိုင်သွားရင် ဆိုင်မှာ Black Coffee, Amaricano, Cafe latte, Cappuccino အစရှိသဖြင့် အမျိုးအစားတွေ အများကြီးရှိတာကို တွေ့ရပါမယ်။ ဒါပေမဲ့ အဲ့ဒီ Coffee တွေအားလုံးမှာ အခြေခံ Coffee ကရှိနေပြီး၊ Milk, Sugar, Ice အစရှိတာတွေကို Decorate လုပ်ပြီး မတူညီတဲ့ Coffee တွေကို Produce လုပ်နေကြတာပဲ ဖြစ်ပါတယ်။
6 |
7 |
8 |
9 | ### Implementations
10 |
11 | ရှိပြီးသား Component တစ်ခုရဲ့ Function တွေကို Modify လုပ်လိုတဲ့အခါ၊ Function အသစ်တွေကို ထပ်မံဖြည့်စွက်လိုတဲ့ အခါမှာ Decorator Pattern ကို အသုံးပြုနိုင်ပါတယ်။ Decorator Pattern မှာ Component, Concrete Component, Decorator, Concrete Decorator တို့ ပါဝင်ကြပါတယ်။
12 |
13 | #### Component
14 |
15 | Abstraction ဖြစ်တဲ့ Interface ဒါမှမဟုတ် Abstract Class တစ်ခုခုကို အသုံးပြုရေးသားနိုင်ပါတယ်။ Conceptual Level Function တွေကို သတ်မှတ်ရေးသားထားနိုင်ပါတယ်။ နမူနာထဲမှာတော့ Maker Interface ကို Component အနေနဲ့ အသုံးပြုပြီး dript():Coffee Method တစ်ခုကို ရေးသားထားပါတယ်။
16 |
17 | ```
18 | public interface Maker {
19 |
20 | Coffee drip();
21 |
22 | }
23 | ```
24 |
25 | #### Concrete Component
26 |
27 | Component မှာပါတဲ့ Function တွေကို Implement လုပ်ပြီးရေးသားထားပြီး မူလ Function တွေကို လုပ်ဆောင်ပေးနိုင်တဲ့ Concrete Class တစ်ခုဖြစ်ပါတယ်။
28 |
29 | ```
30 | public class CoffeeMaker implements Maker {
31 |
32 | @Override
33 | public Coffee drip() {
34 | var coffee = new Coffee();
35 | coffee.setCoffee(1);
36 | return coffee;
37 | }
38 | }
39 | ```
40 |
41 | #### Decorator
42 |
43 | Component Interface ကို Implement လုပ်ထားတဲ့ Class တစ်ခုပါ။ ဒီနေရာမှာတော့ Abstract Class ကို အသုံးပြုပြီး Member အနေနဲ့ Component Object တစ်ခုကို ပိုင်ဆိုင်ပါတယ်။ Function တွေကို Implement လုပ်တဲ့ အခါမှာ Original Component တွေရဲ့ Function တွေကို Modify လုပ်သွားမှာ ဖြစ်ပါတယ်။ နမူနာထဲမှာတော့ Abstract Class ကို အသုံးပြုထားပြီး Function တွေကိုတော့ Decorator ရဲ့ Sub Class တွေကျမှ Modify လုပ်သွားမှာ ဖြစ်ပါတယ်။
44 |
45 | Component ကို Constructor Argument ကနေ မဖြစ်မနေ ရယူစေချင်တဲ့ အတွက် ဒီနေရာမှာ Abstract Class ကို ရေးသားသွားတာ ဖြစ်ပါတယ်။
46 |
47 | ```
48 | public abstract class CoffeeMakerDecorator implements Maker {
49 |
50 | protected Maker maker;
51 |
52 | public CoffeeMakerDecorator(Maker maker) {
53 | this.maker = maker;
54 | }
55 |
56 | }
57 | ```
58 |
59 | #### Concrete Decorators
60 |
61 | Component ရဲ့ Function တွေကို Decorate လုပ်သွားမည့် Concrete Class တွေဖြစ်ကြပြီး Decorator Class ကို Extends လုပ်ထားရပါမယ်။
62 |
63 | ```
64 | public class IceDecorator extends CoffeeMakerDecorator {
65 |
66 | public IceDecorator(Maker maker) {
67 | super(maker);
68 | }
69 |
70 | @Override
71 | public Coffee drip() {
72 | var coffee = maker.drip();
73 | coffee.setIce(1);
74 | return coffee;
75 | }
76 | }
77 | ```
78 |
79 |
--------------------------------------------------------------------------------
/p07_decorator/class-diagram.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minlwin/design-patterns/d7f6b79cf6f9cc807c63609906b635f1175b2a3a/p07_decorator/class-diagram.png
--------------------------------------------------------------------------------
/p07_decorator/src/com/jdc/coffee/shop/AppMain.java:
--------------------------------------------------------------------------------
1 | package com.jdc.coffee.shop;
2 |
3 | public class AppMain {
4 |
5 | public static void main(String[] args) {
6 |
7 | var pureCoffeeMaker = new CoffeeMaker();
8 | System.out.println(pureCoffeeMaker.drip());
9 |
10 | var blakcCoffeeMaker = new SugarDecorator(pureCoffeeMaker);
11 | System.out.println(blakcCoffeeMaker.drip());
12 |
13 | var iceCoffeeMaker = new IceDecorator(blakcCoffeeMaker);
14 | System.out.println(iceCoffeeMaker.drip());
15 |
16 | var noSugarIceCoffeeMaker = new IceDecorator(pureCoffeeMaker);
17 | System.out.println(noSugarIceCoffeeMaker.drip());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/p07_decorator/src/com/jdc/coffee/shop/Coffee.java:
--------------------------------------------------------------------------------
1 | package com.jdc.coffee.shop;
2 |
3 | public class Coffee {
4 |
5 | private int coffee;
6 | private int sugar;
7 | private int milk;
8 | private int ice;
9 |
10 | public int getCoffee() {
11 | return coffee;
12 | }
13 |
14 | public void setCoffee(int coffee) {
15 | this.coffee = coffee;
16 | }
17 |
18 | public int getSugar() {
19 | return sugar;
20 | }
21 |
22 | public void setSugar(int sugar) {
23 | this.sugar = sugar;
24 | }
25 |
26 | public int getMilk() {
27 | return milk;
28 | }
29 |
30 | public void setMilk(int milk) {
31 | this.milk = milk;
32 | }
33 |
34 | public int getIce() {
35 | return ice;
36 | }
37 |
38 | public void setIce(int ice) {
39 | this.ice = ice;
40 | }
41 |
42 | @Override
43 | public String toString() {
44 | return "Coffee [coffee=" + coffee + ", sugar=" + sugar + ", milk=" + milk + ", ice=" + ice + "]";
45 | }
46 |
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/p07_decorator/src/com/jdc/coffee/shop/CoffeeMaker.java:
--------------------------------------------------------------------------------
1 | package com.jdc.coffee.shop;
2 |
3 | public class CoffeeMaker implements Maker {
4 |
5 | @Override
6 | public Coffee drip() {
7 | var coffee = new Coffee();
8 | coffee.setCoffee(1);
9 | return coffee;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/p07_decorator/src/com/jdc/coffee/shop/CoffeeMakerDecorator.java:
--------------------------------------------------------------------------------
1 | package com.jdc.coffee.shop;
2 |
3 | public abstract class CoffeeMakerDecorator implements Maker {
4 |
5 | protected Maker maker;
6 |
7 | public CoffeeMakerDecorator(Maker maker) {
8 | this.maker = maker;
9 | }
10 |
11 | }
--------------------------------------------------------------------------------
/p07_decorator/src/com/jdc/coffee/shop/IceDecorator.java:
--------------------------------------------------------------------------------
1 | package com.jdc.coffee.shop;
2 |
3 | public class IceDecorator extends CoffeeMakerDecorator {
4 |
5 | public IceDecorator(Maker maker) {
6 | super(maker);
7 | }
8 |
9 | @Override
10 | public Coffee drip() {
11 | var coffee = maker.drip();
12 | coffee.setIce(1);
13 | return coffee;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/p07_decorator/src/com/jdc/coffee/shop/Maker.java:
--------------------------------------------------------------------------------
1 | package com.jdc.coffee.shop;
2 |
3 | public interface Maker {
4 |
5 | Coffee drip();
6 |
7 | }
--------------------------------------------------------------------------------
/p07_decorator/src/com/jdc/coffee/shop/SugarDecorator.java:
--------------------------------------------------------------------------------
1 | package com.jdc.coffee.shop;
2 |
3 | public class SugarDecorator extends CoffeeMakerDecorator{
4 |
5 | public SugarDecorator(Maker maker) {
6 | super(maker);
7 | }
8 |
9 | @Override
10 | public Coffee drip() {
11 | var coffee = maker.drip();
12 | coffee.setSugar(1);
13 | return coffee;
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/p08_proxy/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/p08_proxy/README.md:
--------------------------------------------------------------------------------
1 | ## Proxy Pattern
2 |
3 | Proxy Pattern ဆိုတာကတော့ Structural Design Pattern အမျိုးအစားတစ်ခုဖြစ်ပြီး၊ Target Object တစ်ခုကို တိုက်ရိုက်ဆက်သွယ်ပြီး အလုပ်မလုပ်စေလိုတဲ့အခါမှာ ကိုယ်စား Object တစ်ခုကို ခံပြီး အသုံးပြုစေနိုင်တဲ့ Design Pattern ဖြစ်ပါတယ်။ Proxy ရဲ့ General Definition မှာကိုက "authority or power to act for another" လို့ဆိုတဲ့အတွက် ကိုယ်စားဆောင်ရွက်ပေးနိုင်တဲ့ သဘောသက်ရောက်ပါတယ်။
4 |
5 | Proxy Pattern ကို Java Framework တွေအတော်များများမှာ တွေ့ရတတ်ပါတယ်။
6 |
7 | - EJB ရဲ့ Remote Bean တွေနှင့် RMI Specification တွေမှာလဲ Proxy တွေကို အသုံးပြုထားကြပါတယ်
8 | - JPA ရဲ့ Entity Object တွေဟာလဲ Proxy တွေဖြစ်ကြပြီး၊ Lazy Loaded Attribute တွေကို Setter Method ကနေ Access လုပ်တဲ့အခါမှာ Database ကနေ Fatch လုပ်နိုင်အောင် ဆောင်ရွက်ပေးကြပါတယ်
9 | - Spring AOP မှာလဲ Cross Cutting ကို ဆောင်ရွက်နိုင်အောင် Proxy တွေကို အသုံးပြုကြပါတယ်
10 | - Object တွေရဲ့ Access Control ကို ဆောင်ရွက်လိုတဲ့ အခါတွေမှာလဲ Proxy တွေကို အသုံးပြုကြပါတယ်
11 |
12 | ### Implementation
13 |
14 | နမူနာအနေနဲ့ Search Engine တစ်ခုရှိပြီး၊ အဲ့ဒီ Search Engine မှာ Data တွေကို ရှာရတာ Resource တွေကို အရမ်းသုံးရပြီး အချိန်ကြာနိုင်တယ်လို့ ဆိုကြပါစို့။ အဲ့ဒီအခါမျိုးမှာ ကျွန်တော်တို့အနေနဲ့ တစ်ခါရှာထားပြီးသားစကားလုံးကို Cache ထဲမှာ သိမ်းထားပြီး Cache ထဲမှာမရှိမှသာ Search Engine ကို အသုံးပြုပြီးရှာမယ်လို့ လုပ်ချင်ပါလိမ့်မယ်။ အဲ့ဒီလိုအခါမျိုးတွေမှာ Proxy Pattern ကို အသုံးပြုနိုင်ပါတယ်။
15 |
16 |
17 |
18 | #### Service Interface
19 |
20 | ```
21 | public interface SearchService {
22 |
23 | String search(String keyword);
24 | }
25 | ```
26 |
27 | #### Concrete Service Class
28 |
29 | ```
30 | public class SearchEngine implements SearchService{
31 |
32 | private Map engine;
33 |
34 | public SearchEngine() {
35 | engine = new HashMap<>();
36 | engine.put("Hi", "Hello");
37 | engine.put("japanese hi", "konni chiwa");
38 | engine.put("sayonara", "Good Bye");
39 | engine.put("thanks", "Arigato");
40 | engine.put("java", "Programming Language");
41 | }
42 |
43 | @Override
44 | public String search(String keyword) {
45 |
46 | try {
47 | Thread.sleep(2000);
48 | } catch (InterruptedException e) {
49 | e.printStackTrace();
50 | }
51 |
52 | var result = engine.get(keyword);
53 |
54 | if(null == result) {
55 | result = "There is no result";
56 | }
57 |
58 | return result;
59 | }
60 |
61 | }
62 | ```
63 |
64 | Service Interface ကို Implement လုပ်ထားတဲ့ Business Class ဖြစ်ပြီး၊ Search Operation ကို လုပ်ဆောင်ရာမှာ အချိန်ကြာတယ် ဆိုတာကို ဖြစ်အောင် နမူနာ အနေနဲ့ ရေးသားထားပါတယ်။
65 |
66 | #### Proxy Class
67 |
68 | ```
69 | public class SearchServicePorxy implements SearchService{
70 |
71 | private Map cache;
72 | private SearchService serivce;
73 |
74 | public SearchServicePorxy(SearchService serivce) {
75 | super();
76 | this.serivce = serivce;
77 | cache = Collections.synchronizedMap(new HashMap<>());
78 | }
79 |
80 | @Override
81 | public String search(String keyword) {
82 |
83 | var result = cache.get(keyword);
84 |
85 | if(result == null) {
86 | result = serivce.search(keyword);
87 |
88 | if(!result.equals("There is no result")) {
89 | cache.put(keyword, result);
90 | }
91 | }
92 |
93 | return result;
94 | }
95 |
96 | }
97 | ```
98 |
99 | Cache ကို အသုံးပြုနိုင်တဲ့ Proxy အနေနဲ့ကတော့ Service Interface ကို Implement လုပ်ထားပြီး၊ Concrete Service ကို Member Object အနေနဲ့ အသုံးပြုထားပါတယ်။
100 |
101 | Search Method ကို လုပ်ဆောင်တိုင်းမှာ အရင်ဆုံး Cache ထဲကနေ Keyword နဲ့ရှာပြီး၊ မတွေ့ရင် Service Object ကို အသုံးပြုပြီးရှာပါတယ်။ Service ကို သုံးပြီးရှာတဲ့အခါ တွေ့လာရင်လဲ Cache ထဲမှာ မှတ်သွားပါတယ်။ ဤနည်းအားဖြင့် Search Method ရဲ့ Operation ကို မြန်ဆန်စွာ ဆောင်ရွက်နိုင်အောင် Proxy လေးက လုပ်ဆောင်ပေးနိုင်ပါတယ်။
102 |
103 | Proxy Pattern ရဲ့ အဓိက ရည်ရွယ်ချက်ကတော့ နဂိုရှိရင်းစွဲ Operation တွေမှာ Logic အသစ်တွေကို ဖြည့်စွက်လိုတဲ့အခါ Modify လုပ်ပြီး အသုံးပြုလိုတဲ့ အခါမှာ နဂိုရှိရင်းစွဲ Operation ကို တိုက်ရိုက်မပြင်ပဲ Extends လုပ်ပြီးရေးသွားနိုင်ဖို့အတွက်ပဲ ဖြစ်ပါတယ်။
--------------------------------------------------------------------------------
/p08_proxy/class-design.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minlwin/design-patterns/d7f6b79cf6f9cc807c63609906b635f1175b2a3a/p08_proxy/class-design.png
--------------------------------------------------------------------------------
/p08_proxy/src/com/jdc/proxy/SearchEngine.java:
--------------------------------------------------------------------------------
1 | package com.jdc.proxy;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | public class SearchEngine implements SearchService{
7 |
8 | private Map engine;
9 |
10 | public SearchEngine() {
11 | engine = new HashMap<>();
12 | engine.put("Hi", "Hello");
13 | engine.put("japanese hi", "konni chiwa");
14 | engine.put("sayonara", "Good Bye");
15 | engine.put("thanks", "Arigato");
16 | engine.put("java", "Programming Language");
17 | }
18 |
19 | @Override
20 | public String search(String keyword) {
21 |
22 | try {
23 | Thread.sleep(2000);
24 | } catch (InterruptedException e) {
25 | e.printStackTrace();
26 | }
27 |
28 | var result = engine.get(keyword);
29 |
30 | if(null == result) {
31 | result = "There is no result";
32 | }
33 |
34 | return result;
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/p08_proxy/src/com/jdc/proxy/SearchEngineDemo.java:
--------------------------------------------------------------------------------
1 | package com.jdc.proxy;
2 |
3 | import java.util.Scanner;
4 |
5 | public class SearchEngineDemo {
6 |
7 | public static void main(String[] args) {
8 |
9 | var scanner = new Scanner(System.in);
10 |
11 | var engine = new SearchServicePorxy(new SearchEngine());
12 |
13 | while(true) {
14 |
15 | System.out.print("Enter Keyword : ");
16 | var keyword = scanner.nextLine();
17 |
18 | var result = engine.search(keyword);
19 | System.out.println("Result : %s".formatted(result));
20 |
21 | System.out.print("Continue (Y/Others) : ");
22 |
23 | if(!"Y".equalsIgnoreCase(scanner.nextLine())) {
24 | break;
25 | }
26 | }
27 |
28 | scanner.close();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/p08_proxy/src/com/jdc/proxy/SearchService.java:
--------------------------------------------------------------------------------
1 | package com.jdc.proxy;
2 |
3 | public interface SearchService {
4 |
5 | String search(String keyword);
6 | }
7 |
--------------------------------------------------------------------------------
/p08_proxy/src/com/jdc/proxy/SearchServicePorxy.java:
--------------------------------------------------------------------------------
1 | package com.jdc.proxy;
2 |
3 | import java.util.Collections;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 |
7 | public class SearchServicePorxy implements SearchService{
8 |
9 | private Map cache;
10 | private SearchService serivce;
11 |
12 | public SearchServicePorxy(SearchService serivce) {
13 | super();
14 | this.serivce = serivce;
15 | cache = Collections.synchronizedMap(new HashMap<>());
16 | }
17 |
18 | @Override
19 | public String search(String keyword) {
20 |
21 | var result = cache.get(keyword);
22 |
23 | if(result == null) {
24 | result = serivce.search(keyword);
25 |
26 | if(!result.equals("There is no result")) {
27 | cache.put(keyword, result);
28 | }
29 | }
30 |
31 | return result;
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/p08_proxy/src/com/jdc/proxy/dynamic/DynamicProxyDemo.java:
--------------------------------------------------------------------------------
1 | package com.jdc.proxy.dynamic;
2 |
3 | import java.lang.reflect.InvocationHandler;
4 | import java.lang.reflect.Method;
5 | import java.lang.reflect.Proxy;
6 | import java.util.Collections;
7 | import java.util.HashMap;
8 | import java.util.Map;
9 | import java.util.Scanner;
10 |
11 | import com.jdc.proxy.SearchEngine;
12 | import com.jdc.proxy.SearchService;
13 |
14 | public class DynamicProxyDemo {
15 |
16 |
17 | public static void main(String[] args) {
18 |
19 | SearchService engine = getDynamicProxy();
20 | var scanner = new Scanner(System.in);
21 |
22 | while(true) {
23 |
24 | System.out.print("Enter Keyword : ");
25 | var keyword = scanner.nextLine();
26 |
27 | var result = engine.search(keyword);
28 | System.out.println("Result : %s".formatted(result));
29 |
30 | System.out.print("Continue (Y/Others) : ");
31 |
32 | if(!"Y".equalsIgnoreCase(scanner.nextLine())) {
33 | break;
34 | }
35 | }
36 |
37 | scanner.close();
38 |
39 |
40 | }
41 |
42 | private static SearchService getDynamicProxy() {
43 |
44 | var proxy = Proxy.newProxyInstance(DynamicProxyDemo.class.getClassLoader(),
45 | new Class[] {SearchService.class}, new SearchEngineDynanicProxy(new SearchEngine()));
46 |
47 | return (SearchService)proxy;
48 | }
49 |
50 | static class SearchEngineDynanicProxy implements InvocationHandler {
51 |
52 | private Object target;
53 |
54 | private Map map;
55 |
56 | public SearchEngineDynanicProxy(Object target) {
57 | super();
58 | this.target = target;
59 | map = Collections.synchronizedMap(new HashMap<>());
60 | }
61 |
62 | @Override
63 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
64 |
65 | if(method.getName().equals("search")) {
66 | var result = map.get(args[0].toString());
67 |
68 | if(null == result) {
69 | result = String.valueOf(method.invoke(target, args));
70 |
71 | if(!result.equals("There is no result")) {
72 | map.put(args[0].toString(), result);
73 | }
74 | }
75 | return result;
76 | }
77 |
78 | return null;
79 | }
80 |
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/p09_bridge/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/p09_bridge/README.md:
--------------------------------------------------------------------------------
1 | ## Bridge Pattern
2 |
3 | တကယ်လို့ Object တစ်ခုမှာ Abstraction အပိုင်းနှင့် Implementation အပိုင်းတို့မှာ သီးခြားစီတည်ရှိနေပြီး၊ အသီးသီးပြောင်းလဲနိုင်ခြေရှိတယ်ဆိုရင် Bridge Pattern ကို အသုံးပြုနိုင်ပါတယ်။
4 |
5 | ရေးသားနေတဲ့ System တစ်ခုမှာ TableView တစ်ခုကို ရေးဖို့လိုအပ်လာပြီး၊ အဲ့ဒီ TableView နဲ့ Student Data တွေနဲ့ Course Data တွေကို ပြဖို့လိုအပ်တယ်လို့ ဆိုကြပါစို့။ ထို့အပြင် Table ကိုလဲ Vertical Table View အနေနဲ့ကော Horizontal Table View အနေနဲ့ပါရေးဖို့လိုအပ်တဲ့ အခါမျိုးမှာ Class Design တွေကိုအောက်ပါအတိုင်း စဉ်းစားမိကြပါလိမ့်မယ်။
6 |
7 |
8 |
9 | ဒီနေရာမှာ Table ကို ဘယ်လို Data တွေနဲ့ သုံးမှာလဲဆိုတဲ့ Implementation အပိုင်းနဲ့ ဘယ်လို Presentation မျိုးနဲ့ပြမလဲ ဆိုတဲ့ Abstraction အပိုင်းတွေရှိကြပြီး နှစ်မျိုးစလုံးမှာ ပြောင်းလဲမှုတွေရှိလာနိုင်တဲ့ အချက်က ပြဿနာပဲ ဖြစ်ပါတယ်။ ဘယ်နေရာမှာပဲ ပြောင်းပြောင်း ပြင်ရမည့်နေရာတွေက တစ်နေရာထဲမှာ ပြီးမသွားဘူးဆိုတဲ့ အချက်ပါပဲ။
10 |
11 | Registration Data ကိုလဲ Table View မှာ သုံးချင်လာတယ် ဆိုကြပါစို့။ အနဲဆုံး VerticalRegistrationTableView နဲ့ HorizontalRegistrationTableView ဆိုတဲ့ Class နှစ်ခုကို ထပ်ပြီးဖြည့်စွက်ကြရပါတော့မယ်။
12 |
13 |
14 |
15 | အထက်ပါ Class Diagram အတိုင်း ဘယ်လို Data နဲ့ပြမလဲ ဆိုတဲ့အပိုင်းနှင့် Table View ကို ဘယ်လိုပြမလဲဆိုတဲ့ အပိုင်းကို အသီးသီးခွဲထုတ်ပြီး၊ Polymorphic ဖြစ်အောင် ရေးသားစေခြင်းအားဖြင့် ဘယ်ဘက်ကပဲ ပြောင်းပြောင်း တစ်ခြားတစ်ဘက်ကို ပြင်စရာမလိုအောင် ဆောင်ရွက်စေနိုင်တယ်ဆိုတာကတော့ Bridge Pattern ရဲ့ ရည်ရွယ်ချက်ဖြစ်ပါတယ်။
16 |
17 | ### Implementations
18 |
19 | Bridge Pattern မှာ Abstraction, Refined Abstraction, Implementor, Concrete Implementor ဆိုတဲ့ Class တွေနဲ့ ဖွဲ့စည်းတည်ဆောက်ထားပါတယ်။
20 |
21 | #### Abstraction
22 |
23 | Component ရဲ့ အဓိကလုပ်ဆောင်စေလိုတဲ့ Behavior ကို သတ်မှတ်ထားပြီး၊ ဘယ်လို Implementation မျိုးနဲ့တွဲဖက်အသုံးပြုမှာလဲ ဆိုတာကို သတ်မှတ်ဖို့အတွက် Implementor ကို Reference လုပ်ထားနိုင်ဖို့လိုအပ်ပါတယ်။ ဖေါ်ပြပါနမူနာထဲမှာတော့ TableView Class ဟာ Abstraction နေရာကို ကိုယ်စားပြုတဲ့ Class ဖြစ်ပါတယ်။ Table View ဖြစ်သည့်အလျောက် Table တစ်ခုကို ဘယ်လိုတည်ဆောက်မလဲဆိုတဲ့ draw() Method ဟာ Component ရဲ့ Interface ဖြစ်ပါတယ်။
24 |
25 | တဖန် ဘယ်လို Data မျိုးနဲ့ Table View ကို တည်ဆောက်ရမလဲဆိုတာကို ပံ့ပိုးပေးနိုင်တဲ့ Implementor ဖြစ်တဲ့ DataModel ကို Reference လုပ်ထားပါတယ်။ လက်တွေ့ Table View ကို တည်ဆောက်တဲ့အခါမှာလဲ DataModel ကို အသုံးပြုပြီး တည်ဆောက်သွားပါတယ်။
26 |
27 | ```
28 | public abstract class TableView {
29 |
30 | // Reference to Implementor
31 | protected DataModel model;
32 |
33 | protected List colLengths;
34 |
35 | // Inject Implementor from Constructor Argument
36 | public TableView(DataModel model) {
37 | super();
38 | this.model = model;
39 | colLengths = new ArrayList<>();
40 |
41 | init();
42 | }
43 |
44 | protected abstract void init();
45 |
46 | // Main Function (Abstraction Interface)
47 | public abstract void draw();
48 |
49 | // Common Methods
50 |
51 | }
52 | ```
53 |
54 | #### Refined Abstraction
55 |
56 | Abstraction ဖြစ်တဲ့ TableView Class ရဲ့ draw() Method ကို Presentation အလိုက် Extends လုပ်ပြီး သတ်မှတ်ရေးသားပေးဖို့ တာဝန်ရှိပါတယ်။ နမူနာထဲမှာတော့ HorizontalTableView နှင့် VerticalTableView တို့ဟာ Refined Abstraction တွေဖြစ်ကြပါတယ်။
57 |
58 | ```
59 | public class HorizontalTableView extends TableView{
60 |
61 | public HorizontalTableView(DataModel model) {
62 | super(model);
63 | }
64 |
65 | @Override
66 | protected void init() {
67 |
68 | colLengths.addAll(model.headers().stream().map(a -> a.length() + 4).toList());
69 |
70 | for(var rowIndex = 0; rowIndex < model.size(); rowIndex ++) {
71 |
72 | var row = model.row(rowIndex);
73 |
74 | for(var colIndex = 0; colIndex < row.size(); colIndex ++) {
75 |
76 | var colSize = row.get(colIndex).length() + 4;
77 |
78 | if(colSize > colLengths.get(colIndex)) {
79 | colLengths.set(colIndex, colSize);
80 | }
81 | }
82 | }
83 | }
84 |
85 | // Extension point of Abstraction
86 | @Override
87 | public void draw() {
88 |
89 | // Draw Title
90 | System.out.println("Horizontal %s Table".formatted(model.title()));
91 | printLine();
92 | printRow(model.headers());
93 | printLine();
94 |
95 | for(var i = 0; i < model.size(); i ++) {
96 | printRow(model.row(i));
97 | }
98 | printLine();
99 | }
100 |
101 | // Private Methods
102 |
103 | }
104 | ```
105 |
106 | #### Implementor
107 |
108 | Abstraction ထဲမှာ အသုံးပြုလိုတဲ့ လုပ်ဆောင်ချက်တွေကို စုစည်းပေးထားတဲ့ Interface တစ်ခုဖြစ်ပါတယ်။ Abstraction ထဲမှာ အဓိကလုပ်ဆောင်လိုတဲ့ အလုပ်ကို Implementor ဘက်ကနေပြင်ပေးထားတဲ့ Behavior တွေကို အသုံးပြုပြီး ရေးသားသွားကြရမှာ ဖြစ်ပါတယ်။ နမူနာထဲမှာတော့ DataModel Interface ဟာ Implementor နေရာကို ကိုယ်စားပြုပါတယ်။
109 |
110 | ```
111 | public interface DataModel {
112 |
113 | String title();
114 |
115 | int size();
116 |
117 | List headers();
118 |
119 | List row(int index);
120 | }
121 | ```
122 |
123 | #### Concrete Implementor
124 |
125 | Implementor Interface ကို Implements လုပ်ထားတဲ့ Concrete Class တွေဖြစ်ကြပြီး၊ Abstraction မှာ အသုံးပြုမည့် Primitive Operation တွေကို အသေးစိတ် ရေးသားပေးထားရပါမယ်။ နမူနာထဲက StudentDataModel နှင့် CourseDataModel တို့ဟာ Concrete Implementor များဖြစ်ကြပါတယ်။
126 |
127 | ```
128 | public class CourseDataModel implements DataModel{
129 |
130 | private List courses;
131 |
132 | public CourseDataModel(String fileName) {
133 | try(var stream = Files.lines(Path.of(fileName))) {
134 | courses = stream.map(Course::from).toList();
135 | } catch (IOException e) {
136 | e.printStackTrace();
137 | }
138 | }
139 |
140 | @Override
141 | public String title() {
142 | return "Course";
143 | }
144 |
145 | @Override
146 | public int size() {
147 | return courses.size();
148 | }
149 |
150 | @Override
151 | public List headers() {
152 | return List.of("ID", "NAME", "LEVEL", "HOURS", "FEES");
153 | }
154 |
155 | @Override
156 | public List row(int index) {
157 | return courses.get(index).toList();
158 | }
159 |
160 | }
161 | ```
162 |
--------------------------------------------------------------------------------
/p09_bridge/class-design-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minlwin/design-patterns/d7f6b79cf6f9cc807c63609906b635f1175b2a3a/p09_bridge/class-design-1.png
--------------------------------------------------------------------------------
/p09_bridge/class-design-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minlwin/design-patterns/d7f6b79cf6f9cc807c63609906b635f1175b2a3a/p09_bridge/class-design-2.png
--------------------------------------------------------------------------------
/p09_bridge/courses.txt:
--------------------------------------------------------------------------------
1 | 1 Java Basic Basic 120 300000
2 | 2 Spring Framework Intermediate 240 500000
3 | 3 Flutter Foundation Basic 120 300000
4 | 4 Angular Basic 120 300000
--------------------------------------------------------------------------------
/p09_bridge/src/com/jdc/bridge/BridgeDemo.java:
--------------------------------------------------------------------------------
1 | package com.jdc.bridge;
2 |
3 | import com.jdc.bridge.component.HorizontalTableView;
4 | import com.jdc.bridge.component.TableView;
5 | import com.jdc.bridge.component.VerticalTableView;
6 | import com.jdc.bridge.model.CourseDataModel;
7 | import com.jdc.bridge.model.StudentDataModel;
8 |
9 | public class BridgeDemo {
10 |
11 | public static void main(String[] args) {
12 |
13 | var students = new StudentDataModel("students.txt");
14 | draw(new HorizontalTableView(students));
15 | draw(new VerticalTableView(students));
16 |
17 | var courses = new CourseDataModel("courses.txt");
18 | draw(new HorizontalTableView(courses));
19 | draw(new VerticalTableView(courses));
20 | }
21 |
22 | static void draw(TableView table) {
23 | table.draw();
24 | System.out.println();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/p09_bridge/src/com/jdc/bridge/component/DataModel.java:
--------------------------------------------------------------------------------
1 | package com.jdc.bridge.component;
2 |
3 | import java.util.List;
4 |
5 | public interface DataModel {
6 |
7 | String title();
8 |
9 | int size();
10 |
11 | List headers();
12 |
13 | List row(int index);
14 | }
15 |
--------------------------------------------------------------------------------
/p09_bridge/src/com/jdc/bridge/component/HorizontalTableView.java:
--------------------------------------------------------------------------------
1 | package com.jdc.bridge.component;
2 |
3 | import java.util.List;
4 |
5 | public class HorizontalTableView extends TableView{
6 |
7 | public HorizontalTableView(DataModel model) {
8 | super(model);
9 | }
10 |
11 | @Override
12 | protected void init() {
13 |
14 | colLengths.addAll(model.headers().stream().map(a -> a.length() + 4).toList());
15 |
16 | for(var rowIndex = 0; rowIndex < model.size(); rowIndex ++) {
17 |
18 | var row = model.row(rowIndex);
19 |
20 | for(var colIndex = 0; colIndex < row.size(); colIndex ++) {
21 |
22 | var colSize = row.get(colIndex).length() + 4;
23 |
24 | if(colSize > colLengths.get(colIndex)) {
25 | colLengths.set(colIndex, colSize);
26 | }
27 | }
28 | }
29 | }
30 |
31 | @Override
32 | public void draw() {
33 |
34 | // Draw Title
35 | System.out.println("Horizontal %s Table".formatted(model.title()));
36 | printLine();
37 | printRow(model.headers());
38 | printLine();
39 |
40 | for(var i = 0; i < model.size(); i ++) {
41 | printRow(model.row(i));
42 | }
43 | printLine();
44 | }
45 |
46 | private void printRow(List row) {
47 | for(var i = 0; i < row.size(); i ++) {
48 | var colLength = colLengths.get(i);
49 | var colData = row.get(i);
50 | System.out.printf("%%-%ds".formatted(colLength).formatted(colData));
51 | }
52 | System.out.println();
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/p09_bridge/src/com/jdc/bridge/component/TableView.java:
--------------------------------------------------------------------------------
1 | package com.jdc.bridge.component;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | public abstract class TableView {
7 |
8 | protected DataModel model;
9 |
10 | protected List colLengths;
11 |
12 | public TableView(DataModel model) {
13 | super();
14 | this.model = model;
15 | colLengths = new ArrayList<>();
16 |
17 | init();
18 | }
19 |
20 | protected abstract void init();
21 |
22 | public abstract void draw();
23 |
24 | protected void printLine() {
25 | var lineSize = colLengths.stream().mapToInt(a -> a).sum();
26 | System.out.println("%%%ds".formatted(lineSize).formatted("").replaceAll(" ", "-"));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/p09_bridge/src/com/jdc/bridge/component/VerticalTableView.java:
--------------------------------------------------------------------------------
1 | package com.jdc.bridge.component;
2 |
3 | public class VerticalTableView extends TableView{
4 |
5 | private int headerSize;
6 |
7 | public VerticalTableView(DataModel model) {
8 | super(model);
9 | }
10 |
11 | @Override
12 | protected void init() {
13 |
14 |
15 | // Column Sizes
16 | for(var x = 0; x < model.size(); x ++) {
17 | colLengths.add(0);
18 |
19 | var row = model.row(x);
20 |
21 | for(var y = 0; y < row.size(); y ++) {
22 | var colLength = row.get(y).length() + 4;
23 |
24 | if(colLength > colLengths.get(x)) {
25 | colLengths.set(x, colLength);
26 | }
27 | }
28 | }
29 |
30 | // Header Size
31 | headerSize = model.headers().stream().mapToInt(a -> a.length() + 4)
32 | .max().getAsInt();
33 | colLengths.add(headerSize);
34 | }
35 |
36 | @Override
37 | public void draw() {
38 |
39 | System.out.println("Vertical %s Table".formatted(model.title()));
40 | printLine();
41 |
42 | for(var y = 0; y < model.headers().size(); y ++) {
43 |
44 | System.out.printf("%%-%ds".formatted(headerSize).formatted(model.headers().get(y)));
45 |
46 | for(var x = 0; x < model.size(); x ++) {
47 |
48 | var row = model.row(x);
49 | System.out.printf("%%-%ds".formatted(colLengths.get(x)).formatted(row.get(y)));
50 | }
51 | System.out.println();
52 | }
53 | printLine();
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/p09_bridge/src/com/jdc/bridge/model/Course.java:
--------------------------------------------------------------------------------
1 | package com.jdc.bridge.model;
2 |
3 | import java.util.List;
4 |
5 | public record Course(
6 | int id,
7 | String name,
8 | String level,
9 | int hours,
10 | int fees
11 | ) {
12 |
13 | public static Course from(String line) {
14 | var array = line.split("\t");
15 | return new Course(
16 | Integer.parseInt(array[0]),
17 | array[1],
18 | array[2],
19 | Integer.parseInt(array[3]),
20 | Integer.parseInt(array[4]));
21 | }
22 |
23 | public List toList() {
24 | return List.of(String.valueOf(id), name, level, String.valueOf(hours), String.valueOf(fees));
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/p09_bridge/src/com/jdc/bridge/model/CourseDataModel.java:
--------------------------------------------------------------------------------
1 | package com.jdc.bridge.model;
2 |
3 | import java.io.IOException;
4 | import java.nio.file.Files;
5 | import java.nio.file.Path;
6 | import java.util.List;
7 |
8 | import com.jdc.bridge.component.DataModel;
9 |
10 | public class CourseDataModel implements DataModel{
11 |
12 | private List courses;
13 |
14 | public CourseDataModel(String fileName) {
15 | try(var stream = Files.lines(Path.of(fileName))) {
16 | courses = stream.map(Course::from).toList();
17 | } catch (IOException e) {
18 | e.printStackTrace();
19 | }
20 | }
21 |
22 | @Override
23 | public String title() {
24 | return "Course";
25 | }
26 |
27 | @Override
28 | public int size() {
29 | return courses.size();
30 | }
31 |
32 | @Override
33 | public List headers() {
34 | return List.of("ID", "NAME", "LEVEL", "HOURS", "FEES");
35 | }
36 |
37 | @Override
38 | public List row(int index) {
39 | return courses.get(index).toList();
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/p09_bridge/src/com/jdc/bridge/model/Student.java:
--------------------------------------------------------------------------------
1 | package com.jdc.bridge.model;
2 |
3 | import java.util.List;
4 |
5 | public record Student(
6 | int id,
7 | String name,
8 | String phone,
9 | String email
10 | ) {
11 |
12 | public static Student from(String line) {
13 | var array = line.split("\t");
14 | return new Student(Integer.parseInt(array[0]), array[1], array[2], array[3]);
15 | }
16 |
17 | public List toList() {
18 | return List.of(String.valueOf(id), name, phone, email);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/p09_bridge/src/com/jdc/bridge/model/StudentDataModel.java:
--------------------------------------------------------------------------------
1 | package com.jdc.bridge.model;
2 |
3 | import java.io.IOException;
4 | import java.nio.file.Files;
5 | import java.nio.file.Path;
6 | import java.util.List;
7 |
8 | import com.jdc.bridge.component.DataModel;
9 |
10 | public class StudentDataModel implements DataModel{
11 |
12 | private List students;
13 |
14 | public StudentDataModel(String fileName) {
15 |
16 | try(var stream = Files.lines(Path.of(fileName))) {
17 | students = stream.map(Student::from).toList();
18 | } catch (IOException e) {
19 | e.printStackTrace();
20 | }
21 | }
22 |
23 | @Override
24 | public String title() {
25 | return "Student";
26 | }
27 |
28 | @Override
29 | public int size() {
30 | return students.size();
31 | }
32 |
33 | @Override
34 | public List headers() {
35 | return List.of("ID", "NAME", "PHONE", "EMAIL");
36 | }
37 |
38 | @Override
39 | public List row(int index) {
40 | return students.get(index).toList();
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/p09_bridge/students.txt:
--------------------------------------------------------------------------------
1 | 1 Aung Aung 09181717111 aung@gmail.com
2 | 2 Maung Maung 09373838444 maung@gmail.com
3 | 3 Thidar 09874747474 thidar@gmail.com
4 | 4 Thuzar 09383736333 thuzar@gmail.com
5 | 5 Thandar 09283737474 thandar@gmail.com
--------------------------------------------------------------------------------
/p10_facade/.gitignore:
--------------------------------------------------------------------------------
1 | /bin/
2 |
--------------------------------------------------------------------------------
/p10_facade/README.md:
--------------------------------------------------------------------------------
1 | ## Facade Pattern
2 |
3 | Facade Pattern ဟာ Structural Design Pattern အမျိုးအစားထဲက Design Pattern တစ်ခုဖြစ်ပြီး၊ ရေးသားနေတဲ့ Library, Framework, Sub System တစ်ခုအတွက် ရိုးရှင်းတဲ့ Interface တစ်ခုကို ပြင်ဆင်ပေးနိုင်ပါတယ်။
4 |
5 | Class များစွာပါဝင်တဲ့ Sub System တစ်ခုကို ရေးသားနေကြပြီး အတွင်းပိုင်းမှာ Class တွေရဲ့ Dependency ကလဲ ရှုပ်ထွေးနေတယ်ဆိုရင် အသုံးပြုသူတစ်ယောက်အနေနဲ့ Class တစ်ခုကို အသုံးပြုဖို့ ဘယ်လို Dependency တွေကို ပြင်ဆင်ပေးရမယ်ဆိုတာဟာ အမတန် စိတ်ရှုပ်စရာကောင်းလာမှာ ဖြစ်ပါတယ်။
6 |
7 |
8 |
9 | Student Management System ရဲ့ Backend အတွက် Sub System တစ်ခုကို စဉ်းစားကြည့်မယ်ဆိုရင်ပဲ Database Table တွေကို ကိုယ်စားပြုတဲ့ DTO Class တွေ၊ Data Access Object အတွက် DAO Class တွေပြီးတော့ Message Queue တွေနဲ့ Daemon Service Class တွေများစွာပါဝင်နိုင်ပါတယ်။ Sub System အတွင်မှာရှိတဲ့ Class တွေဟာလဲ ဘယ် Class က ဘယ် Class ကို သုံးနေတယ်ဆိုတာက Code တွေကို ဖွင့်မကြည့်ပဲ မသိနိုင်ပါဘူး။
10 |
11 | နမူနာအနေနဲ့ Leave ကို Apply လုပ်တဲ့ Operation တစ်ခုကို စဉ်းစားကြည့်ကြရအောင်။
12 |
13 | - Leave Application Table ထဲကို Record တစ်ကြောင်း Insert လုပ်ရပါမယ်
14 | - Leave Days Table ထဲကို သက်ဆိုင်ရာ ရက်အလိုက် Record တွေကို Insert လုပ်ရပါမယ်
15 | - Attendance Table ထဲကို Leave Status နဲ့ သက်ဆိုင်ရာ ရက်အလိုက် Record တွေကို Insert လုပ်ရပါမယ်
16 | - Message Queue ထဲကို Leave Application Operation ပြီးဆုံးကြောင်း Message တစ်ခုကို ဖြည့်စွက်ထားရပါမယ်
17 |
18 | အထက်ပါ Operation တွေကို အစီအစဉ်အလိုက် မှန်ကန်အောင် ရေးသားပေးရမှာ ဖြစ်ပါတယ်
19 |
20 |
21 |
22 | Client Operation အတွက် Dependency Object တွေကော Operation Step တွေပါ ရှုပ်ထွေးလာကြမှာ ဖြစ်ပါတယ်။ Sub System အတွက် ရိုးရှင်းတဲ့ Interface တွေကို ပြင်ဆင်ထားပြီး အတွင်းပိုင်းဖွဲစည်းတည်ဆောက်ပုံကို Client ဆီကနေ Hide လုပ်ထားမယ်။ ဤနည်းအားဖြင့် Sub System ရဲ့ Function တွေကို လွယ်ကူစွာဆောင်ရွက်နိုင်အောင်ပြင်ဆင်ပေးမယ် ဆိုတာကတော့ Facade Pattern ရဲ့ Approach ပဲ ဖြစ်ပါတယ်။
23 |
24 |
25 |
26 | Public Method တွေဟာ Object တစ်ခုရဲ့ အသုံးပြုနိုင်တဲ့ Interface တွေဖြစ်ကြမယ်ဆိုရင်၊ Facade တွေဟာ Sub System တစ်ခုရဲ့ အသုံးပြုနိုင်တဲ့ Interface တွေပဲဖြစ်ကြပါတယ်။ Facade Pattern ကို အသုံးပြုခြင်းအားဖြင့် အောက်ပါ အကျိုးတွေကို ရရှိနိုင်ပါတယ်။
27 |
28 | 1. Facade တွေဟာ Sub System Classes တွေကို Client တွေကနေ မတွေ့ရအောင် Hide လုပ်ပေးထားနိုင်တဲ့အတွက် အသုံးပြုသူဘက်ကကြည့်မယ်ဆိုရင် သုံးရတာလွယ်ကူစေပါတယ်။
29 | 2. Client နှင့် Sub System Classes တွေအကြားမှာရှိတဲ့ Coupling ကို လျော့ချပေးနိုင်တဲ့အတွက်၊ Client ဘက်မှာကော Sub System ဘက်မှာပါ ပြင်စရာရှိလို့ ပြင်ကြမယ်ဆိုရင်တောင် အပြန်အလှန် အကျိုးသက်ရောက်မှုကိုမရှိအောင် ဆောင်ရွက်ပေးနိုင်ပါတယ်။
30 | 3. Facade Pattern ဟာ Sub System Classes တွေကို Client ကနေ မသုံးရဘူးလို့ တားမြစ်ထားတာတော့ မဟုတ်ပါဘူး။ လိုအပ်ပါက အသုံးပြုနိုင်ပါတယ်။ Client Developer တွေအနေနဲ့ ရွေးချယ်ရမှာကတော့ Easy to Use (သုံးရတာလွယ်ကူတဲ့ ပုံစံ)လား၊ Generics ကျတဲ့ပုံစံနဲ့ သုံးချင်တာလားဆိုတဲ့ အချက်ပဲ ဖြစ်ပါမယ်။
31 |
32 | ### Implementation
33 |
34 |
--------------------------------------------------------------------------------
/p10_facade/system-diagram-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minlwin/design-patterns/d7f6b79cf6f9cc807c63609906b635f1175b2a3a/p10_facade/system-diagram-1.png
--------------------------------------------------------------------------------
/p10_facade/system-diagram-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minlwin/design-patterns/d7f6b79cf6f9cc807c63609906b635f1175b2a3a/p10_facade/system-diagram-2.png
--------------------------------------------------------------------------------
/p10_facade/system-diagram-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/minlwin/design-patterns/d7f6b79cf6f9cc807c63609906b635f1175b2a3a/p10_facade/system-diagram-3.png
--------------------------------------------------------------------------------