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

Lập trình hướng đối tượng (OOP) là gì? Tại sao lập trình hướng đối tượng lại hay được hỏi khi đi phỏng vấn. Lập trình hướng đối tượng có những tính chất gì? ...

Qua bài viết này mình hi vọng sẽ giải đáp được đầy đủ và chính xác về lập trình hướng đối tượng trong C#.

Lập trình hướng đối tượng là gì?

Lập trình hướng đối tượng (OOP - Object Oriented Programming) là một phương pháp lập trình sử dụng các đối tượng (object) để xây dựng hệ thống phần mềm hoặc ứng dụng web.

5 khái niệm trong lập trình hướng đối tượng

Bạn sẽ bắt gặp một số khái niệm như: lớp (class), phương thức (method), thuộc tính (property), trường (field), đối tượng (object) ... trong lập trình hướng đối tượng.

Chúng ta cùng tìm hiểu chúng là gì nào.

Lớp (class)

Một class trong lập trình hướng đối tượng là tập hợp các đối tượng có cùng các đặc điểm, hành vi, phương thức hoạt động.

Trong đó các đặc điểm của đối tượng được gọi là các trường (field), các đặc điểm của đối tượng được thể hiện ra bên ngoài thông qua thuộc tính (property) của class.

Các hành vi hay phương thức hoạt động của đối tượng được gọi là phương thức (method) của class.

Các trường, các thuộc tính, các phương thức, ... được gọi chung là các thành viên của lớp.

Dưới đây là một ví dụ về class trong C# - lớp Box:

class Box 
{
	// properties
	public double Length { get; set; }
	public double Breadth { get; set; }
	public double Height { get; set; }
  
	// default constructor
	public Box()
	{}
  
	// constructor with parameters
	public Box(double length, double breadth, double height)
	{
		Length = length;
		Breadth = breadth;
		Height = height;
	}
		
	// method
	public void Print()
	{
		Console.WriteLine("Length = {0}, Breadth = {1}, Height = {2}", Length, Breadth, Height);
	}
}

Các bạn có thể tìm hiểu chi tiết về class tại bài viết này:

Class trong C# | Comdy
Class trong C# là gì? Làm sao để định nghĩa và sử dụng class trong C#? Bài viết này sẽ hướng dẫn chi tiết cho bạn.

Phương thức (method)

Phương thức là các hành vi hay phương thức hoạt động của đối tượng. Phương thức trong C# là một tập các câu lệnh cùng nhau thực hiện một tác vụ nào đó.

Mỗi chương trình C# có ít nhất một lớp với một phương thức là Main.

Để sử dụng một phương thức trong C#, bạn cần:

  • Định nghĩa phương thức
  • Gọi phương thức

Dưới đây là một ví dụ về phương thức trong C# - phương thức Print của lớp Box:

class Box 
{
	// method
	public void Print()
	{
		Console.WriteLine("Print something");
	}
}

Xem thêm về phương thức trong C# ở bài viết dưới đây:

Phương thức trong C# | Comdy
Một phương thức là một nhóm lệnh cùng nhau thực hiện một tác vụ. Bài viết sẽ giúp bạn định nghĩa và sử dụng phương thức trong C#.

Trường (field)

Trường là các biến của class hay còn gọi là biến toàn cục. Trường được sử dụng để lưu trữ dữ liệu về các đặc điểm của đối tượng.

Trường nên sử dụng chỉ thị truy cập là private để nó chỉ có thể truy cập được ở bên trong class. Nếu muốn truy cập trường từ bên ngoài class chung ta sẽ sử dụng thuộc tính (property) sẽ được trình bày ở ngay phí dưới.

Một ví dụ về trường (field) trong C#:

class Box 
{
	// fields
	private double _length;
	private double _breadth;
	private double _height;
}

Quy ước đặt tên trường hoặc biến toàn cục trong C# là bắt đầu bằng dấu gạch dưới _, ký tự tiếp theo là chữ thường a-z.

Best practice: luôn sử dụng property để thay thế cho các trường public.

Thuộc tính (property)

Một thuộc tính là một thành viên của class, nó cung cấp một cơ chế linh hoạt để truy cập các trường (field) của class.

Trong thuộc tính có 2 phương thức đặc biệt được gọi là accessor đó là getset. Trong đó get sẽ trả về trường còn set sẽ gán giá trị cho trường.

Một ví dụ về thuộc tính trong C#:

class Box 
{
	// fields
	private double _length;
	private double _breadth;
	private double _height;
    
	// properties
	public double Length 
    { 
    	get
        {
        	return _length;
        }
        set
        {
        	_length = value;
        }
    }
    
	public double Breadth 
    { 
    	get
        {
        	return _breadth;
        }
        set
        {
        	_breadth = value;
        }
    }
    
	public double Height 
    { 
    	get
        {
        	return _height;
        }
        set
        {
        	_height = value;
        }
    }
}

Ngoài ra C# còn cung cấp auto-implemented property - một cách định nghĩa nhanh thuộc tính như sau:

class Box 
{
	// automatic properties
	public double Length { get; set; }
	public double Breadth { get; set; }
	public double Height { get; set; }
}

Khi biên dịch auto-implemented property, trình biên dịch sẽ tự động chuyển về dạng property thông thường với đầy đủ các field cho từng property.

Đối tượng (object)

Một đối tượng là một thực thể trong thế giới thực có các đặc điểm và các hành vi.

Trong C# thì đối tượng là thể hiện của một lớp. Mình thấy có nhiều bạn nhầm lẫn xem class là đối tượng - đây là nhầm lẫn rất tai hại. Mình đã đề cập ở trên, class đại diện cho một nhóm các đối tượng có chung những đặc điểm và hành vi. Khi bạn tạo thể hiện cho một class thì thể hiện đó mới là đối tượng.

Dưới đây là một ví dụ về cách tạo đối tượng:

using System;

namespace BoxApplication 
{
   class Box 
   {
   	  // properties
      public double Length { get; set; }
      public double Breadth { get; set; }
      public double Height { get; set; }
      
      // default constructor
      public Box()
      {}
      
      // constructor with parameters
      public Box(double length, double breadth, double height)
      {
      	  Length = length;
          Breadth = breadth;
          Height = height;
      }
            
      // methods
      public void Print()
      {
      	  Console.WriteLine("Length = {0}, Breadth = {1}, Height = {2}", Length, Breadth, Height);
      }
   }
   
   class Boxtester 
   {
      static void Main(string[] args) 
      {
         // box1 is an object
         Box box1 = new Box(6.0, 7.0, 5.0);
         
         box1.Print();         
         Console.ReadKey();
      }
   }
}

Bạn hãy để ý trong phương thức Main có đoạn code Box box = new Box(6.0, 7.0, 5.0); thì box chính là một đối tượng. Mỗi khi tạo một thể hiện của lớp ta có một đối tượng.

4 tính chất của lập trình hướng đối tượng

Lập trình hướng đối tượng có 4 tính chất quan trọng là:

  • Tính đóng gói (Encapsulation).
  • Tính kế thừa (Inheritance).
  • Tính đa hình (Polymorphism).
  • Tính trừu tượng (Abstraction).

4 tính chất này bạn sẽ gặp thường xuyên khi lập trình lẫn đi phỏng vấn. Dó đo việc hiểu và nắm vững 4 tính chất này rất quan trọng.

Tính đóng gói (Encapsulation)

Tính đóng gói là khả năng che giấu thông tin của đối tượng với môi trường bên ngoài. Việc cho phép môi trường bên ngoài tác động lên các dữ liệu nội tại của đối tượng hoàn toàn tùy thuộc vào người viết mã.

Tính chất này giúp đảm bảo sự toàn vẹn và bảo mật của đối tượng. Tính chất này được thể hiện thông qua các từ khóa chỉ định truy cập như: public, private, protected, internal, protected internal.

Tính đóng gói trong C# | Comdy
Tính đóng gói trong OOP là gì? Các ví dụ minh họa về tính đóng gói trong C#.

Tính kế thừa (Inheritance)

Tính kế thừa là khả năng tạo một lớp mới dựa trên một lớp có sẵn. Lớp có sẵn là lớp cha, lớp mới là lớp con và lớp con thừa kế các thành phần được định nghĩa ở lớp cha.

Dưới đây là ví dụ class Rectangle kế thừa class Shape:

using System;

namespace InheritanceApplication 
{
   class Shape 
   {
      public int Width { get; set; }
      public int Height { get; set; }
   }

   // Derived class
   class Rectangle : Shape 
   {
      public int GetArea() 
      { 
         return Width * Height; 
      }
   }
   
   class RectangleTester 
   {
      static void Main(string[] args) 
      {
         Rectangle rectangle = new Rectangle();

         rectangle.Width = 5;
         rectangle.Height = 7;

         // Print the area of the object.
         Console.WriteLine("Total area: {0}",  rectangle.GetArea());
         Console.ReadKey();
      }
   }
}

Khi đoạn mã trên được biên dịch và thực thi, nó tạo ra kết quả sau:

Total area: 35
Tính kế thừa trong C# | Comdy
Tính kế thừa (inheritance) trong lập trình hướng đối tượng (oop) là gì? Áp dụng tính kế thừa trong C# như thế nào?

Tính đa hình (Polymorphism)

Tính đa hình là khả năng một đối tượng có thể thực hiện một tác vụ theo nhiều cách khác nhau. Đa hình gồm 2 loại là đa hình tĩnh và đa hình động.

Đa hình tĩnh (overloading)

Đa hình tĩnh còn gọi là đa hình tại thời điểm biên dịch (compile time). C# cung cấp hai kỹ thuật để thực hiện đa hình tĩnh là:

  • Nạp chồng phương thức: là các phương thức có cùng tên nhưng khác nhau về số lượng và/hoặc kiểu dữ liệu của tham số truyền vào.
  • Nạp chồng toán tử: Bạn có thể định nghĩa lại hoặc nạp chồng hầu hết các toán tử tích hợp sẵn có trong C#. Nhờ đó, bạn có thể sử dụng các toán tử với các kiểu do người dùng định nghĩa.

Dưới đây là ví dụ về đa hình tĩnh trong C#:

using System;

namespace BoxApplication 
{
   class Rectangle 
   {
      public double Width { get; set; }
      public double Height { get; set; }
      
      public Rectangle(double width, double height)
      {
      	  Width = width;
          Height = height;
      }
      
      // overload method
      public void Resize(double sameSize)
      {
      	  Width = sameSize;
          Height = sameSize;
      }      
      public void Resize(int width, int height)
      {
      	  Width = width;
          Height = height;
      }      
      public void Resize(double width, double height)
      {
      	  Width = width;
          Height = height;
      }
      
      // overload operator
      public static Rectangle operator +(Rectangle a, Rectangle b) 
      {
         return new Rectangle(a.Width + b.Width, a.Height + b.Height);
      }
      public static Rectangle operator -(Rectangle a, Rectangle b) 
      {
         return new Rectangle(a.Width - b.Width, a.Height - b.Height);
      }
            
      // other methods
      public double GetArea()
      {
      	  return Width * Height;
      }
   }
   
   class RectangleTester 
   {
      static void Main(string[] args) 
      {
         Rectangle rectangle1 = new Rectangle(6.0, 7.0);
         Console.WriteLine("Area = {0} x {1} = {2}", rectangle1.Width, rectangle1.Height, rectangle1.GetArea());
         
         rectangle1.Resize(5.0);
         Console.WriteLine("Area = {0} x {1} = {2}", rectangle1.Width, rectangle1.Height, rectangle1.GetArea());
         
         Rectangle rectangle2 = new Rectangle(6.0, 4.0);
         
         // use operator +
         Rectangle rectangle3 = rectangle1 + rectangle2;
         Console.WriteLine("Area = {0} x {1} = {2}", rectangle3.Width, rectangle3.Height, rectangle3.GetArea());
                
         Console.ReadKey();
      }
   }
}

Kết quả khi biên dịch và chạy chương trình trên:

Area = 6 x 7 = 42
Area = 5 x 5 = 25
Area = 11 x 9 = 99

Đa hình động (overriding)

Đa hình động là đa hình lúc thực thi (runtime). C# cho phép bạn tạo các lớp trừu tượng (abstract class) được sử dụng để cung cấp triển khai lớp một phần của giao diện.

Việc thực hiện được hoàn thành khi một lớp dẫn xuất kế thừa từ nó. Các lớp trừu tượng chứa các phương thức trừu tượng (abstract method) sẽ được thực hiện bởi lớp dẫn xuất.

Dưới đây là ví dụ về đa hình động trong C#:

using System;

namespace PolymorphismApplication 
{
   abstract class Shape 
   {
      public abstract int GetArea();
   }
   
   class Rectangle : Shape 
   {
      public int Width { get; set; }
      public int Height { get; set; }
      
      public Rectangle(int width, int height) 
      {
         Width = width;
         Height = height;
      }
      
      public override int GetArea() 
      { 
         return Width * Height; 
      }
   }
   
   class RectangleTester 
   {
      static void Main(string[] args) 
      {
         Rectangle rectangle = new Rectangle(10, 7);
         Console.WriteLine("Area: {0}", rectangle.GetArea());
         Console.ReadKey();
      }
   }
}

Kết quả khi biên dịch và chạy chương trình trên:

Area: 70
Tính đa hình trong C# | Comdy
Tính đa hình (Polymorphism) trong lập trình hướng đối tượng (OOP) là gì? Các triển khai tính đa hình trong lập trình C#.

Tính trừu tượng (Abstraction)

Tính trừu tượng là khả năng ẩn chi tiết triển khai, chỉ cung cấp thông tin tính năng tới người dùng.

Tính trừu tượng được thể hiện qua abstract class và interface. Ví dụ ở phần đa hình động cũng có thể được sử dụng để làm ví dụ cho tính trưu tượng sử dụng abstract class và abstract method. Dưới đây là ví dụ về tính trừu tượng trong C# sử dụng interface:

using System;

namespace AbstractionApplication 
{
   interface IExportData
   {
      void Export();
   }
   
   class TextExport : IExportData 
   {
      public void Export()
      {
         Console.WriteLine("Export data to .txt file");
      }
   }
   
   class CsvExport : IExportData 
   {
      public void Export()
      {
         Console.WriteLine("Export data to .csv file");
      }
   }
   
   class Application
   {
      private readonly IExportData _exportData;
      
      public Application(IExportData exportData)
      {
         _exportData = exportData;
      }
      
      public void ExportData()
      {
         _exportData.Export();
      }
   }
   
   class RectangleTester 
   {
      static void Main(string[] args) 
      {
         Application app = new Application(new TextExport());
         app.ExportData();
         Console.ReadKey();
      }
   }
}

Kết quả khi biên dịch và chạy chương trình trên:

Export data to .txt file

Như các bạn thấy, lớp Application có chức năng ExportData, nó gọi phương thức Export của interface IExportData mà không cần quan tâm tới phương thức này làm gì.

Trên chương trình trên mình muốn xuất dữ liệu ra file txt nên khi khởi tạo thể hiện của class Application, mình chỉ cần truyền vào thể hiện của class TextExport là xong.

Nếu muốn xuất ra file csv thì mình chỉ cần thay thế bằng thể hiện của class CsvExport.

Tính trừu tượng trong C# | Comdy
Tính trừu tượng (Abstraction) trong lập trình hướng đối tượng (OOP) là gì? Áp dụng tính trừu tượng trong lập trình C# như thế nào?


Bài viết liên quan:

Hướng dẫn này sẽ giúp bạn tìm hiểu về đọc ghi file (File I/O) trong C# và sử dụng các lớp tiện ích để đọc ghi file.

Reflection trong C#

  • 6 min read

Reflection trong C# là gì? Ứng dụng của Reflection trong C#. Cách khai báo và sử dụng Reflection trong C#.

Attribute trong C#

  • 7 min read

Attribute trong C# là gì? Có những loại attribute nào trong C#? Làm sao để sử dụng attribute trong C#.