Giới thiệu OOP trong C#
Giới thiệu lập trình hướng đối tượng trong C#
Các class cho phép bạn tạo các loại tùy chỉnh, khép kín và có thể tái sử dụng của riêng bạn. Các giao diện cho phép bạn xác định một tập hợp các đầu vào và đầu ra mà các lớp phải triển khai để đảm bảo khả năng tương thích với người tiêu dùng của các lớp. Trong mô-đun này, bạn sẽ học cách sử dụng các giao diện và các lớp để xác định và tạo các loại tùy chỉnh, có thể sử dụng lại của riêng bạn.
Sau khi hoàn thành mô-đun này, bạn sẽ có thể:
- Tạo và khởi tạo các lớp.
- Tạo và thực hiện các giao diện.
Tạo lớp
Tạo lớp và thuộc tính
Trong Visual C#, bạn có thể xác định các loại tùy chỉnh của riêng mình bằng cách tạo các lớp. Là một cấu trúc lập trình, lớp là trung tâm của lập trình hướng đối tượng trong Visual C#. Nó cho phép bạn gói gọn các hành vi và đặc điểm của bất kỳ thực thể logic nào theo cách có thể sử dụng lại và mở rộng. Trong bài học này, bạn sẽ học cách tạo, sử dụng và kiểm tra các lớp trong các ứng dụng của riêng bạn.
Trong Visual C#, một lớp là một cấu trúc lập trình mà bạn có thể sử dụng để xác định các loại tùy chỉnh của riêng bạn. Khi bạn tạo một lớp, bạn đang tạo một kế hoạch chi tiết cho kiểu đó một cách hiệu quả. Lớp định nghĩa các hành vi và đặc điểm, hoặc các thuộc tính của lớp, được chia sẻ bởi tất cả các thể hiện của lớp. Bạn đại diện cho các hành vi và đặc điểm này bằng cách xác định các phương thức, trường, thuộc tính và sự kiện trong lớp của bạn.
Giả sử bạn tạo một lớp có tên là DrinksMachine.
Bạn sử dụng từ khóa lớp để khai báo một lớp, như trong ví dụ sau:
//Declaring a Class
public class DrinksMachine
{
// Methods, fields, properties, and events go here.
}
Từ khóa lớp được đi trước bởi một access modifier, chẳng hạn như public trong ví dụ trên, sẽ được mô tả trong phần Đóng gói.
Thêm thuộc tính vào một lớp
Bạn sẽ sử dụng các trường và thuộc tính để xác định các đặc tính của máy đồ uống, chẳng hạn như nhãn hiệu, kiểu máy, tuổi và khoảng thời gian phục vụ của máy. Bạn sẽ tạo ra các phương pháp để thể hiện những điều mà một máy đồ uống có thể làm, chẳng hạn như pha cà phê espresso hoặc pha cà phê cappuccino. Cuối cùng, bạn sẽ xác định các sự kiện để thể hiện các hành động có thể đòi hỏi sự chú ý của bạn, chẳng hạn như thay thế hạt cà phê khi máy hết hạt cà phê.
Trong lớp của bạn, bạn có thể thêm các phương thức, trường, thuộc tính và sự kiện để xác định các hành vi và đặc điểm của loại của bạn, như trong ví dụ sau:
// Defining Class Members
public class DrinksMachine
{
// The following statements define a property with a private field.
private string _location;
public string Location
{
get
{
return _location;
}
set
{
if (value != null)
_location = value;
}
}
// The following statements define properties.
public string Make {get; set;}
public string Model {get; set;}
// The following statements define methods.
public void MakeCappuccino()
{
// Method logic goes here.
}
public void MakeEspresso()
{
// Method logic goes here.
}
// The following statement defines an event. The delegate definition is not shown.
public event OutOfBeansHandler OutOfBeans;
}
Partial Classes
C# cũng có thể thực hiện các partial class. Các partial class cho phép bạn phân chia định nghĩa của lớp trên nhiều tệp nguồn. Sau đó, bạn biên dịch ứng dụng của mình, tất cả các phần được kết hợp thành một tệp duy nhất.
Các partial class hữu ích khi:
- Khi làm việc trên các dự án lớn, việc trải một lớp trên các tệp riêng biệt cho phép nhiều lập trình viên làm việc trên cùng một lớp cùng một lúc.
- Khi làm việc với nguồn được tạo tự động. Visual Studio sử dụng phương pháp này khi ứng dụng của bạn sử dụng Windows Forms, mã trình bao bọc dịch vụ Web, v.v. Microsoft khuyên bạn không nên sửa đổi mã được tạo tự động cho các thành phần này vì nó có thể bị ghi đè khi ứng dụng được biên dịch hoặc tệp dự án thay đổi. Thay vào đó, bạn có thể tạo một phần khác của lớp, dưới dạng một phần lớp có cùng tên, và thực hiện các bổ sung và chỉnh sửa của bạn ở đó.
Một ví dụ về việc sử dụng các partial class sau đây:
public partial class DrinksMachine
{
public void MakeCappuccino()
{
// Method logic goes here.
}
}
public partial class DrinksMachine
{
public void MakeEspresso()
{
// Method logic goes here.
}
}
Lưu ý: bạn cũng có thể phân chia cấu trúc và giao diện trên nhiều tệp nguồn.
Instantiating Classes
Instantiating Classes
Một lớp chỉ là một bản thiết kế cho một loại. Để sử dụng các hành vi và đặc điểm mà bạn xác định trong một lớp, bạn cần tạo các thể hiện của lớp. Một thể hiện của một lớp được gọi là một đối tượng.
Để tạo một thể hiện mới của một lớp, bạn sử dụng từ khóa mới, như trong ví dụ sau:
// Instantiating a Class
DrinksMachine dm = new DrinksMachine();
Khi bạn khởi tạo một lớp theo cách này, bạn thực sự đang làm hai việc:
- Bạn đang tạo một đối tượng mới trong bộ nhớ dựa trên loại DrinksMachine.
- Bạn đang tạo một tham chiếu đối tượng có tên là dm đề cập đến đối tượng DrinksMachine mới.
Khi bạn tạo tham chiếu đối tượng của mình, thay vì chỉ định rõ ràng loại DrinksMachine, bạn có thể cho phép trình biên dịch suy ra loại đối tượng tại thời điểm biên dịch. Điều này được gọi là suy luận loại. Để sử dụng suy luận kiểu, bạn tạo tham chiếu đối tượng của mình bằng cách sử dụng từ khóa var, như trong ví dụ sau:
// Instantiating a Class by Using Type Inference
var dm = new DrinksMachine();
Trong trường hợp này, trình biên dịch không biết trước loại biến dm. Khi biến dm được khởi tạo như một tham chiếu đến một đối tượng DrinksMachine, trình biên dịch sẽ suy ra rằng loại dm là DrinksMachine. Sử dụng suy luận kiểu theo cách này không gây ra thay đổi trong cách ứng dụng của bạn chạy, nó chỉ đơn giản là một phím tắt để bạn tránh gõ tên lớp hai lần. Trong một số trường hợp, suy luận kiểu có thể làm cho mã của bạn dễ đọc hơn, trong khi trong các trường hợp khác, nó có thể làm cho mã của bạn khó hiểu hơn. Theo nguyên tắc chung, hãy xem xét sử dụng suy luận kiểu khi loại biến hoàn toàn rõ ràng.
Sau khi bạn đã khởi tạo đối tượng của mình, bạn có thể sử dụng bất kỳ phương thức, trường, thuộc tính và sự kiện nào của thuộc tính mà bạn đã xác định trong lớp, như trong ví dụ sau:
// Using Object Members
var dm = new DrinksMachine();
dm.Make = "Fourth Coffee";
dm.Model = "Beancrusher 3000";
dm.Age = 2;
dm.MakeEspresso();
Cách tiếp cận này để gọi các thuộc tính trên một biến thể hiện được gọi là ký hiệu dấu chấm. Bạn nhập tên biến, theo sau là dấu chấm, theo sau là tên thuộc tính. Tính năng IntelliSense trong Visual Studio sẽ nhắc bạn với tên thuộc tính khi bạn nhập một khoảng thời gian sau một biến.
Giới thiệu đóng gói
Đóng gói trong C#
Thường được coi là trụ cột đầu tiên của lập trình hướng đối tượng, đóng gói có thể được sử dụng để mô tả khả năng truy cập của các thuộc tính thuộc một lớp hoặc cấu trúc.
C# cung cấp các sửa đổi truy cập và các thuộc tính để giúp thực hiện đóng gói trong các lớp của bạn. Trong khi một số người coi cấu hình khả năng truy cập này là khía cạnh duy nhất của đóng gói, thì một số khác cũng định nghĩa đóng gói là hành động bao gồm tất cả dữ liệu và hành vi cần thiết của lớp, trong định nghĩa lớp. Định nghĩa này có thể được kéo dài một chút trong C# khi sử dụng các partial class.
Xem lại chủ đề trên các lớp để xem tất cả các partial class là gì.
Private vs Public vs Protected
Private vs Public vs Protected vs Internal
Bảng sau đây thảo luận về các bộ sửa đổi truy cập có thể được áp dụng cho các thuộc tính lớp để kiểm soát cách chúng có thể được truy cập bằng mã khác trong ứng dụng. Đây là một phần của việc đóng gói bằng cách cho phép bạn hạn chế quyền truy cập vào các thuộc tính nơi có ý nghĩa.
Access modifier
|
Sự miêu tả
|
public
|
Loại có sẵn để mã chạy trong bất kỳ hội đồng tham chiếu đến hội đồng trong đó lớp được chứa.
|
internal
|
Loại có sẵn cho bất kỳ mã nào trong cùng một assembly, nhưng không có sẵn cho mã trong một assembly khác.
|
private
|
Loại chỉ có sẵn để mã trong lớp có chứa nó. Bạn chỉ có thể sử dụng access modifier riêng với các lớp lồng nhau. Đây là giá trị mặc định nếu bạn không chỉ định access modifier.
|
protected
|
Loại chỉ có thể truy cập trong lớp của nó và bởi các thể hiện của lớp dẫn xuất.
|
Truyền thống là tạo các trường dữ liệu riêng trong lớp để ngăn chặn thao tác trực tiếp các giá trị cho các trường đó và phơi bày các thuộc tính để cung cấp quyền truy cập vào các giá trị một cách gián tiếp. Các thuộc tính được gọi là truy cập hoặc getters và setters.
Sử dụng thuộc tính
Properties
Là một phần của đóng gói, bạn nên xem xét sử dụng các thuộc tính trong các tệp lớp của mình. Các thuộc tính cho phép bạn cho phép người dùng, của lớp, một phương tiện nhận và đặt giá trị cho các trường dữ liệu thuộc tính riêng trong lớp của bạn. Các thuộc tính cung cấp quyền truy cập vào dữ liệu thuộc tính trong khi ẩn mã triển khai hoặc xác minh mà bạn có thể đã viết bên trong thuộc tính. Ví dụ: bạn có thể muốn xác thực ngày sinh đã được thông qua để đảm bảo ngày đó ở định dạng phù hợp hoặc nó nằm trong phạm vi chính xác cho việc sử dụng ứng dụng. Đặt các biến thuộc tính của bạn thành private được gọi là một dạng ẩn dữ liệu. Một số người cũng coi việc ẩn dữ liệu là một phần của việc đóng gói.
Các thuộc tính cũng trình bày một "giao diện" cho lớp của bạn bằng cách đưa ra một cách để lấy hoặc đặt các thuộc tính của lớp mà người dùng có thể tin tưởng. Nói cách khác, nếu bạn có một tài sản được gọi là Ngày sinh public (ngày sinh), chấp nhận ngày sinh từ người dùng, bạn có thể triển khai mã xác thực trong bất kỳ cách nào bạn thấy phù hợp, chẳng hạn như sử dụng biểu thức thông thường để xác thực hoặc có thể một số logic tùy chỉnh để xác minh phạm vi ngày và sau đó thay đổi logic xác thực đó mà không ảnh hưởng đến việc sử dụng thuộc tính. Người dùng vẫn chỉ vượt qua trong một ngày sinh ở định dạng ngày.
Đoạn mã sau đây cho thấy một ví dụ về các thuộc tính được khai báo trong lớp DrinksMachine:
public class DrinksMachine
{
// private member variables
private int age;
private string make;
// public properties
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
public string Make
{
get
{
return make;
}
set
{
make = value;
}
}
// auto-implemented property
public string Model { get; set; }
// Constructors
public DrinksMachine(int age)
{
this.Age = age;
}
public DrinksMachine(string make, string model)
{
this.Make = make;
this.Model = model;
}
public DrinksMachine(int age, string make, string model)
{
this.Age = age;
this.Make = make;
this.Model = model;
}
}
Các thuộc tính là Age, Make và Model. Các thuộc tính này sẽ được hỗ trợ bởi các biến thuộc tính riêng gọi là age, make và model.
Các loại tài sản
Bạn có thể tạo hai loại thuộc tính cơ bản trong lớp C#. Chỉ đọc hoặc đọc-ghi: (Về mặt kỹ thuật bạn cũng có thể tạo một thuộc tính chỉ ghi nhưng điều đó không phổ biến.
- Một trình truy cập thuộc tính get được sử dụng để trả về giá trị thuộc tính
- Một bộ truy cập được sử dụng để gán một giá trị mới. (Bỏ qua thuộc tính này làm cho nó chỉ đọc)
- Một từ khóa giá trị được sử dụng để xác định "giá trị" được gán bởi bộ truy cập đã đặt.
- Các thuộc tính không thực hiện một bộ truy cập được thiết lập chỉ được đọc.
- Đối với các thuộc tính đơn giản không yêu cầu mã truy cập tùy chỉnh, hãy xem xét tùy chọn sử dụng các thuộc tính được triển khai tự động.
Các thuộc tính được triển khai tự động làm cho khai báo thuộc tính ngắn gọn hơn khi tạo các phương thức truy cập đơn giản (getter và setter). Họ cũng cho phép mã máy khách để tạo các đối tượng. Khi bạn khai báo một thuộc tính theo cách này, trình biên dịch sẽ tự động tạo một trường riêng, ẩn danh trong nền chỉ có thể được truy cập thông qua các bộ truy cập get và set.
Ví dụ sau đây cho thấy các thuộc tính được thực hiện tự động:
// Auto-implemented properties
public double TotalPurchases { get; set; }
public string Name { get; set; }
public int CustomerID { get; set; }```
Constructor
Sử dụng constructor
Nếu bạn xem chủ đề về Tạo lớp, bạn sẽ nhận thấy rằng, để khởi tạo một lớp, chúng tôi đã sử dụng dòng mã này:
DrinksMachine dm = new DrinksMachine();
Lưu ý cách này trông giống như cú pháp để gọi một phương thức. Điều này là do khi bạn khởi tạo một lớp, bạn thực sự đang gọi một phương thức đặc biệt gọi là hàm tạo. Hàm tạo là một phương thức trong lớp có cùng tên với lớp. Tuy nhiên, các hàm tạo không sử dụng giá trị trả về, thậm chí không có giá trị và chúng phải có cùng tên với tệp lớp.
Các hàm tạo thường được sử dụng để chỉ định các giá trị ban đầu hoặc mặc định cho các thuộc tính dữ liệu trong đối tượng mới, như được hiển thị trong ví dụ sau:
// Adding a Constructor
public class DrinksMachine
{
public int Age { get; set; }
public DrinksMachine()
{
Age = 0;
}
}
Hàm tạo không có tham số nào được gọi là hàm tạo mặc định. Hàm tạo này được gọi bất cứ khi nào ai đó khởi tạo lớp của bạn mà không cung cấp bất kỳ đối số nào. Nếu bạn không bao gồm một hàm tạo trong lớp của mình, trình biên dịch Visual C# sẽ tự động thêm một hàm tạo mặc định public trống vào lớp đã biên dịch của bạn.
Trong nhiều trường hợp, rất hữu ích cho người tiêu dùng của lớp bạn có thể chỉ định các giá trị ban đầu cho các thuộc tính dữ liệu khi lớp được khởi tạo. Ví dụ: khi ai đó tạo một phiên bản mới của DrinksMachine, có thể hữu ích nếu họ có thể chỉ định kiểu dáng và kiểu máy của máy cùng một lúc. Lớp của bạn có thể bao gồm nhiều nhà xây dựng với các chữ ký khác nhau cho phép người tiêu dùng cung cấp các kết hợp thông tin khác nhau khi họ khởi tạo lớp của bạn. Nhớ lại phương thức quá tải.
Ví dụ sau đây cho thấy cách thêm nhiều hàm tạo vào một lớp:
// Adding Multiple Constructors
public class DrinksMachine
{
public int Age { get; set; }
public string Make { get; set; }
public string Model { get; set; }
public DrinksMachine(int age)
{
this.Age = age;
}
public DrinksMachine(string make, string model)
{
this.Make = make;
this.Model = model;
}
public DrinksMachine(int age, string make, string model)
{
this.Age = age;
this.Make = make;
this.Model = model;
}
}
Người sử dụng lớp có thể sử dụng bất kỳ hàm tạo nào để tạo các thể hiện của lớp của bạn, tùy thuộc vào thông tin có sẵn cho họ tại thời điểm đó. Ví dụ:
// Calling Constructors
var dm1 = new DrinksMachine(2);
var dm2 = new DrinksMachine("Fourth Coffee", "BeanCrusher 3000");
var dm3 = new DrinksMachine(3, "Fourth Coffee", "BeanToaster Turbo");
إرسال تعليق