UML Class Diagrams (class တစ်ခုကို အကွက် သုံးကွက်နဲ့ ပြတဲ့ ပုံများ)

B3.1: Design and interpret UML class diagrams showing class structure and relationships.
မြန်မာလို: class (object တွေ ဖန်တီးဖို့ ပုံစံခွက်) တွေရဲ့ ဖွဲ့စည်းပုံနဲ့ class တွေကြား ဆက်နွယ်မှုတွေကို ပြတဲ့ UML class diagram တွေကို ဒီဇိုင်းဆွဲနိုင်ပြီး ဖတ်ရှု အဓိပ္ပာယ် ဖော်နိုင်ရပါမယ်။


အဓိက အယူအဆများ

UML ဆိုတာ ဘာလဲ

UML (Unified Modeling Language) ဆိုတာ software စနစ်တွေကို ဒီဇိုင်းဆွဲဖို့နဲ့ မှတ်တမ်းတင်ဖို့ သုံးတဲ့ စံသတ်မှတ်ထားတဲ့ ပုံနဲ့ပြ ဘာသာစကား တစ်ခုပါ။ UML class diagram က class တစ်ခုရဲ့ ဖွဲ့စည်းပုံ (သူ့နာမည်၊ attribute (object ရဲ့ ဒေတာကို သိမ်းတဲ့ variable) တွေနဲ့ method (သီးခြား အလုပ်တစ်ခု လုပ်ပေးတဲ့ code အပိုင်း) တွေ) ကို အကွက် သုံးကွက်ပါတဲ့ box တစ်ခုထဲမှာ ပြပါတယ်။

Class diagram တွေကို code မရေးခင် အရင် ဆွဲပါတယ်။ Syntax (code ရေးထုံး) အသေးစိတ်တွေထဲ မပျောက်သွားဘဲ design ကို တခြား developer (software ရေးသူ) တွေကို (ဒါမှမဟုတ် ကိုယ့်ကိုယ်ကို) ပြောပြပေးတဲ့ blueprint (အသေးစိတ် ပုံကြမ်း) အဖြစ် အလုပ်လုပ်ပါတယ်။

အကွက် သုံးကွက်ပါတဲ့ box

Class တိုင်းကို အပိုင်း သုံးပိုင်း ခွဲထားတဲ့ စတုဂံ တစ်ခုနဲ့ ပြပါတယ်:

+---------------------------+
|       ClassName           |    ← Section 1: Class name (centred, bold)
+---------------------------+
| - attribute1: Type        |    ← Section 2: Attributes (name: type)
| - attribute2: Type        |
+---------------------------+
| + method1(params): Return |    ← Section 3: Methods (name(params): return)
| + method2(): void         |
+---------------------------+

ပုံထဲက Section 1: Class name (centred, bold) က အပိုင်း 1: class နာမည် (အလယ်မှာ၊ စာလုံးထူနဲ့)၊ Section 2: Attributes (name: type) က အပိုင်း 2: attribute တွေ (နာမည်: type)၊ Section 3: Methods (name(params): return) က အပိုင်း 3: method တွေ (နာမည်(parameter တွေ): return type) လို့ ဆိုလိုပါတယ်။

Access Modifier သင်္ကေတများ

Visibility (ဘယ်ကနေ မြင်ရ၊ သုံးရလဲ ဆိုတာ) ကို ပြဖို့ UML က Java keyword (programming language မှာ အထူး အဓိပ္ပာယ်ရှိတဲ့ စကားလုံး) တွေအစား သင်္ကေတတွေကို သုံးပါတယ်:

သင်္ကေတ Java keyword အဓိပ္ပာယ်
- private Class ရဲ့ အထဲမှာပဲ သုံးလို့ ရပါတယ်
+ public ဘယ် class ကမဆို သုံးလို့ ရပါတယ်
# protected Class ရဲ့ အထဲမှာနဲ့ subclass (အမွေဆက်ခံတဲ့ child class) တွေမှာ သုံးလို့ ရပါတယ်

UML diagram ထဲက attribute နဲ့ method တိုင်းမှာ access modifier (ဘယ်ကနေ သုံးခွင့်ရလဲ သတ်မှတ်တဲ့ keyword) သင်္ကေတ ပါရပါမယ်။ စံ ပုံစံ: attribute တွေအတွက် -၊ constructor (object ဖန်တီးချိန် attribute တွေကို စတင် သတ်မှတ်ပေးတဲ့ method) နဲ့ public method တွေအတွက် +။

Attribute ရေးပုံ

Attribute တွေကို ဒီပုံစံနဲ့ ရေးပါတယ်: visibility name: type

- title: String
- fee: double
- isActive: boolean
- items: Product[]

သတိပြုပါ: type က နာမည်ရဲ့ နောက်မှာ colon (:) နဲ့ ခြားပြီး လာပါတယ်။ ဒါက Java syntax ရဲ့ ပြောင်းပြန်ပါ (Java မှာ String title၊ UML မှာ title: String)။

Method ရေးပုံ

Method တွေကို ဒီပုံစံနဲ့ ရေးပါတယ်: visibility name(parameterTypes): returnType

+ Workshop(String, int)     ← constructor (no return type)
+ getEnrolled(): int        ← getter returns int
+ enrol(int): void          ← mutator returns void
+ hasSpace(int): boolean    ← method returns boolean

ပုံထဲက constructor (no return type) က constructor (return type မရှိ)၊ getter returns int က getter (private attribute ရဲ့ တန်ဖိုးကို ပြန်ပေးတဲ့ method) က int ကို ပြန်ပေးတယ်၊ mutator returns void က mutator (attribute ရဲ့ တန်ဖိုးကို ပြောင်းပေးတဲ့ method) က void ကို ပြန်ပေးတယ် (ဘာမှ ပြန်မပေးဘူး)၊ method returns boolean က method က boolean ကို ပြန်ပေးတယ် လို့ ဆိုလိုပါတယ်။

Constructor တွေကို class နာမည်နဲ့ parameter (method ကို ပေးလိုက်တဲ့ တန်ဖိုးကို လက်ခံတဲ့ variable) type တွေနဲ့ ရေးပေမယ့် return type (method က ပြန်ပေးတဲ့ ဒေတာ အမျိုးအစား) မပါပါဘူး။

ဥပမာ အပြည့်အစုံ

Java class:

public class Workshop {
    private String title;
    private int capacity;
    private int enrolled;

    public Workshop(String title, int capacity) {
        this.title = title;
        this.capacity = capacity;
        this.enrolled = 0;
    }

    public String getTitle() { return title; }
    public int getEnrolled() { return enrolled; }
    public void enrol(int students) { ... }
    public boolean hasSpace(int students) { ... }
}
class Workshop():
    def __init__(self, title, capacity):
        self._title = title
        self._capacity = capacity
        self._enrolled = 0

    def get_title(self):
        return self._title

    def get_enrolled(self):
        return self._enrolled

    def enrol(self, students):
        # code missing

    def has_space(self, students):
        # code missing

UML diagram:

classDiagram
    class Workshop {
        -title : String
        -capacity : int
        -enrolled : int
        +Workshop(String, int)
        +getTitle() String
        +getEnrolled() int
        +enrol(int) void
        +hasSpace(int) boolean
    }

(ဒီ diagram တစ်ခုတည်းက Python class ကိုလည်း ဖော်ပြပါတယ်: UML က ဘယ် programming language နဲ့မှ မချိတ်ပါဘူး၊ IB Computer Science (နိုင်ငံတကာ ကျောင်းတွေမှာ သင်တဲ့ ကွန်ပျူတာသိပ္ပံ သင်ရိုး) ကလည်း Java စာမေးပွဲ စာစောင်ရော Python စာမေးပွဲ စာစောင်ပါ type ပါတဲ့ diagram ပုံစံ တူတူကို သုံးပါတယ်။)

ဆက်နွယ်မှု မြှားများ

UML diagram တွေက class တွေ အချင်းချင်း ဘယ်လို ဆက်နွယ်နေလဲ ဆိုတာကိုလည်း ပြပါတယ်။

Inheritance (is-a) (parent class ကနေ အမွေဆက်ခံခြင်း): parent ကို ညွှန်းထားတဲ့ ပိတ်ထားတဲ့ တြိဂံ ပါတဲ့ မျဉ်းအပြည့်:

classDiagram
    Animal <|-- Dog
    class Animal
    class Dog

“Dog IS-A Animal” (Dog က Animal တစ်မျိုး ဖြစ်တယ်) လို့ ဖတ်ပါ။ Dog က Animal ကို extend လုပ်ပါတယ်။

Aggregation (has-a) (သီးခြား ရှိနေနိုင်တဲ့ has-a ဆက်နွယ်မှု): “whole” (အလုံးစုံ) ဘက်မှာ အထဲ အရောင်မဖြည့်ထားတဲ့ စိန်ပုံ ပါတဲ့ မျဉ်း:

classDiagram
    Student o-- Address
    class Student
    class Address

“Student HAS-A Address” (Student မှာ Address ရှိတယ်) လို့ ဖတ်ပါ။ Student က Address object (class တစ်ခုကနေ ဖန်တီးထားတဲ့ instance) တစ်ခုကို attribute အဖြစ် ပါဝင်ပါတယ်။

Diagram တစ်ခုထဲမှာ နှစ်မျိုးလုံး:

classDiagram
    Vehicle <|-- Car
    Car o-- Engine
    class Vehicle
    class Car
    class Engine

Car IS-A Vehicle (Car က Vehicle တစ်မျိုး ဖြစ်တယ်၊ inheritance) ဖြစ်ပြီး Car HAS-A Engine (Car မှာ Engine ရှိတယ်၊ aggregation) ဖြစ်ပါတယ်။

Code ကနေ diagram ဆွဲခြင်း

Java code ကို UML အဖြစ် ပြောင်းဖို့:

  1. Class နာမည်ကို အပိုင်း 1 မှာ ရေးပါ
  2. Instance variable (object တစ်ခုချင်းရဲ့ ကိုယ်ပိုင် variable) တွေက အပိုင်း 2 မှာ attribute တွေ ဖြစ်လာပါတယ် (private အတွက် -၊ public အတွက် + ထည့်ပါ)
  3. Constructor နဲ့ method တွေကို အပိုင်း 3 မှာ ရေးပါ (public အတွက် +၊ private အတွက် - ထည့်ပါ)
  4. Type အစဉ်ကို ပြောင်းပြန်လှန်ပါ: Java က String name က UML မှာ name: String ဖြစ်သွားပါတယ်
  5. Colon ရဲ့ နောက်မှာ return type တွေ ထည့်ပါ: void, String, int, boolean စသဖြင့်

Scenario (ပြဿနာ ဖော်ပြချက်) ကနေ diagram ဆွဲခြင်း

Scenario ဖော်ပြချက် တစ်ခုကို UML အဖြစ် ပြောင်းဖို့:

  1. Noun (နာမ်) တွေကို ရှာပါ: သူတို့က class ဒါမှမဟုတ် attribute တွေ ဖြစ်လာပါတယ်
  2. Verb (ကြိယာ) တွေကို ရှာပါ: သူတို့က method တွေ ဖြစ်လာပါတယ်
  3. ဆက်နွယ်မှု တွေကို ရှာပါ: “has a” (ရှိတယ်) က aggregation ကို ညွှန်ပြပြီး “is a” (ဖြစ်တယ်) က inheritance ကို ညွှန်ပြပါတယ်
  4. Attribute တစ်ခုစီအတွက် data type (ဒေတာ အမျိုးအစား) ကို ဆုံးဖြတ်ပါ
  5. Method တစ်ခုစီအတွက် return type နဲ့ parameter တွေကို ဆုံးဖြတ်ပါ

ပြည့်စုံတဲ့ UML class diagram မှာ စစ်ရမယ့် အပိုင်း လေးပိုင်း ရှိပါတယ်: အပိုင်း သုံးပိုင်းပါတဲ့ class box၊ type နဲ့ visibility ပါတဲ့ attribute တွေ၊ return type ပါတဲ့ method တွေ နဲ့ မှန်ကန်တဲ့ ဆက်နွယ်မှု မြှားတွေ။


အဆင့်ဆင့် ရှင်းပြထားတဲ့ ဥပမာများ

ဥပမာ 1: Code ကနေ UML

Java code:

public class Product {
    private String name;
    private double price;
    private int stock;

    public Product(String name, double price, int stock) { ... }
    public String getName() { return name; }
    public double getPrice() { return price; }
    public int getStock() { return stock; }
    public boolean isInStock() { return stock > 0; }
    public void sell(int quantity) { ... }
    private boolean hasEnoughStock(int quantity) { ... }
}
class Product():
    def __init__(self, name, price, stock):
        # code missing

    def get_name(self):
        return self._name

    def get_price(self):
        return self._price

    def get_stock(self):
        return self._stock

    def is_in_stock(self):
        return self._stock > 0

    def sell(self, quantity):
        # code missing

    def _has_enough_stock(self, quantity):    # leading underscore = private helper
        # code missing

UML:

classDiagram
    class Product {
        -name : String
        -price : double
        -stock : int
        +Product(String, double, int)
        +getName() String
        +getPrice() double
        +getStock() int
        +isInStock() boolean
        +sell(int) void
        -hasEnoughStock(int) boolean
    }

သတိထားကြည့်ပါ: hasEnoughStock က helper method (တခြား method တွေကို ကူညီပေးတဲ့ class အတွင်းသုံး method) ဖြစ်လို့ - (private) ပါ။

ဥပမာ 2: Scenario ကနေ UML

အခြေအနေ: မိသားစု တစ်စု အိမ်ပြောင်းနေပြီး ပစ္စည်းထုပ်တဲ့ box တွေကို မှတ်တမ်း လုပ်ထားပါတယ်။ Box တစ်ခုစီမှာ label (တံဆိပ်)၊ box ရောက်ရမယ့် အခန်းနဲ့ အထဲက ပစ္စည်းတွေ ကွဲလွယ် (fragile) မလွယ် ဆိုတာ ရှိပါတယ်။ Box တစ်ခုစီက သူ့အလေးချိန်ကို ကီလိုဂရမ်နဲ့လည်း မှတ်ထားပြီး box အသစ်မှာ 0 ပါ။ မိသားစုက အလေးချိန် မတူတဲ့ ပစ္စည်းတွေကို box ထဲ ထုပ်ပိုး (pack) ပြီး box လေးလား (15 kg ထက် ပိုလား) စစ်ပါတယ်၊ ဘာလို့လဲဆိုတော့ လေးတဲ့ box ကို မဖို့ လူ နှစ်ယောက် လိုလို့ပါ။

အဆင့် 1: Noun တွေ = Box (class)၊ label, room, fragile, weightKg (attribute တွေ)

အဆင့် 2: Verb တွေ = pack (ထုပ်ပိုး)၊ လေးမလေး စစ် (pack နဲ့ isHeavy method တွေ)။ Getter တွေလည်း လိုပါတယ်။

အဆင့် 3: Data type တွေ: label (String)၊ room (String)၊ fragile (boolean)၊ weightKg (int)

အဆင့် 4: Parameter နဲ့ return type တွေ: pack က ပစ္စည်းရဲ့ အလေးချိန် (int) ကို ယူပြီး box ရဲ့ အလေးချိန်ထဲ ပေါင်းထည့်ကာ ရလဒ် ဘာမှ ပြန်မပေးလို့ ဒီ design မှာ void ကို return ပြန်ပါတယ်။ isHeavy က ဟုတ်/မဟုတ် မေးခွန်းကို ဖြေတာမို့ boolean ကို return ပြန်ပါတယ်။ Box အသစ်က 0 kg နဲ့ စလို့ weightKg ကို constructor ထဲမှာ သတ်မှတ်ပြီး constructor ရဲ့ parameter တွေထဲမှာ မပါပါဘူး။

UML:

classDiagram
    class Box {
        -label : String
        -room : String
        -fragile : boolean
        -weightKg : int
        +Box(String, String, boolean)
        +getLabel() String
        +getRoom() String
        +isFragile() boolean
        +getWeightKg() int
        +pack(int) void
        +isHeavy() boolean
    }

ဥပမာ 3: ဆက်နွယ်မှု ရှိတဲ့ class နှစ်ခု

အခြေအနေ: MovingVan (အိမ်ပြောင်း ကား) က Box object တွေရဲ့ array (အရွယ်အစား ပုံသေ၊ အမျိုးအစားတူ ဒေတာစု) တစ်ခုကို သယ်ပါတယ်။ ဒီမှာ Box က ဥပမာ 2 က class ရဲ့ fragile မပါတဲ့ အတိုချုံး ပုံစံပါ။

classDiagram
    class MovingVan {
        -name : String
        -boxes : Box[]
        -boxCount : int
        +MovingVan(String, int)
        +loadBox(Box) void
        +displayHeavy() void
        +countForRoom(String) int
    }
    class Box {
        -label : String
        -room : String
        -weightKg : int
        +Box(String, String)
        +getLabel() String
        +getRoom() String
        +getWeightKg() int
        +pack(int) void
        +isHeavy() boolean
    }
    MovingVan o-- Box

MovingVan ဘက်က စိန်ပုံ (◇) က aggregation ကို ပြပါတယ်: MovingVan မှာ Box တွေ ရှိပါတယ် (HAS)။ Box တွေကို ကား မရောက်ခင် ထုပ်ပိုးပြီး အိမ်အသစ်မှာ ပြန်ဖြည်လို့ ကားနဲ့ မသက်ဆိုင်ဘဲ သီးခြား ရှိနေပါတယ်။ ကား တစ်စီးမှာ box ဘယ်နှစ်ခု ဆံ့လဲဆိုတာကို diagram က မပြပါဘူး: code ထဲမှာတော့ ကားရဲ့ capacity (ဆံ့နိုင်တဲ့ အများဆုံး အရေအတွက်) က အဲဒီ ကန့်သတ်ချက်ကို သတ်မှတ်ပါတယ်။


Quick Check (အမြန် စစ်ဆေးမေးခွန်း)

Q1. Private double fee ကို UML မှာ ဘယ်လို ရေးသလဲ။

Q2. UML class diagram ရဲ့ အပိုင်း သုံးပိုင်းက ဘာတွေလဲ။

Q3. ဘယ် UML သင်္ကေတက inheritance ကို ကိုယ်စားပြုသလဲ။

Q4. UML diagram မှာ constructor က method နဲ့ ဘယ်လို ကွာသလဲ။

Q5. School တစ်ခုမှာ Student object တွေရဲ့ array တစ်ခု ပါပါတယ်။ ဒါက ဘယ် UML ဆက်နွယ်မှုလဲ။


Fill in the Blanks (ကွက်လပ် ဖြည့်ခြင်း)

UML ရေးထုံး စည်းမျဉ်းတွေကို ဖြည့်ပါ။ အောက်က စာတွေက ဒီလို ဆိုလိုပါတယ်: UML Access Modifier Symbols က UML access modifier သင်္ကေတများ၊ means private က private ကို ဆိုလိုတယ်၊ UML Attribute Format က UML attribute ရေးပုံ၊ UML Relationships က UML ဆက်နွယ်မှုများ၊ closed triangle က ပိတ်ထားတဲ့ တြိဂံ၊ open diamond က အလွတ် စိန်ပုံ။ စကားလုံး အဖြေတွေကို English စာလုံးနဲ့ ရိုက်ထည့်ပါ:

UML Access Modifier Symbols
============================
 means private
 means public
 means protected

UML Attribute Format
====================
visibility  : 

UML Relationships
=================
△ (closed triangle) = 
◇ (open diamond) = 

Spot the Error (အမှား ရှာခြင်း)

ဒီ UML diagram မှာ ရေးထုံး အမှား တစ်ခု ပါပါတယ်။ အမှားပါတဲ့ line ကို ရွေးပါ၊ ပြီးရင် ပြင်နည်းကို ရွေးပါ။

1+---------------------------+
2|        Student            |
3+---------------------------+
4| - String: name            |
5| - grade: int              |
6+---------------------------+
7| + getName(): String       |
8+---------------------------+

မှန်ကန်တဲ့ UML ပုံစံကို ရွေးပါ:


Practice Exercises (လေ့ကျင့်ခန်းများ)

Core (အခြေခံ အဆင့်)

  1. Code ကနေ UML: ဒီ class ကို ပြည့်စုံတဲ့ UML class diagram အဖြစ် ပြောင်းပါ:
    public class Circle {
        private double radius;
        public Circle(double radius) { this.radius = radius; }
        public double getRadius() { return radius; }
        public double getArea() { return Math.PI * radius * radius; }
        public void setRadius(double radius) { if (radius > 0) this.radius = radius; }
    }
    
    import math
    
    class Circle():
        def __init__(self, radius):
            self._radius = radius
    
        def get_radius(self):
            return self._radius
    
        def get_area(self):
            return math.pi * self._radius * self._radius
    
        def set_radius(self, radius):
            if radius > 0:
                self._radius = radius
    
  2. Scenario ကနေ UML: တိရစ္ဆာန်ဆေးခန်း (vet clinic) တစ်ခုက လူနာ (patient) တွေကို မှတ်တမ်းတင်ပါတယ်။ လူနာ တစ်ကောင်စီမှာ နာမည် (String)၊ မျိုးစိတ် (String)၊ အသက် (int) နဲ့ ကာကွယ်ဆေး ထိုးပြီး မပြီး အခြေအနေ (boolean) ရှိပါတယ်။ ဆေးခန်းက လူနာကို ကာကွယ်ဆေး ထိုးနိုင်ပြီး ထိုးပြီးပြီလား စစ်နိုင်ပါတယ်။ UML diagram ကို ဆွဲပါ။

  3. UML diagram ကို ဖတ်ခြင်း: ဒီ UML ကို ကြည့်ပြီး Java class ကို ရေးပါ:

    classDiagram
        class Song {
            -title : String
            -artist : String
            -durationSecs : int
            +Song(String, String, int)
            +getTitle() String
            +getArtist() String
            +isLong() boolean
        }
    

Extension (တိုးချဲ့ အဆင့်)

  1. Class နှစ်ခုပါတဲ့ diagram: Song object တွေရဲ့ array တစ်ခု ပါတဲ့ Playlist အတွက် UML ကို ဆွဲပါ။ Class နှစ်ခုလုံးနဲ့ aggregation ဆက်နွယ်မှုကို ပြပါ။ Playlist မှာ နာမည် ရှိပြီး သီချင်း ထည့်တာ၊ ခေါင်းစဉ် (title) နဲ့ ဖယ်တာ၊ စုစုပေါင်း ကြာချိန်ကို ယူတာ လုပ်နိုင်ပါတယ်။

  2. ဆက်နွယ်မှုတွေကို ခွဲခြားခြင်း: အတွဲ တစ်တွဲစီအတွက် ဆက်နွယ်မှုက inheritance (is-a) လား aggregation (has-a) လား ဖော်ပြပါ:

    • (a) Car နဲ့ Engine
    • (b) Dog နဲ့ Animal
    • (c) School နဲ့ Student
    • (d) Teacher နဲ့ SchoolMember

Challenge (စိန်ခေါ်မှု အဆင့်)

  1. စနစ် တစ်ခုလုံးကို design လုပ်ခြင်း: ဆေးရုံ တစ်ရုံက ဆရာဝန် (doctor) တွေနဲ့ ချိန်းဆိုမှု (appointment) တွေကို မှတ်တမ်းတင်ဖို့ လိုပါတယ်။ ဆရာဝန် တစ်ယောက်စီမှာ နာမည်၊ အထူးပြု ဘာသာ နဲ့ appointment စာရင်း တစ်ခု ရှိပါတယ်။ Appointment တစ်ခုစီမှာ လူနာ နာမည်၊ ရက်စွဲ နဲ့ ကြာချိန် ရှိပါတယ်။ Class နှစ်ခုလုံး၊ သူတို့ရဲ့ attribute တွေ၊ method တွေ နဲ့ သူတို့ကြား ဆက်နွယ်မှုပါတဲ့ ပြည့်စုံတဲ့ UML ကို ဆွဲပါ။

ဆက်စပ် ခေါင်းစဉ်များ

  • အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: Encapsulation (ဒေတာနဲ့ method ကို တစ်စုတည်း ထုပ်ပိုးခြင်း): UML ရဲ့ - နဲ့ + သင်္ကေတတွေက private/public access modifier တွေကို ကိုယ်စားပြုပါတယ်
  • အရင် လေ့လာထားရမယ့် ခေါင်းစဉ်: Access Modifiers: visibility အဆင့် တစ်ခုစီရဲ့ အဓိပ္ပာယ်ကို နားလည်ခြင်း
  • နောက်ထပ် လေ့လာမယ့် ခေါင်းစဉ်: Aggregation: ◇ နဲ့ ပြတဲ့ has-a ဆက်နွယ်မှုကို ပိုနက်နက် လေ့လာခြင်း
  • ရှေ့ဆက် ခေါင်းစဉ်: Inheritance: △ နဲ့ ပြတဲ့ is-a ဆက်နွယ်မှု

© EduCS.me. ကွန်ပျူတာသိပ္ပံ ပညာရေးအတွက် အရင်းအမြစ်တွေ စုထားတဲ့ နေရာပါ။ EduCS is an independent educational resource. It is not affiliated with, or endorsed by, the International Baccalaureate Organization. (EduCS ဟာ သီးခြား ပညာရေး အရင်းအမြစ်တစ်ခုပါ။ International Baccalaureate Organization နဲ့ ဆက်စပ်မှု မရှိသလို သူတို့ရဲ့ ထောက်ခံချက်လည်း မရှိပါဘူး။) ဆက်သွယ်ရန်