Lập trình hướng đối tượng trong C#

Hướng đối tượng trong C#

Lập trình hướng đối tượng

Lập trình hướng đối tượng (Object-Oriented Programming – OOP) là một phương pháp lập trình tập trung vào các đối tượng trong thế giới thực và mối quan hệ giữa chúng. Trong OOP, mỗi đối tượng có thể chứa dữ liệu và các phương thức để xử lý dữ liệu đó. Các đối tượng có thể kế thừa và mở rộng các tính năng của nhau.

Trong C#, tất cả các đối tượng đều phải được xác định bởi một lớp (class). Một lớp có thể chứa các trường (fields) và phương thức (methods) để xử lý dữ liệu của đối tượng. Trong lập trình hướng đối tượng, mỗi đối tượng được xem như một thể hiện (instance) của một lớp.

Để định nghĩa một lớp trong C#, chúng ta sử dụng từ khóa class theo sau là tên lớp và một cặp dấu ngoặc nhọn để chứa các thành phần của lớp, như sau:

class ClassName {
    // Trường (field) của lớp
    // Phương thức (method) của lớp
}

Trường là biến thuộc tính của lớp và phương thức là hành động được thực hiện trên đối tượng của lớp.

Để tạo một đối tượng của lớp, chúng ta sử dụng từ khóa new theo sau là tên lớp và một cặp dấu ngoặc tròn (nếu không có tham số) hoặc chứa các tham số để truyền cho hàm khởi tạo của lớp, như sau:

ClassName objectName = new ClassName();

Một lớp có thể kế thừa các thuộc tính và phương thức của lớp khác bằng cách sử dụng từ khóa :, như sau:

class DerivedClass : BaseClass {
    // Trường (field) và phương thức (method) của lớp kế thừa
    // Các trường (field) và phương thức (method) mới của lớp
}

Lập trình hướng đối tượng (Object-Oriented Programming – OOP) là một phương pháp lập trình tập trung vào các đối tượng trong thế giới thực và mối quan hệ giữa chúng. Trong OOP, mỗi đối tượng có thể chứa dữ liệu và các phương thức để xử lý dữ liệu đó. Các đối tượng có thể kế thừa và mở rộng các tính năng của nhau.

Trong C#, tất cả các đối tượng đều phải được xác định bởi một lớp (class). Một lớp có thể chứa các trường (fields) và phương thức (methods) để xử lý dữ liệu của đối tượng. Trong lập trình hướng đối tượng, mỗi đối tượng được xem như một thể hiện (instance) của một lớp.

Để định nghĩa một lớp trong C#, chúng ta sử dụng từ khóa class theo sau là tên lớp và một cặp dấu ngoặc nhọn để chứa các thành phần của lớp, như sau:

class ClassName {
    // Trường (field) của lớp
    // Phương thức (method) của lớp
}

Trường là biến thuộc tính của lớp và phương thức là hành động được thực hiện trên đối tượng của lớp.

Để tạo một đối tượng của lớp, chúng ta sử dụng từ khóa new theo sau là tên lớp và một cặp dấu ngoặc tròn (nếu không có tham số) hoặc chứa các tham số để truyền cho hàm khởi tạo của lớp, như sau:

ClassName objectName = new ClassName();

Một lớp có thể kế thừa các thuộc tính và phương thức của lớp khác bằng cách sử dụng từ khóa :, như sau:

class DerivedClass : BaseClass {
    // Trường (field) và phương thức (method) của lớp kế thừa
    // Các trường (field) và phương thức (method) mới của lớp
}

Trong đó, BaseClass là tên của lớp được kế thừa. Trong C#, một lớp chỉ có thể kế thừa từ một lớp duy nhất, tuy nhiên nó có thể kế thừa từ một giao diện (interface) hoặc nhiều giao diện.

Giao diện (interface) là một tập hợp các phương thức và thuộc tính không được hiện thực hóa bên trong giao diện. Để hiện thực một giao diện

Lớp và đối tượng trong C#

Lớp và đối tượng là hai khái niệm quan trọng trong lập trình hướng đối tượng (OOP) của C#. Lớp là một mô tả chung về một nhóm đối tượng, bao gồm các thuộc tính và phương thức. Trong khi đó, đối tượng là một thực thể của lớp, được tạo ra từ lớp đó.

Để định nghĩa một lớp trong C#, chúng ta sử dụng từ khóa class, theo sau là tên của lớp và một cặp dấu ngoặc nhọn để chứa các thành phần của lớp. Ví dụ, ta có thể định nghĩa một lớp Person như sau:

class Person {
    // Các thuộc tính (properties) của lớp
    public string Name { get; set; }
    public int Age { get; set; }
    
    // Các phương thức (methods) của lớp
    public void SayHello() {
        Console.WriteLine("Hello!");
    }
}

Trong đó, NameAge là các thuộc tính của lớp Person, và SayHello() là một phương thức của lớp.

Sau khi định nghĩa một lớp, chúng ta có thể tạo ra các đối tượng từ lớp đó bằng cách sử dụng từ khóa new. Ví dụ, ta có thể tạo ra một đối tượng person1 từ lớp Person như sau:

Person person1 = new Person();

Sau khi tạo ra một đối tượng, chúng ta có thể truy cập các thuộc tính và phương thức của đối tượng đó bằng cách sử dụng toán tử chấm .. Ví dụ, để đặt tên cho đối tượng person1, ta có thể sử dụng thuộc tính Name như sau:

person1.Name = "John";

Tương tự, để gọi phương thức SayHello(), ta có thể sử dụng đối tượng person1 như sau:

person1.SayHello();

Trong C#, các lớp có thể kế thừa các thuộc tính và phương thức của lớp khác bằng cách sử dụng từ khóa :, như sau:

class Student : Person {
    // Các thuộc tính (properties) mới của lớp
    public int StudentID { get; set; }
    
    // Các phương thức (methods) mới của lớp
    public void Study() {
        Console.WriteLine("I am studying.");
    }
}

Trong đó, lớp Student kế thừa các thuộc tính và phương thức của lớp `

Kế thừa và đa hình trong C#

Trong lập trình hướng đối tượng, kế thừa và đa hình là hai khái niệm cơ bản giúp tăng tính tái sử dụng mã và giảm độ phức tạp của mã.

Kế thừa là quá trình tạo ra một lớp mới bằng cách sử dụng các thành phần của một lớp hiện có. Lớp mới được gọi là lớp con (derived class), và lớp đã tồn tại được gọi là lớp cha (base class). Trong C#, kế thừa được thực hiện bằng từ khóa ” : “. Ví dụ:

class Animal {
  public void Speak() {
    Console.WriteLine("Animal is speaking...");
  }
}

class Dog : Animal {
  public void Bark() {
    Console.WriteLine("Dog is barking...");
  }
}

Trong ví dụ trên, lớp Dog kế thừa các thành phần của lớp Animal, và cũng có thêm phương thức Bark.

Đa hình (polymorphism) là khả năng của một đối tượng để thực hiện nhiều hành vi khác nhau dựa trên các đối tượng khác nhau của cùng một lớp hoặc các lớp con khác nhau của lớp cha. Có hai loại đa hình trong C#:

  1. Đa hình tại thời điểm biên dịch (compile-time polymorphism): Được thực hiện bằng cách sử dụng phương thức nạp chồng (method overloading) hoặc toán tử nạp chồng (operator overloading). Phương thức nạp chồng cho phép chúng ta định nghĩa nhiều phương thức cùng tên nhưng khác nhau về số lượng hoặc kiểu tham số. Toán tử nạp chồng cho phép chúng ta định nghĩa lại các toán tử cơ bản như +, -, *, /, %… Ví dụ:
class Calculator {
  public int Add(int a, int b) {
    return a + b;
  }
  
  public double Add(double a, double b) {
    return a + b;
  }
  
  public int Add(int a, int b, int c) {
    return a + b + c;
  }
}

Calculator calc = new Calculator();
int sum1 = calc.Add(2, 3); // Gọi phương thức Add(int, int)
double sum2 = calc.Add(2.5, 3.7); // Gọi phương thức Add(double, double)
int sum3 = calc.Add(2, 3, 4); // Gọi phương thức Add(int, int, int)

2. Đa hình tại thời điểm chạy (runtime polymorphism): Được thực hiện bằng cách sử dụng tính đa hình của kế thừa. Điều này có nghĩa là khi đối tượng được tạo ra tại thời điểm chạy, phương thức được gọi tương ứng với kiểu đối tượng hiện tại, không phải kiểu của biến đang giữ nó.

Ví dụ:

class Animal {
    public virtual void AnimalSound() {
        Console.WriteLine("The animal makes a sound");
    }
}

class Dog : Animal {
    public override void AnimalSound() {
        Console.WriteLine("The dog barks");
    }
}

class Cat : Animal {
    public override void AnimalSound() {
        Console.WriteLine("The cat meows");
    }
}

class Program {
    static void Main(string[] args) {
        Animal myAnimal = new Animal();
        Animal myDog = new Dog();
        Animal myCat = new Cat();

        myAnimal.AnimalSound(); // Output: The animal makes a sound
        myDog.AnimalSound(); // Output: The dog barks
        myCat.AnimalSound(); // Output: The cat meows
    }
}

Ở đây, chúng ta có một lớp cơ sở Animal với một phương thức ảo AnimalSound(). Lớp Dog và lớp Cat kế thừa từ lớp Animal và ghi đè phương thức AnimalSound() của nó. Trong phương thức Main(), chúng ta tạo ra ba đối tượng: myAnimal kiểu Animal, myDog kiểu DogmyCat kiểu Cat. Khi chúng ta gọi phương thức AnimalSound() trên mỗi đối tượng, phương thức được gọi tương ứng với kiểu đối tượng hiện tại, không phải kiểu của biến đang giữ nó. Do đó, kết quả sẽ khác nhau tùy thuộc vào đối tượng được tạo ra.

Ngoài kế thừa, đa hình là một khái niệm khác rất quan trọng trong lập trình hướng đối tượng. Đa hình cho phép ta sử dụng một đối tượng của lớp con trong một tình huống đòi hỏi đối tượng của lớp cha.

Ví dụ:

class Shape
{
    public virtual void Draw()
    {
        Console.WriteLine("Drawing a shape.");
    }
}

class Circle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a circle.");
    }
}

class Rectangle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing a rectangle.");
    }
}

Trong ví dụ trên, lớp Shape là lớp cha, và có một phương thức Draw mặc định. Lớp CircleRectangle là các lớp con, mỗi lớp có một phương thức Draw riêng, ghi đè phương thức của lớp cha.

Bằng cách sử dụng tính đa hình, ta có thể sử dụng một đối tượng của lớp con trong một tình huống đòi hỏi đối tượng của lớp cha, như sau:

Shape s = new Circle();
s.Draw();

Kết quả là “Drawing a circle.” sẽ được hiển thị ra màn hình, do phương thức Draw của lớp Circle được gọi đến.

Giao diện và trừu tượng hóa trong C#

Trong lập trình hướng đối tượng, giao diện và trừu tượng hóa là các khái niệm quan trọng để giúp code trở nên linh hoạt và dễ bảo trì.

Giao diện (Interface) trong C#

Giao diện là một tập hợp các phương thức và thuộc tính mà các lớp khác có thể triển khai. Giao diện trong C# được khai báo bằng từ khóa interface và không thể khởi tạo đối tượng từ nó.

Ví dụ:

interface IAnimal
{
    void Speak();
}

class Dog : IAnimal
{
    public void Speak()
    {
        Console.WriteLine("Gâu gâu");
    }
}

class Cat : IAnimal
{
    public void Speak()
    {
        Console.WriteLine("Meow meow");
    }
}

Trong ví dụ trên, IAnimal là giao diện, có duy nhất một phương thức Speak() mà các lớp khác có thể triển khai. Lớp DogCat triển khai giao diện IAnimal bằng cách cung cấp thân hàm cho phương thức Speak(). Khi gọi phương thức Speak() trên một đối tượng Dog hoặc Cat, nó sẽ in ra kết quả tương ứng là "Gâu gâu" hoặc "Meow meow".

Trừu tượng hóa (Abstraction) trong C#

Trừu tượng hóa là khả năng tách biệt các tính năng của một đối tượng, chỉ giữ lại những tính năng quan trọng nhất để tập trung vào các phương thức và thuộc tính quan trọng. Trừu tượng hóa trong C# được thực hiện thông qua lớp trừu tượng và phương thức trừu tượng.

Lớp trừu tượng (Abstract class) là một lớp không thể khởi tạo đối tượng trực tiếp, được sử dụng để định nghĩa các tính năng chung của một nhóm các lớp con. Lớp trừu tượng có thể chứa các phương thức trừu tượng và phương thức thực tế.

Ví dụ:

abstract class Animal
{
    public abstract void Speak();
}

class Dog : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Gâu gâu");
    }
}

class Cat : Animal
{
    public override void Speak()
    {
        Console.WriteLine("Meow meow");
    }
}

Trong ví dụ trên, lớp Animal là một lớp trừu tượng có phương thức trừu tượng Speak(). Lớp DogCat kế thừa từ lớp Animal