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 សម្រាប់កូដប្រសើរឡើង!