MVC Architecture (MVC ဖွဲ့စည်းပုံ)
IA (Internal Assessment) code ကို စီစဉ်တဲ့ နည်းလမ်း တစ်ခုပါ၊ စာမေးပွဲ ခေါင်းစဉ် မဟုတ်ပါဘူး: MVC (Model-View-Controller၊ app ကို Model၊ View၊ Controller ဆိုပြီး အပိုင်းသုံးပိုင်း ခွဲရေးတဲ့ ပုံစံ) ကို syllabus (IB သင်ရိုး) ထဲမှာ နာမည် တပ်ပြီး မဖော်ပြထားပါဘူး။ IA (IB သင်တန်းမှာ ကျောင်းသားတစ်ယောက်ချင်း ကိုယ်တိုင် တည်ဆောက်ရပြီး ကျောင်းက ဆရာက အမှတ်ပေးတဲ့ အပိုင်း) ကလည်း သတ်မှတ်ထားတဲ့ ဖွဲ့စည်းပုံ တစ်ခုခုကို မတောင်းပါဘူး။ MVC က user interface (UI၊ user နဲ့ program ကြားက မြင်ကွင်း၊ ဆိုလိုတာက user မြင်ရပြီး သုံးရတဲ့ screen တွေ) ပါတဲ့ program တစ်ခုကို စီစဉ်ရေးတဲ့ အသုံးများတဲ့ နည်းလမ်း တစ်ခုပါ။ ဒေတာ၊ screen တွေနဲ့ user ကို တုံ့ပြန်တဲ့ code တွေကို သီးခြား class (object တွေ ဖန်တီးဖို့ ပုံစံခွက်) တွေထဲ ခွဲထားလို့ code ကို test လုပ်ရတာ၊ ရှင်းပြရတာ၊ ပြင်ရတာ ပိုလွယ်ပါတယ်။ Modularisation (program ကို အလုပ်တစ်ခုစီ ရှိတဲ့ သီးခြား အပိုင်းငယ်တွေ ခွဲရေးခြင်း၊ IB သင်ရိုးရဲ့ B2.3.4) ရဲ့ အကျိုးကျေးဇူးတွေကို လက်တွေ့ အသုံးချထားတာပါ။ Python နဲ့ ရေးနေသလား။ ဒီစာမျက်နှာရဲ့ tkinter version က MVC with tkinter ပါ။
ခြုံငုံ မိတ်ဆက်
JavaFX Basics (JavaFX အခြေခံများ) ထဲက ဥပမာတွေမှာ ဒေတာ၊ ပြသတဲ့ အပိုင်းနဲ့ event handling (user က နှိပ်တာ ဒါမှမဟုတ် စာရိုက်တာကို program က တုံ့ပြန်အောင် လုပ်ခြင်း) ကို class တစ်ခုတည်းထဲမှာ ထည့်ရေးထားပါတယ်။ App အသေးလေး တစ်ခုအတွက်တော့ အဆင်ပြေပါတယ်။ ဒါပေမယ့် application ကြီးလာတဲ့အခါ ဒါတွေကို ရောထားရင် တခြား အပိုင်းတွေကို မထိခိုက်စေဘဲ အပိုင်း တစ်ခုကို ပြင်ဖို့ ဒါမှမဟုတ် test လုပ်ဖို့ ပိုခက်လာပါတယ်။ အဲဒီ တာဝန်တွေကို ခွဲထားရင် code က စနစ်တကျ ရှိနေပါတယ်။
Model-View-Controller (MVC) က user interface ပါတဲ့ program တွေအတွက် architecture (ဖွဲ့စည်းပုံ) တစ်ခုပါ: program ကို ဘယ်အပိုင်းတွေ ခွဲမလဲ၊ အဲဒီ အပိုင်းတွေ ဘယ်လို ပူးပေါင်း အလုပ်လုပ်မလဲ ဆိုတဲ့ အစီအစဉ် တစ်ခုပါ။ MVC ကို design pattern (ထပ်ကြုံရတဲ့ ဒီဇိုင်း ပြဿနာအတွက် ဖြေရှင်းပုံစံ) လို့လည်း မကြာခဏ ခေါ်ကြပါတယ်။ MVC က application ကို ကိုယ်ပိုင် အလုပ်စီ ရှိတဲ့ အပိုင်း သုံးပိုင်း ခွဲပေးပါတယ်။ MVC ကို နားလည်ရင် ဒီအရာတွေမှာ အထောက်အကူ ဖြစ်ပါလိမ့်မယ်:
- ဖတ်တဲ့သူ နားလည်လွယ်တဲ့ IA code ရေးဖို့
- ရှိပြီးသား feature (program ရဲ့ လုပ်ဆောင်ချက်) တွေ ပျက်သွားနိုင်ခြေ နည်းနည်းနဲ့ feature အသစ်တွေ ထည့်ဖို့
- ကိုယ့် IA product (ကိုယ်တိုင် တည်ဆောက်ရတဲ့ program) ရဲ့ ဖွဲ့စည်းပုံကို ရှင်းပြဖို့: Criterion C (System overview၊ IA အမှတ်ပေး စံနှုန်း C: system တစ်ခုလုံးကို ခြုံငုံ ဖော်ပြခြင်း) က အဓိက component (အစိတ်အပိုင်း) တွေနဲ့ သူတို့ အချင်းချင်း ဆက်သွယ် အလုပ်လုပ်ပုံကို ပြတဲ့ system model (system ရဲ့ ဖွဲ့စည်းပုံကို ပြတဲ့ ပုံ ဒါမှမဟုတ် ဖော်ပြချက်) တစ်ခုကို တောင်းပါတယ်။ Criterion D (Development၊ IA အမှတ်ပေး စံနှုန်း D: product ကို တည်ဆောက်ခြင်း) က product ရဲ့ ဖွဲ့စည်းပုံကို justify (ဘာကြောင့် ရွေးတာလဲ အကြောင်းပြချက်နဲ့ ပြ) လုပ်ဖို့ တောင်းပါတယ်
အစိတ်အပိုင်း သုံးခု
Model: ဒေတာ
Model က application ရဲ့ ဒေတာနဲ့ business logic (ဒေတာ လိုက်နာရမယ့် စည်းမျဉ်းတွေနဲ့ ဒေတာကို သုံးပြီး လုပ်တဲ့ တွက်ချက်မှုတွေ) ကို သိမ်းထားပါတယ်။ Model က user interface အကြောင်း ဘာမှ မသိပါဘူး: button တွေ၊ text field တွေ ဒါမှမဟုတ် window တွေ ရှိမှန်းတောင် မသိပါဘူး။
တာဝန်များ:
- ဒေတာ သိမ်းခြင်း: attribute (object ရဲ့ ဒေတာကို သိမ်းတဲ့ variable) တွေ၊ collection (ဒေတာအစု) တွေ
- ဒေတာက စည်းမျဉ်းတွေနဲ့ ကိုက်ညီမညီ စစ်ခြင်း (ဥပမာ grade (အမှတ်) က 0 ကနေ 100 အထိ ဖြစ်ရမယ်)
- တွက်ချက်မှုတွေနဲ့ operation (ဒေတာပေါ်မှာ လုပ်တဲ့ လုပ်ဆောင်ချက်) တွေ လုပ်ခြင်း
- ဒေတာကို file တွေထဲ ရေးခြင်း၊ file တွေကနေ ဖတ်ခြင်း (File I/O in Apps ကို ကြည့်ပါ)
ဥပမာ: နာမည်၊ grade နဲ့ validation (စည်းမျဉ်းကို ချိုးဖောက်တဲ့ ဒေတာကို လက်မခံအောင် စစ်တာ) ပါတဲ့ Student class တစ်ခု။
public class Student {
private String name;
private int grade;
public Student(String name, int grade) {
if (name == null || name.trim().isEmpty()) {
throw new IllegalArgumentException("Name cannot be empty");
}
if (grade < 0 || grade > 100) {
throw new IllegalArgumentException("Grade must be 0-100");
}
this.name = name;
this.grade = grade;
}
public String getName() { return name; }
public int getGrade() { return grade; }
public void setGrade(int grade) {
if (grade < 0 || grade > 100) {
throw new IllegalArgumentException("Grade must be 0-100");
}
this.grade = grade;
}
@Override
public String toString() {
return name + " (" + grade + ")";
}
}
throw new IllegalArgumentException(...) က constructor (object ဖန်တီးချိန် attribute တွေကို စတင် သတ်မှတ်ပေးတဲ့ method) ဒါမှမဟုတ် setter (private attribute ရဲ့ တန်ဖိုးကို ပြောင်းတဲ့ method) ကို ရပ်လိုက်ပြီး exception (program run နေစဉ် ဖြစ်တဲ့ အမှား၊ ဘာမှားသွားလဲ ဖော်ပြတဲ့ object တစ်ခု) ကို ခေါ်ခဲ့တဲ့ code ဆီ ပြန်ပို့ပါတယ်။ အောက်က Controller က အဲဒီ exception ကို try/catch နဲ့ ဖမ်းပြီး message ကို user ကို ပြပါတယ်။ Syllabus မှာ try၊ catch နဲ့ finally ကို ဖော်ပြထားပေမယ့် throw ကို မဖော်ပြထားလို့ ကိုယ်ပိုင် exception တွေ throw လုပ်တာကို IA အတွက် tool တစ်ခုအဖြစ် သဘောထားပါ။
Collection Model (ဒေတာအစုကို စီမံတဲ့ Model)
IA project အများအပြားမှာ model object (class တစ်ခုကနေ ဖန်တီးထားတဲ့ instance) တွေရဲ့ collection ကို စီမံတဲ့ class တစ်ခုလည်း လိုပါတယ်: ထည့်ခြင်း၊ ဖယ်ခြင်း၊ ရှာခြင်းနဲ့ စီခြင်း။
import java.util.ArrayList;
public class StudentList {
private ArrayList<Student> students;
public StudentList() {
students = new ArrayList<>();
}
public void addStudent(Student s) {
students.add(s);
}
public boolean removeByName(String name) {
for (int i = 0; i < students.size(); i++) {
if (students.get(i).getName().equals(name)) {
students.remove(i);
return true;
}
}
return false;
}
public Student findByName(String name) {
for (int i = 0; i < students.size(); i++) {
if (students.get(i).getName().equals(name)) {
return students.get(i);
}
}
return null;
}
public ArrayList<Student> getAll() {
return students;
}
public int size() {
return students.size();
}
}
ဒီ design မှာ Model က JavaFX ရဲ့ screen class တွေကို ဘာမှ import (တခြားနေရာက code ကို ယူသုံးမယ်လို့ ကြေညာခြင်း) မလုပ်ပါဘူး။ ကိုယ့် model class က control (button၊ text field စတဲ့ user သုံးတဲ့ အစိတ်အပိုင်း)၊ layout (control တွေကို screen ပေါ်မှာ စီစဉ်ထားပုံ)၊ window ဒါမှမဟုတ် alert (message ပြတဲ့ pop-up window) (javafx.scene ဒါမှမဟုတ် javafx.stage ထဲက ဘာမဆို) ကို import လုပ်နေရင် တစ်ခုခု နေရာမှားနေပါပြီ။ JavaFX မှာ screen နဲ့ ဘာမှ မဆိုင်တဲ့ class တွေလည်း ရှိပါတယ်။ ဥပမာ ObservableList (ကိုယ့်ထဲက content ပြောင်းသွားတဲ့အခါ screen ပေါ်က table ကို အသိပေးတဲ့ list) နဲ့ FXCollections (ObservableList ကို ဖန်တီးပေးတဲ့ class) ပါ။ နှစ်ခုလုံး javafx.collections ထဲမှာ ရှိပါတယ်။ JavaFX Cookbook ရဲ့ Tables recipe (လုပ်နည်း) တွေမှာ သူတို့ကို သုံးထားပါတယ်။ တချို့ project တွေက Model ရဲ့ ဒေတာကို ObservableList တစ်ခုထဲမှာ သိမ်းထားပါတယ်။ ဒါက တမင် ရွေးထားတဲ့ ရွေးချယ်မှုပါ: Model က control တွေ၊ window တွေကို ဆက်ပြီး မဖန်တီးပါဘူး၊ window မဖွင့်ဘဲနဲ့လည်း test လုပ်လို့ ရနေဆဲပါ။
View: ပြသတဲ့ အပိုင်း
View က user မြင်ရပြီး ထိတွေ့ သုံးရတဲ့ အပိုင်းပါ။ JavaFX မှာဆိုရင် control တွေ (button တွေ၊ text field တွေ၊ label တွေ) ပါတဲ့ window နဲ့ အဲဒီ control တွေကို စီစဉ်ပေးတဲ့ layout တွေပါ။ View ကို တတ်နိုင်သမျှ ရိုးရှင်းအောင် ထားပါ: View က ဒေတာကို ပြပြီး user ရဲ့ လုပ်ဆောင်ချက်တွေကို Controller ဆီ လွှဲပေးပါတယ်၊ ဒါပေမယ့် အဲဒီ လုပ်ဆောင်ချက်တွေနဲ့ ဘာလုပ်မလဲ ဆိုတာကို မဆုံးဖြတ်ပါဘူး။ ဒေတာနဲ့ ဆိုင်တဲ့ စည်းမျဉ်းတွေက Model ထဲမှာ ရှိရပါမယ်။
တာဝန်များ:
- UI control တွေကို ဖန်တီးပြီး စီစဉ်ခြင်း
- Controller ပေးတဲ့ ဒေတာကို ပြခြင်း
- User ရဲ့ လုပ်ဆောင်ချက်တွေ (button နှိပ်တာ၊ စာရိုက်ထည့်တာ) ကို Controller ဆီ အသိပေးခြင်း
Controller: ကြားက ညှိပေးတဲ့ အပိုင်း
Controller က Model နဲ့ View ကြားက ညှိပေးသူ (coordinator) ပါ။ User ရဲ့ လုပ်ဆောင်ချက်တွေကို ကိုင်တွယ်ပြီး Model ကို update လုပ်ကာ View ကို ဘာပြရမလဲ ပြောပါတယ်။
တာဝန်များ:
- View ကနေ လာတဲ့ user ရဲ့ လုပ်ဆောင်ချက်တွေကို စောင့်နားထောင်ခြင်း
- ဒေတာကို ထည့်ဖို့၊ ဖယ်ဖို့ ဒါမှမဟုတ် ပြင်ဖို့ Model ရဲ့ method (သီးခြား အလုပ်တစ်ခု လုပ်ပေးတဲ့ code အပိုင်း) တွေကို ခေါ်ခြင်း
- View က Model ရဲ့ လက်ရှိ ဒေတာကို ပြအောင် View ကို update လုပ်ခြင်း
- Error တွေကို ဖမ်းပြီး user ကို ရှင်းလင်းတဲ့ message ပြခြင်း
အစိတ်အပိုင်းတွေ ဆက်သွယ် အလုပ်လုပ်ပုံ
flowchart LR
V["View<br>(UI)"] -- "user action" --> C["Controller<br>(coordinator)"]
C -- "update data" --> M["Model<br>(data and rules)"]
M -- "return data" --> C
C -- "update display" --> V
ပုံထဲက စာတွေရဲ့ အဓိပ္ပာယ်: View (UI) က user action (user ရဲ့ လုပ်ဆောင်ချက်) ကို Controller (coordinator၊ ညှိပေးသူ) ဆီ ပို့ပါတယ်။ Controller က Model (data and rules၊ ဒေတာနဲ့ စည်းမျဉ်းများ) ထဲက ဒေတာကို update data (ဒေတာကို update လုပ်) ပြီး Model က return data (ဒေတာကို ပြန်ပေး) ပါတယ်။ ပြီးရင် Controller က View ကို update display (ပြတာကို update လုပ်) ပါတယ်။
- User က View ထဲက button တစ်ခုကို နှိပ်ပါတယ်
- Controller က event (ဖြစ်ရပ်) ကို ကိုင်တွယ်ပါတယ်: View ကနေ input (program ထဲ ထည့်ပေးတဲ့ ဒေတာ) ကို ဖတ်ပြီး သုံးလို့ ရမရ စစ်ပါတယ် (ဥပမာ grade က ဂဏန်း ဟုတ်မဟုတ်)
- Controller က Model ကို update လုပ်ပါတယ်: ကျောင်းသား တစ်ယောက် ထည့်တာ၊ grade ပြောင်းတာ စသဖြင့် လုပ်ပါတယ်။ Model က ကိုယ့်စည်းမျဉ်းတွေကို ကိုယ်တိုင် စစ်ပါတယ် (grade က 0 ကနေ 100 အထိ)
- Controller က View ကို update လုပ်ပါတယ်: display ကို refresh (အသစ် ပြန်ပြ) လုပ်ပြီး message ပြပါတယ်
ဒီ design မှာ Model နဲ့ View က တိုက်ရိုက် ဆက်သွယ်ကြတာ မရှိပါဘူး။ ဆက်သွယ်မှု အားလုံးက Controller ကနေ ဖြတ်သွားပါတယ်။
MVC ရဲ့ ပုံစံ အမျိုးမျိုး
MVC မှာ ပုံစံ အမျိုးမျိုး ရှိပါတယ်။ ဒီစာမျက်နှာက ပုံစံမှာ View က passive (ကိုယ်တိုင် ဘာမှ မလုပ်ဘဲ ပေးတာကိုပဲ ပြတဲ့) ဖြစ်ပါတယ်: View က Model ကို မဖတ်ပါဘူး၊ Controller က ဒေတာကို View ထဲ ကူးထည့်ပေးပါတယ်။ တခြား ပုံစံတွေမှာတော့ View က Model ကနေ ဒေတာကို ကိုယ်တိုင် ဖတ်တာ ဒါမှမဟုတ် Model က ကိုယ့်ဒေတာ ပြောင်းသွားတဲ့အခါ View ကို အသိပေးတာ ရှိပါတယ်။ ဒုတိယ နည်းလမ်းက observer pattern (state ပြောင်းရင် အလိုအလျောက် အသိပေးတဲ့ ပုံစံ) ကို သုံးပါတယ်။ Observer pattern က HL (Higher Level: IB သင်တန်းမှာ ပိုနက်နက်ရှိုင်းရှိုင်း လေ့လာရတဲ့ အဆင့်) syllabus ထဲက design pattern တွေထဲက တစ်ခုပါ (B3.2.5): object တစ်ခုက တခြား object တွေရဲ့ စာရင်းကို သိမ်းထားပြီး တစ်ခုခု ပြောင်းသွားတဲ့အခါ အဲဒီ object တစ်ခုစီကို အသိပေးပါတယ်။ အလုပ်ကို နည်းနည်းစီ ကွဲပြားတဲ့ ပုံစံနဲ့ ခွဲတဲ့ ဆက်စပ် design တွေမှာလည်း ကိုယ်ပိုင် နာမည်တွေ ရှိပါတယ်။ ဥပမာ MVP (Model-View-Presenter) နဲ့ MVVM (Model-View-ViewModel) ပါ။ သူတို့ အားလုံး တူတာက Model က screen တွေအပေါ် မမှီခိုတာပါ: screen တွေ မပါဘဲ Model က အလုပ်လုပ်ပါတယ်။
Screen တွေကို FXML (screen တစ်ခုရဲ့ layout ကို ဖော်ပြတဲ့ file format တစ်ခု၊ FXML and Controllers ကို ကြည့်ပါ) နဲ့ တည်ဆောက်တဲ့အခါ FXML file က View ဖြစ်ပါတယ်။ အဲဒီ file က သူ့ controller class ကို fx:controller setting မှာ နာမည် ဖော်ပြထားပါတယ်။ အဲဒီ Java class က screen ရဲ့ event တွေကို ကိုင်တွယ်ပြီး Controller ရဲ့ အခန်းကဏ္ဍကို ယူပါတယ်။
MVC ကို လက်တွေ့ သုံးခြင်း: Student Manager
ဒါက MVC ရဲ့ ဥပမာ အပြည့်အစုံ တစ်ခုပါ: ကျောင်းသား စာရင်းကို စီမံတဲ့ program တစ်ခုပါ။ Model class တွေကို အပေါ်မှာ ပြခဲ့ပြီးပါပြီ။ အောက်မှာ View၊ Controller နဲ့ အဲဒီ အပိုင်းတွေကို ချိတ်ဆက်ပေးတဲ့ Application class ကို ပြထားပါတယ်။
View
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
public class StudentView {
private TextField nameField;
private TextField gradeField;
private Button addBtn;
private Button removeBtn;
private Button searchBtn;
private TextArea display;
private Label status;
// Creates the controls, so the Controller can use them straight away
public StudentView() {
nameField = new TextField();
nameField.setPromptText("Student name");
gradeField = new TextField();
gradeField.setPromptText("Grade (0-100)");
addBtn = new Button("Add");
removeBtn = new Button("Remove");
searchBtn = new Button("Search");
display = new TextArea();
display.setEditable(false);
display.setPrefRowCount(12);
status = new Label("Ready");
}
// Arranges the controls in a layout and returns the finished scene
public Scene createScene() {
HBox buttons = new HBox(10, addBtn, removeBtn, searchBtn);
VBox form = new VBox(10, nameField, gradeField, buttons, status);
form.setPadding(new Insets(10));
BorderPane root = new BorderPane();
root.setCenter(display);
root.setBottom(form);
root.setPadding(new Insets(10));
return new Scene(root, 450, 450);
}
// Getters for the Controller to access controls
public TextField getNameField() { return nameField; }
public TextField getGradeField() { return gradeField; }
public Button getAddBtn() { return addBtn; }
public Button getRemoveBtn() { return removeBtn; }
public Button getSearchBtn() { return searchBtn; }
public TextArea getDisplay() { return display; }
public Label getStatus() { return status; }
}
သတိပြုကြည့်ပါ: View က control တွေကို ဖန်တီးပြီး getter (private attribute ရဲ့ တန်ဖိုးကို ပြန်ပေးတဲ့ method) တွေ ပေးထားပေမယ့် event handler (button နှိပ်တာလို event ဖြစ်တဲ့အခါ run တဲ့ code) မရှိပါဘူး၊ logic (ဘာလုပ်မလဲ ဆုံးဖြတ်တဲ့ code) လည်း မရှိပါဘူး။ Button ကို နှိပ်တဲ့အခါ ဘာဖြစ်မလဲ ဆိုတာ View က မသိပါဘူး။ View ရဲ့ constructor က control တွေကို ဖန်တီးလို့ View object ရှိလာတာနဲ့ control တွေလည်း ရှိလာပါတယ်: ဒါကြောင့် createScene() က control တွေကို screen ပေါ်မှာ မစီစဉ်ခင်ကတည်းက Controller က သူ့ handler တွေကို ချိတ်လို့ ရပါတယ်။
Controller
Handler တွေက JavaFX Basics မှာလို lambda (နာမည် မပါတဲ့ method အတိုလေးတွေ) တွေပါ။ Lambda တစ်ခုစီက နာမည်ပါတဲ့ method တစ်ခုကို ခေါ်ပါတယ်၊ ဒါကြောင့် event handling ကို ဖတ်ရလွယ်ပါတယ်။
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
public class StudentController {
private StudentList model;
private StudentView view;
public StudentController(StudentList model, StudentView view) {
this.model = model;
this.view = view;
attachHandlers();
refreshDisplay();
}
private void attachHandlers() {
view.getAddBtn().setOnAction(event -> handleAdd());
view.getRemoveBtn().setOnAction(event -> handleRemove());
view.getSearchBtn().setOnAction(event -> handleSearch());
view.getNameField().setOnAction(event -> handleAdd());
}
private void handleAdd() {
String name = view.getNameField().getText().trim();
String gradeText = view.getGradeField().getText().trim();
if (name.isEmpty()) {
view.getStatus().setText("Error: Name cannot be empty.");
return;
}
int grade;
try {
grade = Integer.parseInt(gradeText);
} catch (NumberFormatException e) {
view.getStatus().setText("Error: Grade must be a number.");
return;
}
try {
Student s = new Student(name, grade);
model.addStudent(s);
view.getStatus().setText("Added: " + s);
view.getNameField().clear();
view.getGradeField().clear();
refreshDisplay();
} catch (IllegalArgumentException e) {
view.getStatus().setText("Error: " + e.getMessage());
}
}
private void handleRemove() {
String name = view.getNameField().getText().trim();
if (name.isEmpty()) {
view.getStatus().setText("Error: Enter a name to remove.");
return;
}
Alert confirm = new Alert(Alert.AlertType.CONFIRMATION);
confirm.setTitle("Confirm");
confirm.setHeaderText(null);
confirm.setContentText("Remove " + name + "?");
if (confirm.showAndWait().get() == ButtonType.OK) {
if (model.removeByName(name)) {
view.getStatus().setText("Removed: " + name);
view.getNameField().clear();
refreshDisplay();
} else {
view.getStatus().setText("Not found: " + name);
}
}
}
private void handleSearch() {
String name = view.getNameField().getText().trim();
if (name.isEmpty()) {
view.getStatus().setText("Error: Enter a name to search.");
return;
}
Student found = model.findByName(name);
if (found != null) {
view.getStatus().setText("Found: " + found);
} else {
view.getStatus().setText("Not found: " + name);
}
}
private void refreshDisplay() {
view.getDisplay().clear();
for (int i = 0; i < model.getAll().size(); i++) {
view.getDisplay().appendText(
(i + 1) + ". " + model.getAll().get(i) + "\n"
);
}
}
}
Application Class (အပိုင်းတွေကို ချိတ်ဆက်ခြင်း)
import javafx.application.Application;
import javafx.stage.Stage;
public class StudentApp extends Application {
@Override
public void start(Stage stage) {
StudentList model = new StudentList();
StudentView view = new StudentView();
StudentController controller = new StudentController(model, view);
stage.setTitle("Student Manager");
stage.setScene(view.createScene());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Application class က သေးသေးလေးပဲ ရှိပါတယ်။ Model၊ View နဲ့ Controller ကို ဖန်တီးပြီး ချိတ်ဆက်ကာ window ကို ပြပါတယ်။ Application ရဲ့ ကျန်တဲ့ အလုပ်တွေက အဲဒီ component သုံးခုထဲမှာ ဖြစ်ပါတယ်။ အစဉ်က အရေးကြီးပါတယ်: Controller က ဖန်တီးလိုက်တာနဲ့ Model ကော View ကော နှစ်ခုလုံးကို ချက်ချင်း သုံးလို့ Model နဲ့ View ကို အရင် ဖန်တီးပါတယ်။
MVC က IA အတွက် ဘာကြောင့် အရေးကြီးသလဲ
ကိုယ့် ဖွဲ့စည်းပုံကို ရှင်းပြခြင်း
MVC က ကိုယ်ရွေးလို့ရတဲ့ ဖွဲ့စည်းပုံ တစ်ခုပါ၊ IA က မဖြစ်မနေ မတောင်းပါဘူး။ သုံးမယ်ဆိုရင် criterion (အမှတ်ပေး စံနှုန်း) နှစ်ခုမှာ ပြောစရာ ရှင်းလင်းတဲ့ အချက်တွေ ရပါတယ်:
- Criterion C (System overview) က “the key components, their relationships, the rules governing their interaction” (အဓိက component တွေ၊ သူတို့ကြားက ဆက်နွယ်မှုတွေ၊ သူတို့ ဆက်သွယ် အလုပ်လုပ်ပုံကို ထိန်းတဲ့ စည်းမျဉ်းတွေ) ပါတဲ့ system model တစ်ခုကို တောင်းပါတယ်။ ကိုယ့် Model၊ View နဲ့ Controller class တွေကို ဆွဲပြပြီး သူတို့ကြား ချိတ်ဆက်မှုတွေကို မြှားတွေနဲ့ ပြထားတဲ့ ပုံက အဲဒီ component တွေနဲ့ ဆက်နွယ်မှုတွေကို ပြပါတယ်။
- Criterion D (Development) က “justify the structure of the product, why the structure is appropriate” (product ရဲ့ ဖွဲ့စည်းပုံကို အကြောင်းပြချက်နဲ့ ပြပါ၊ ဘာကြောင့် အဲဒီ ဖွဲ့စည်းပုံက သင့်တော်လဲ) ကို တောင်းပါတယ်။ MVC က ကိုယ့် code ကို modular design (အလုပ်တစ်ခုစီ ရှိတဲ့ သီးခြား အပိုင်းတွေ) ဖြစ်စေပါတယ်။ ဒါက ကိုယ့် product ကို ဘယ်လို အထောက်အကူ ဖြစ်လဲဆိုတာ ရှင်းပြနိုင်ပါတယ်၊ ဥပမာ:
- Model class တွေကို GUI (graphical user interface၊ window တွေ၊ button တွေ၊ text box တွေ) မပါဘဲ test လုပ်လို့ ရပါတယ်
- Model ကို မပြင်ဘဲ screen ရဲ့ ပုံစံကို ပြောင်းလို့ ရပါတယ်
- ဒေတာ class တွေကို မပြင်ဘဲ Controller ကို ပြောင်းလို့ ရပါတယ်
Feature အသစ် ထည့်ရတာ ပိုလွယ်ပါတယ်
MVC နဲ့ဆိုရင် feature အသစ် တစ်ခုက အပိုင်း သုံးပိုင်းကို အလှည့်ကျ ထိလေ့ ရှိပါတယ်။ ဥပမာ အတန်းရဲ့ ပျမ်းမျှ grade ကို ပြချင်ရင်:
- Model: method ကို ထည့်ပါ (ဥပမာ
StudentListထဲမှာaverageGrade()) - View: control ကို ထည့်ပါ (ဥပမာ ပျမ်းမျှကို ပြဖို့ label တစ်ခု)
- Controller: method ကို ခေါ်ပြီး ရလဒ်ကို ပြပါ (ဥပမာ
refreshDisplay()ရဲ့ အဆုံးမှာ)
ဒီလို ခွဲမထားရင် feature တစ်ခု ထည့်ဖို့ ဒေတာ၊ ပြသတဲ့ အပိုင်းနဲ့ event handling တွေ ရောနေတဲ့ နေရာတွေကို ရှည်လျားတဲ့ class တစ်ခုထဲမှာ လိုက်ရှာရလေ့ ရှိပါတယ်။
Debugging (program ထဲက အမှားကို ရှာပြီး ပြင်ခြင်း) ပိုလွယ်ပါတယ်
တစ်ခုခု မှားသွားတဲ့အခါ:
- ဒေတာ မှားပြီး သိမ်းမိနေသလား။ Model ကို စစ်ပါ
- Screen ရဲ့ layout မှားနေသလား။ View ကို စစ်ပါ
- Button က မှားတာကို လုပ်နေသလား၊ ဒါမှမဟုတ် display က နောက်ဆုံး ဒေတာကို မပြဘူးလား။ Controller ကို စစ်ပါ
MVC မှာ အဖြစ်များတဲ့ အမှားများ
View ထဲမှာ logic ထည့်ခြင်း။ ကိုယ့် View class ထဲမှာ user ရဲ့ input နဲ့ ဘာလုပ်မလဲ ဆုံးဖြတ်တဲ့ if statement (code ထဲက ညွှန်ကြားချက်) တွေ ရှိရင် ရွှေ့ပါ: ဒေတာနဲ့ ဆိုင်တဲ့ စည်းမျဉ်းတွေက Model ထဲ၊ နှိပ်ပြီးနောက် ဘာဖြစ်မလဲ ဆိုတဲ့ ဆုံးဖြတ်ချက်တွေက Controller ထဲမှာ ရှိရပါမယ်။
Model ထဲမှာ screen code ထည့်ခြင်း။ ကိုယ့် Model က control တွေ၊ alert တွေ ဒါမှမဟုတ် window တွေကို ဖန်တီးနေရင် View ရဲ့ အလုပ်ကို လုပ်နေတာပါ။ Model ကို main (program စ run တဲ့ method) method ကနေ test လုပ်နိုင်အောင် window တစ်ခုမှ မဖွင့်ဘဲ အလုပ်လုပ်ရပါမယ်။
Controller ကို ကျော်ခြင်း။ တချို့ ကျောင်းသားတွေက Model method တွေကို တိုက်ရိုက် ခေါ်တဲ့ handler တွေကို View ထဲမှာ ရေးကြပါတယ်။ App အသေးလေးတွေမှာ အလုပ်လုပ်ပေမယ့် app ကြီးလာတာနဲ့အမျှ code ကို ပြောင်းရတာ၊ ပြင်ရတာ ခက်လာပါတယ်။ ကြားမှာ Controller ရှိရင် View နဲ့ Model က တစ်ခုနဲ့ တစ်ခု မမှီခိုတော့ပါဘူး။
MVC စစ်ဆေးစရာ စာရင်း
ဒီစာမျက်နှာက design ကို ကိုယ့် IA မှာ သုံးမယ်ဆိုရင် အပိုင်း သုံးပိုင်း ခွဲထားဆဲ ဟုတ်မဟုတ်ကို ဒီ စစ်ဆေးချက်တွေက ပြပါတယ်။ ဒီ စစ်ဆေးချက်တွေက View က Model ကို ဘယ်တော့မှ မဖတ်တဲ့ ဒီစာမျက်နှာရဲ့ MVC ပုံစံအတွက်ပါ။ တခြား ပုံစံတွေ (MVC ရဲ့ ပုံစံ အမျိုးမျိုး ကို ကြည့်ပါ) က မတူတဲ့ ပုံစံနဲ့ အလုပ်လုပ်ပါတယ်။
| စည်းမျဉ်း | စစ်ပြီးပြီ |
|---|---|
Model class တွေက JavaFX screen class တွေကို import မလုပ်ပါဘူး: control၊ layout၊ window ဒါမှမဟုတ် alert မပါပါဘူး (ObservableList လို screen နဲ့ မဆိုင်တဲ့ class တွေကိုတော့ တမင် ရွေးသုံးနိုင်ပါတယ်) | |
| View က control တွေကို ဖန်တီးပြီး စီစဉ်ပေမယ့် ဒေတာနဲ့ ပတ်သက်ပြီး ဘာမှ မဆုံးဖြတ်ပါဘူး | |
| Controller က user ရဲ့ လုပ်ဆောင်ချက် တိုင်းကို ကိုင်တွယ်ပါတယ် | |
| GUI ကို မဖွင့်ဘဲ Model ကို test လုပ်လို့ ရပါတယ် | |
| Class တစ်ခုစီမှာ ရှင်းလင်းတဲ့ တာဝန် တစ်ခုတည်း ရှိပါတယ် | |
| Application class က အပိုင်း သုံးပိုင်းကို ဖန်တီးပြီး ချိတ်ဆက်ကာ window ကို ပြတာပဲ လုပ်ပါတယ် |
Quick Check (အမြန် စစ်ဆေးမေးခွန်း)
Q1. MVC မှာ ဘယ် component က application ရဲ့ ဒေတာနဲ့ business logic ကို သိမ်းထားသလဲ။
Q2. User ရဲ့ လုပ်ဆောင်ချက်တွေကို ကိုင်တွယ်ပြီး ဒေတာနဲ့ ပြသတဲ့ အပိုင်းကြားမှာ ညှိပေးတာ ဘယ် component လဲ။
Q3. ကိုယ့် Student model class ထဲမှာ import javafx.scene.control.Alert; ပါပြီး grade က သတ်မှတ်ထားတဲ့ အပိုင်းအခြား အပြင် ရောက်နေတဲ့အခါ alert တစ်ခု ပြပါတယ်။ ဒါက ဘာကို ပြနေသလဲ။
Q4. Student Manager မှာ user က နာမည်နဲ့ grade ကို ရိုက်ထည့်ပြီး Add ကို နှိပ်ပါတယ်။ နောက်မှာ ဘယ်လို အစဉ်နဲ့ ဖြစ်သွားသလဲ။
Q5. ဒေတာနဲ့ သူ့စည်းမျဉ်းတွေကို View နဲ့ ခွဲပြီး Model ထဲမှာ ထားတာရဲ့ အဓိက အားသာချက်က ဘာလဲ။
Code Completion (code ကွက်လပ် ဖြည့်ခြင်း)
ဒီ Application class ရဲ့ ပျောက်နေတဲ့ အပိုင်းတွေကို ဖြည့်ပါ။ BookList၊ BookView နဲ့ BookController က Student Manager ရဲ့ Model၊ View နဲ့ Controller နဲ့ design တူပါတယ်။
ကွက်လပ် ဖြည့်ပါ: Model၊ View နဲ့ Controller ကို ဖန်တီးပြီး ချိတ်ဆက်ပေးတဲ့ Application class ကို ဖြည့်ပါ။
public class BookApp extends Application {
@Override
public void start(Stage stage) {
BookList model = new ;
BookView view = new BookView();
BookController ctrl = new BookController();
stage.setTitle("Book Manager");
stage.setScene(view.);
stage.;
}
public static void main(String[] args) {
;
}
} Spot the Error (အမှား ရှာခြင်း)
ဒီ Controller method က ကျောင်းသား တစ်ယောက်ကို ထည့်ပါတယ်။ တိုတိုလေး ဖြစ်အောင် input စစ်ဆေးချက်တွေကို ချန်ထားပါတယ်။ ဒီ version ထဲက View မှာ သူ့ layout ကို ပြန်ပေးတဲ့ getRoot() method လည်း ပါပါတယ်။
အမှား ရှာပါ: ဒီ Controller method က run ပါတယ်၊ ဒါပေမယ့် line တစ်ကြောင်းက View ရဲ့ အလုပ်ကို လုပ်ပြီး MVC ရဲ့ ခွဲခြားမှုကို ချိုးဖောက်နေပါတယ်။
Line 6 အတွက် မှန်ကန်တဲ့ ပြင်နည်းကို ရွေးပါ:
Predict the Output (output ကို ကြိုခန့်မှန်းခြင်း)
ကြိုခန့်မှန်းပါ: start() ရဲ့ ဒီ version မှာ Controller ကို မဖန်တီးခင် Model ထဲကို ကျောင်းသား နှစ်ယောက် ထည့်ထားပါတယ်။ Window ပွင့်လာတဲ့အခါ display TextArea ထဲက ဒုတိယ line က ဘာလဲ။
// In StudentApp's start():
StudentList model = new StudentList();
model.addStudent(new Student("Ana", 91));
model.addStudent(new Student("Ben", 78));
StudentView view = new StudentView();
StudentController controller = new StudentController(model, view);
// In StudentController:
public StudentController(StudentList model, StudentView view) {
this.model = model;
this.view = view;
attachHandlers();
refreshDisplay();
}
private void refreshDisplay() {
view.getDisplay().clear();
for (int i = 0; i < model.getAll().size(); i++) {
view.getDisplay().appendText(
(i + 1) + ". " + model.getAll().get(i) + "\n"
);
}
} Practice Exercises (လေ့ကျင့်ခန်းများ)
(4 marks) စတာတွေက မေးခွန်း တစ်ခုစီအတွက် ရနိုင်တဲ့ အမှတ်ပါ။ IB စာမေးပွဲ မေးခွန်းတွေမှာ အမှတ်ကို ဒီလို ပြလေ့ ရှိပါတယ်။
Core (အခြေခံ အဆင့်)
- Component တွေကို ခွဲခြားခြင်း (4 marks): ဂီတ ကျောင်းသား တစ်ယောက်ရဲ့ လေ့ကျင့်မှု မှတ်တမ်း app မှာ အောက်က class လေးခု ပါပါတယ်။ Class တစ်ခုစီက Model၊ View ဒါမှမဟုတ် Controller ထဲက ဘယ်အပိုင်းမှာ ပါလဲ Identify (ဖြစ်နိုင်တဲ့ အဖြေတွေထဲက ရွေးပြီး ဖော်ပြပါ)။
Sessionက တူရိယာ တစ်ခု၊ ရက်စွဲ တစ်ခုနဲ့ မိနစ် အရေအတွက်ကို သိမ်းပြီး အနုတ် မိနစ် အရေအတွက်ကို လက်မခံပါဘူး။PracticeLogကArrayList<Session>တစ်ခုကို သိမ်းထားပြီး လေ့ကျင့်ခဲ့တဲ့ မိနစ် စုစုပေါင်းကို တွက်ပါတယ်။PracticeWindowက text box တွေ၊ Save button တစ်ခုနဲ့ အရင် လေ့ကျင့်ခဲ့တဲ့ session တွေရဲ့ list ကို ဖန်တီးပြီး control တစ်ခုစီအတွက် getter တစ်ခုစီ ပါပါတယ်။PracticeManagerက Save button မှာ handler တစ်ခု ချိတ်ပေးပါတယ်။ အဲဒီ handler က text box တွေကို ဖတ်ပြီးPracticeLogထဲSessionအသစ် တစ်ခု ထည့်ကာ screen ပေါ်က list ကို update လုပ်ပါတယ်။
- စည်းမျဉ်း ချိုးဖောက်မှုကို ပြင်ခြင်း (4 marks): ကျောင်းသား တစ်ယောက်ရဲ့
ProductViewclass ထဲက Save button ရဲ့ handler ထဲမှာ ဒီ code ပါပါတယ်:if (price < 0) { status.setText("Invalid price"); return; }။ ဈေးနှုန်း အနုတ် မဖြစ်ရဘူးလို့ စစ်တဲ့ အပိုင်းက ဘယ်မှာ ရှိသင့်လဲ၊ message ပြဖို့ ဆုံးဖြတ်ချက်က ဘယ်မှာ ရှိသင့်လဲ၊ တစ်ခုစီက ဘာကြောင့် အဲဒီမှာ ရှိသင့်လဲ ဆိုတာကို Explain (ရှင်းပြပါ)။ Code ရေးဖို့ မလိုပါဘူး။
Extension (တိုးချဲ့ အဆင့်)
- Calculator တစ်ခု တည်ဆောက်ခြင်း (6 marks): MVC ကို သုံးပြီး ရိုးရှင်းတဲ့ calculator (ဂဏန်း တွက်စက်) တစ်ခုကို Construct (ကိုယ်တိုင် တည်ဆောက်ပါ):
- Model: ဂဏန်း နှစ်ခုစီကို လက်ခံပြီး အဖြေကို
resultfield (object ထဲက အချက်အလက် အကွက်) ထဲ သိမ်းတဲ့add()၊subtract()၊multiply()နဲ့divide()method တွေနဲ့getResult()method ပါတဲ့Calculatorclass တစ်ခု။divide()က စားကိန်း 0 ကို လက်မခံပါဘူး။ - View: ဂဏန်းတွေအတွက် text field နှစ်ခု၊ operation button လေးခုနဲ့ ရလဒ် ပြတဲ့ label တစ်ခု။
- Controller: ဂဏန်း နှစ်ခုကို ဖတ်ပြီး ကိုက်ညီတဲ့ Model method ကို ခေါ်ကာ ရလဒ်ကို ပြပါတယ်။ ဂဏန်း မဟုတ်တဲ့ စာသား ဒါမှမဟုတ် 0 နဲ့ စားတာ ဖြစ်ရင် ရလဒ်အစား message တစ်ခု ပြပါ။
- Model: ဂဏန်း နှစ်ခုစီကို လက်ခံပြီး အဖြေကို
- Sorting (အစဉ်တကျ စီခြင်း) ထည့်ခြင်း (6 marks): Student Manager အတွက် sorting feature တစ်ခုကို Construct လုပ်ပါ: View ထဲမှာ “Sort by Grade” button တစ်ခု၊
StudentListmodel ထဲမှာ selection sort (အငယ်ဆုံးကို ရှာပြီး နေရာချ စီခြင်း) ကို သုံးပြီး ကျောင်းသားတွေကို grade အမြင့်ဆုံးကနေ အနိမ့်ဆုံးအထိ စီပေးတဲ့sortByGrade()method တစ်ခုနဲ့ Controller ထဲမှာ list ကို စီပြီး display ကို refresh လုပ်ပေးတဲ့ handler တစ်ခု။
Challenge (စိန်ခေါ်မှု အဆင့်)
-
ကလပ် အစီအစဉ်များ App (8 marks):
Memberobject တွေရဲ့ list တစ်ခုနဲ့Eventobject (ကလပ် အစီအစဉ်) တွေရဲ့ list တစ်ခုကို သိမ်းထားတဲ့ ကျောင်း ကလပ် တစ်ခုအတွက် MVC application တစ်ခုကို Construct လုပ်ပါ။ Event တစ်ခုစီမှာ အဲဒီ event ကို တက်ရောက်မယ့် member တွေရဲ့ ကိုယ်ပိုင် list ရှိပါတယ်။ User က member တစ်ယောက် ထည့်တာ၊ event တစ်ခု ထည့်တာ၊ member တစ်ယောက်ကို event တစ်ခုအတွက် စာရင်းသွင်းတာ (တစ်ကြိမ်ပဲ) နဲ့ event တစ်ခုကို ဘယ်သူတွေ တက်ရောက်မလဲ ပြတာတွေ လုပ်နိုင်ရပါမယ်။ Model class တွေ၊ View ရဲ့ control တွေနဲ့ Controller ရဲ့ method တွေကို စာရွက်ပေါ်မှာ အရင် စီစဉ်ပြီးမှ implement (တကယ် အလုပ်လုပ်အောင် code ရေး) လုပ်ပါ။ -
ဖွဲ့စည်းပုံကို အကြောင်းပြချက်နဲ့ ပြခြင်း (6 marks): အတန်းဖော် တစ်ယောက်ရဲ့ IA product က ဒေတာကို သိမ်းတာ၊ screen ကို တည်ဆောက်တာနဲ့ click တိုင်းကို ကိုင်တွယ်တာတွေကို လုပ်တဲ့ line 600 လောက် ရှိတဲ့ JavaFX class တစ်ခုတည်း ဖြစ်ပါတယ်။ အဲဒါကို Model၊ View နဲ့ Controller class တွေအဖြစ် ခွဲတာရဲ့ အကျိုးကျေးဇူး နှစ်ခုနဲ့ အားနည်းချက် တစ်ခုကို Explain လုပ်ပါ။ Code ရေးဖို့ မလိုပါဘူး။
ဆက်စပ် ခေါင်းစဉ်များ
- အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: JavaFX Basics: control တွေ၊ layout တွေနဲ့ event handling
- အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: Encapsulation (ဒေတာနဲ့ method ကို တစ်စုတည်း ထုပ်ပိုးခြင်း): Model class တွေထဲက private field တွေ၊ getter တွေနဲ့ setter တွေ
- အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: ArrayList (ကြီးလာ၊ သေးသွားနိုင်တဲ့ list): Model ထဲက object list တစ်ခု။ HL အတွက်ဆိုရင် အပြင်မှာ ဖန်တီးထားတဲ့
Studentobject တွေကို သိမ်းထားတဲ့StudentListက Aggregation (သီးခြား ရှိနေနိုင်တဲ့ has-a ဆက်နွယ်မှု) ရဲ့ ဥပမာ တစ်ခုပါ - နောက်ထပ် လေ့လာမယ့် ခေါင်းစဉ်: FXML and Controllers: View ရဲ့ layout ကို FXML file တွေထဲ ရွှေ့ခြင်း
- နောက်ထပ် လေ့လာမယ့် ခေါင်းစဉ်: File I/O in Apps: Model ရဲ့ ဒေတာကို file တွေထဲ သိမ်းပြီး ပြန် load လုပ်ခြင်း
- ဆက်စပ် ခေါင်းစဉ်: JavaFX Cookbook: Share data across the whole app (app တစ်ခုလုံးမှာ ဒေတာ မျှသုံးခြင်း): screen တိုင်း သုံးနိုင်တဲ့ မျှသုံး object တစ်ခု၊ singleton (instance တစ်ခုတည်းပဲ ရှိတဲ့ class ပုံစံ) အဖြစ် တည်ဆောက်ထားပါတယ်