© Khmer Angkor Academy - sophearithput168

Dart OOP

Object-Oriented Programming ក្នុង Dart

Dart គឺជាភាសា OOP ពេញលេញ។ គ្រប់អ្វីទាំងអស់ជា object រួមទាំង numbers, functions និង null។ OOP ជួយឱ្យ code មានរចនាសម្ព័ន្ធល្អ, ងាយ maintain និង reusable។

📚 OOP Core Principles (4 Pillars)

OOP Principles

1️⃣ ENCAPSULATION (ការរុំព័ទ្ធ)
   - Hide internal details
   - Expose only necessary interface
   - Use private/public access modifiers

2️⃣ INHERITANCE (ការទទួលមរតក)
   - Reuse code from parent class
   - Create specialized versions
   - "is-a" relationship

3️⃣ POLYMORPHISM (ភាពពហុរូប)
   - Same interface, different implementations
   - Method overriding
   - Runtime behavior changes

4️⃣ ABSTRACTION (ការអរូបី)
   - Hide complex implementation
   - Show only essential features
   - Abstract classes & interfaces

OOP Benefits:

  • Modularity: Code organized in logical units
  • Reusability: Code can be reused through inheritance
  • Maintainability: Easier to update and fix
  • Scalability: Easy to extend functionality
  • Data Security: Encapsulation protects data

🎯 Class និង Object

Class vs Object:

Class Object
Blueprint/Template Actual instance
Defined once Can create many
No memory allocated Memory allocated
Example: Car blueprint Example: My Toyota, Your Honda

បង្កើត Class

class Person {
  // Properties
  String name;
  int age;
  
  // Constructor
  Person(this.name, this.age);
  
  // Method
  void introduce() {
    print('ឈ្មោះ៖ $name, អាយុ៖ $age ឆ្នាំ');
  }
}

void main() {
  // បង្កើត object
  Person person1 = Person('សុខា', 20);
  Person person2 = Person('ដារា', 25);
  
  person1.introduce();  // ឈ្មោះ៖ សុខា, អាយុ៖ 20 ឆ្នាំ
  person2.introduce();  // ឈ្មោះ៖ ដារា, អាយុ៖ 25 ឆ្នាំ
}

Constructors ប្រភេទផ្សេងៗ

class Student {
  String name;
  int age;
  String grade;
  
  // Default constructor
  Student(this.name, this.age, this.grade);
  
  // Named constructor
  Student.withName(this.name) : age = 18, grade = 'A';
  
  // Factory constructor
  factory Student.fromJson(Map<String, dynamic> json) {
    return Student(
      json['name'],
      json['age'],
      json['grade']
    );
  }
}

void main() {
  Student s1 = Student('សុខា', 20, 'A');
  Student s2 = Student.withName('ដារា');
  
  Map<String, dynamic> data = {
    'name': 'សុភា',
    'age': 22,
    'grade': 'B'
  };
  Student s3 = Student.fromJson(data);
}

Constructor Types Explained:

Constructor Type Purpose Example Use Case
Default Standard initialization Person('John', 25)
Named Multiple ways to create object Person.guest(), Person.admin()
Factory Return existing instance or subclass Singleton pattern, caching
Const Create compile-time constant Immutable objects

🔒 Encapsulation (Private/Public)

Encapsulation គឺការលាក់ internal state និង expose តែ safe interface។

Why Encapsulation?

  • 🔐 Protect data from invalid values
  • ✅ Validate input before setting
  • 📦 Hide implementation details
  • 🔄 Easy to change internal logic without breaking external code
class BankAccount {
  String _accountNumber;  // Private (underscore)
  double _balance;
  
  BankAccount(this._accountNumber, this._balance);
  
  // Getter
  double get balance => _balance;
  
  // Setter
  set balance(double amount) {
    if (amount >= 0) {
      _balance = amount;
    }
  }
  
  // Public method
  void deposit(double amount) {
    if (amount > 0) {
      _balance += amount;
      print('បញ្ចូល៖ $$amount, សមតុល្យ៖ $$_balance');
    }
  }
  
  void withdraw(double amount) {
    if (amount > 0 && amount <= _balance) {
      _balance -= amount;
      print('ដក៖ $$amount, សមតុល្យ៖ $$_balance');
    } else {
      print('លុយមិនគ្រប់!');
    }
  }
}

void main() {
  BankAccount account = BankAccount('001', 1000);
  
  print(account.balance);     // 1000
  account.deposit(500);       // បញ្ចូល៖ $500, សមតុល្យ៖ $1500
  account.withdraw(200);      // ដក៖ $200, សមតុល្យ៖ $1300
  
  // account._balance = 10000; // ERROR! Private property
}

🧬 Inheritance (ការបង្កាន់ទុក)

Inheritance អនុញ្ញាតឱ្យ class មួយទទួលបាន properties និង methods ពី parent class។

Inheritance Benefits:

  • ♻️ Code Reusability: មិនចាំបាច់សរសេរ code ដដែលៗ
  • 📊 Hierarchy: បង្កើត class hierarchy ច្បាស់លាស់
  • 🔧 Extensibility: ងាយស្រួលបន្ថែម features
  • 🎯 Method Overriding: Customize parent behavior

Inheritance Syntax:

Parent Class (Superclass)
        ↓
    extends
        ↓
Child Class (Subclass)

• Child inherits all public members
• Use super() to call parent constructor
• Use @override to replace parent methods
// Parent class
class Animal {
  String name;
  int age;
  
  Animal(this.name, this.age);
  
  void eat() {
    print('$name កំពុងញ៉ាំ');
  }
  
  void sleep() {
    print('$name កំពុងដេក');
  }
}

// Child class
class Dog extends Animal {
  String breed;
  
  Dog(String name, int age, this.breed) : super(name, age);
  
  void bark() {
    print('$name ព្រោង៖ Woof Woof!');
  }
  
  @override
  void eat() {
    print('$name កំពុងញ៉ាំឆ្អឹង');
  }
}

class Cat extends Animal {
  String color;
  
  Cat(String name, int age, this.color) : super(name, age);
  
  void meow() {
    print('$name ព្រោង៖ Meow!');
  }
}

void main() {
  Dog dog = Dog('Max', 3, 'Golden Retriever');
  dog.eat();    // Max កំពុងញ៉ាំឆ្អឹង (Overridden)
  dog.bark();   // Max ព្រោង៖ Woof Woof!
  dog.sleep();  // Max កំពុងដេក (Inherited)
  
  Cat cat = Cat('Kitty', 2, 'White');
  cat.eat();    // Kitty កំពុងញ៉ាំ
  cat.meow();   // Kitty ព្រោង៖ Meow!
}

🎭 Polymorphism (ភាពពហុរូប)

Polymorphism អនុញ្ញាតឱ្យ objects ប្រភេទផ្សេងៗ respond ទៅ same method call តាម way ផ្សេងៗគ្នា។

Types of Polymorphism:

Type Description Example
Method Overriding Child redefines parent method Dog.eat() vs Animal.eat()
Runtime Polymorphism Actual method decided at runtime Animal a = Dog(); a.eat();
class Shape {
  void draw() {
    print('គូររូបរាង');
  }
  
  double area() {
    return 0;
  }
}

class Circle extends Shape {
  double radius;
  
  Circle(this.radius);
  
  @override
  void draw() {
    print('គូររង្វង់');
  }
  
  @override
  double area() {
    return 3.14 * radius * radius;
  }
}

class Rectangle extends Shape {
  double width;
  double height;
  
  Rectangle(this.width, this.height);
  
  @override
  void draw() {
    print('គូរចតុកោណកែង');
  }
  
  @override
  double area() {
    return width * height;
  }
}

void main() {
  List<Shape> shapes = [
    Circle(5),
    Rectangle(4, 6),
    Circle(3)
  ];
  
  for (Shape shape in shapes) {
    shape.draw();
    print('ទំហំ៖ ' + shape.area().toString() + '\n');
  }
}

📐 Abstract Classes (ការអរូបី)

Abstract Class គឺជា template ដែលមិនអាច instantiate ដោយផ្ទាល់។ វាប្រើសម្រាប់កំណត់ contract ដែល subclasses ត្រូវតែ implement។

Abstract vs Concrete Classes:

Abstract Class Concrete Class
Cannot create instance Can create instance
Can have abstract methods All methods implemented
Use as template/contract Complete implementation
Example: Vehicle, Animal Example: Car, Dog
abstract class Vehicle {
  String brand;
  
  Vehicle(this.brand);
  
  // Abstract method (no implementation)
  void start();
  void stop();
  
  // Concrete method
  void honk() {
    print('$brand: Beep Beep!');
  }
}

class Car extends Vehicle {
  Car(String brand) : super(brand);
  
  @override
  void start() {
    print('$brand ចាប់ផ្តើមម៉ាស៊ីន');
  }
  
  @override
  void stop() {
    print('$brand បញ្ឈប់ម៉ាស៊ីន');
  }
}

class Motorcycle extends Vehicle {
  Motorcycle(String brand) : super(brand);
  
  @override
  void start() {
    print('$brand ទាញស្តាត');
  }
  
  @override
  void stop() {
    print('$brand ចុចប្រេក');
  }
}

void main() {
  Car car = Car('Toyota');
  car.start();  // Toyota ចាប់ផ្តើមម៉ាស៊ីន
  car.honk();   // Toyota: Beep Beep!
  car.stop();   // Toyota បញ្ឈប់ម៉ាស៊ីន
  
  Motorcycle motor = Motorcycle('Honda');
  motor.start(); // Honda ទាញស្តាត
}

🔌 Interfaces (using abstract class)

Interface ក្នុង Dart ត្រូវបានធ្វើឱ្យប្រសើរឡើងដោយប្រើ implements keyword។ Class អាច implement interfaces ច្រើន (multiple inheritance of contracts)។

Interface vs Abstract Class:

Feature Interface (implements) Abstract Class (extends)
Multiple ✅ Can implement many ❌ Extend only one
Implementation Must implement all methods Can have some implemented
Purpose Define contract/capability Share common code
abstract class Flyable {
  void fly();
}

abstract class Swimmable {
  void swim();
}

class Duck implements Flyable, Swimmable {
  @override
  void fly() {
    print('ទាហានហោះ');
  }
  
  @override
  void swim() {
    print('ទាហានហែល');
  }
}

class Penguin implements Swimmable {
  @override
  void swim() {
    print('ភេនឃ្វីនហែល');
  }
}

void main() {
  Duck duck = Duck();
  duck.fly();   // ទាហានហោះ
  duck.swim();  // ទាហានហែល
  
  Penguin penguin = Penguin();
  penguin.swim(); // ភេនឃ្វីនហែល
}

🎨 Mixins (Code Reuse without Inheritance)

Mixins អនុញ្ញាតឱ្យ reuse class code ក្នុង multiple class hierarchies ដោយមិនប្រើ inheritance។

When to Use Mixins?

  • ✅ Need to share behavior across unrelated classes
  • ✅ Want to avoid deep inheritance hierarchies
  • ✅ Composition over inheritance
  • ✅ Add capabilities to classes (logging, serialization, etc.)

Mixin vs Inheritance:

Aspect Inheritance Mixin
Relationship "is-a" "has-capability"
Quantity Single parent Multiple mixins
Purpose Hierarchy Composition
mixin CanFly {
  void fly() {
    print('កំពុងហោះ');
  }
}

mixin CanSwim {
  void swim() {
    print('កំពុងហែល');
  }
}

class Bird with CanFly {
  String name;
  Bird(this.name);
}

class Fish with CanSwim {
  String name;
  Fish(this.name);
}

class Duck with CanFly, CanSwim {
  String name;
  Duck(this.name);
}

void main() {
  Bird bird = Bird('ស្វា');
  bird.fly();  // កំពុងហោះ
  
  Duck duck = Duck('ទា');
  duck.fly();  // កំពុងហោះ
  duck.swim(); // កំពុងហែល
}

🔧 Static Members (Class-Level)

Static members belong to the class itself, not to instances។ ប្រើសម្រាប់ utility functions និង constants។

Static vs Instance Members:

Static Instance
One copy per class One copy per object
Access: ClassName.member Access: object.member
No access to this Can use this
Example: Math.pi, Math.sqrt() Example: person.name, person.walk()
class MathUtils {
  static const double pi = 3.14159;
  
  static int add(int a, int b) {
    return a + b;
  }
  
  static double circleArea(double radius) {
    return pi * radius * radius;
  }
}

void main() {
  print(MathUtils.pi);                    // 3.14159
  print(MathUtils.add(5, 3));             // 8
  print(MathUtils.circleArea(5));         // 78.53975
  
  // មិនចាំបាច់បង្កើត object
  // MathUtils math = MathUtils(); // Not needed
}

🏗️ Design Patterns in OOP

1. Singleton Pattern (Single Instance)

class DatabaseConnection {
  static final DatabaseConnection _instance = DatabaseConnection._internal();
  
  // Private constructor
  DatabaseConnection._internal();
  
  // Factory constructor returns same instance
  factory DatabaseConnection() {
    return _instance;
  }
  
  void query(String sql) {
    print('Executing: ' + sql);
  }
}

void main() {
  var db1 = DatabaseConnection();
  var db2 = DatabaseConnection();
  
  print(identical(db1, db2));  // true - same instance!
}

2. Factory Pattern

abstract class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle();
    if (type == 'rectangle') return Rectangle();
    throw 'Unknown shape type';
  }
  void draw();
}

class Circle implements Shape {
  @override
  void draw() => print('Drawing circle');
}

class Rectangle implements Shape {
  @override
  void draw() => print('Drawing rectangle');
}

void main() {
  Shape shape1 = Shape('circle');
  shape1.draw();  // Drawing circle
}

3. Builder Pattern

class User {
  String? name;
  int? age;
  String? email;
  String? phone;
  
  User._builder(UserBuilder builder) {
    name = builder.name;
    age = builder.age;
    email = builder.email;
    phone = builder.phone;
  }
}

class UserBuilder {
  String? name;
  int? age;
  String? email;
  String? phone;
  
  UserBuilder setName(String name) {
    this.name = name;
    return this;
  }
  
  UserBuilder setAge(int age) {
    this.age = age;
    return this;
  }
  
  UserBuilder setEmail(String email) {
    this.email = email;
    return this;
  }
  
  UserBuilder setPhone(String phone) {
    this.phone = phone;
    return this;
  }
  
  User build() {
    return User._builder(this);
  }
}

void main() {
  User user = UserBuilder()
    .setName('John')
    .setAge(25)
    .setEmail('john@example.com')
    .build();
}

💡 Best Practices:

  • ✅ Follow Single Responsibility Principle (one class, one purpose)
  • ✅ Use composition over inheritance when possible
  • ✅ Make classes small and focused
  • ✅ Use private members to protect data
  • ✅ Prefer immutability (final fields) when possible
  • ✅ Use meaningful class and method names

⚠️ Common OOP Mistakes:

  • ❌ Creating god classes (too many responsibilities)
  • ❌ Deep inheritance hierarchies (hard to maintain)
  • ❌ Not using encapsulation (all public members)
  • ❌ Overusing inheritance instead of composition
  • ❌ Tight coupling between classes

💡 ជំនួយ: OOP ជួយឱ្យកូដងាយយល់ និងងាយការពារថែរក្សា។ ក្នុង Flutter អ្នកនឹងប្រើ classes ជាច្រើនសម្រាប់បង្កើត widgets និង models។ Master OOP principles សម្រាប់កូដប្រសើរឡើង!