MonoDevelop (https://www.monodevelop.com/) là một open-source GNOME IDE (intergrated development environment) hỗ trợ lập trình đa ngôn ngữ (với mục tiêu ban đầu là .Net) trên các hệ điều hành Linux, Mac OS X và Windows.
Phiên bản hiện tại 7.6 (7.6.9.22) ra mắt vào đầu 2019.
Với giao diện tương tự Visual Studio, chúng ta có thể nhanh chóng làm quen và phát triển các dự án .Net trên những platform khác nhau.
Những chức năng chính
Multi-platform: Supports Linux, Windows and macOS.
Advanced Text Editing: Code completion support for C#, code templates, code folding.
Configurable workbench: Fully customizable window layouts, user defined key bindings, external tools.
Multiple language support: C#, F#, Visual Basic .NET, Vala.
Integrated Debugger: For debugging Mono and native applications.
Trong nội dung bài viết này, chúng ta cùng nhau tìm hiểu cách thức mà Java hỗ trợ việc thực hiện những thuật ngữ về Lập trình hướng đối tượng: (i) tính chất trừu tượng – abstraction; (ii) tính chất đa hình – polymorphism; (iii) lớp trừu tượng – abstract class; (iv) giao diện – interface.
Chúng ta thiết kế một chương trình nhỏ bao gồm các lớp và giao diện như sau:
Lớp trừu tượng: PhuongTienGiaoThong.
Các lớp đối tượng ở tầng dưới thứ hai: PhuongTienDuongBo; PhuongTienDuongThuy; PhuongTienDuongKhong.
Các lớp đối tượng ở tầng dưới cùng: Oto; XeMay; XeDap; TauThuy; Thuyen; MayBay; KhinhKhiCau; ThuyPhiCo.
Giao diện ở cấp cao nhất: HoatDong.
Giao diện ở tầng dưới: CoTheChay; CoTheBay; CoTheBoi.
Thiết kế Lớp trừu tượng
Bước 1.
Chúng ta thực hiện tạo Console Project trong MonoDevelop và đặt tên là CsharpOOPThirdProject.
Mặc định thì class Program.cs được tạo ra với phương thức Main().
Bước 2.
Chúng ta thực hiện tạo folder Object.
Chúng ta thực hiện tạo class PhuongTienGiaoThong.
Bước 3.
Chúng ta thực hiện tạo class PhuongTienDuongBo là một dẫn xuất của class PhuongTienGiaoThong.
Bước 4.
Chúng ta thực hiện tạo class PhuongTienDuongThuy là một dẫn xuất của class PhuongTienGiaoThong.
Bước 5.
Chúng ta thực hiện tạo class PhuongTienDuongKhong là một dẫn xuất của class PhuongTienGiaoThong.
Thiết kế Lớp đối tượng
Bước 1.
Chúng ta thực hiện tạo class Oto là một dẫn xuất của class PhuongTienDuongBo.
Bước 2.
Chúng ta thực hiện tạo class XeMay là một dẫn xuất của class PhuongTienDuongBo.
Bước 3.
Chúng ta thực hiện tạo class XeDap là một dẫn xuất của class PhuongTienDuongBo.
Bước 4.
Chúng ta thực hiện tạo class Thuyen là một dẫn xuất của class PhuongTienDuongThuy.
Bước 5.
Chúng ta thực hiện tạo class TauThuy là một dẫn xuất của class PhuongTienDuongThuy.
Bước 6.
Chúng ta thực hiện tạo class MayBay là một dẫn xuất của class PhuongTienDuongKhong.
Bước 7.
Chúng ta thực hiện tạo class KhinhKhiCau là một dẫn xuất của class PhuongTienDuongKhong.
Bước 8.
Chúng ta thực hiện tạo class ThuyPhiCo là một dẫn xuất của class PhuongTienGiaoThong.
Thiết kế Giao diện
Bước 1.
Chúng ta thực hiện tạo folder action.
Chúng ta thực hiện tạo interface ICoTheChay.
Những điểm cần chú ý:
Chúng ta sử dụng từ khóa interface đứng trước định nghĩa tên của giao diện.
Riêng đối với Csharp, một quy tắc phổ biến là thêm chữ cái I đứng trước tên dự kiến được đặt cho giao diện. Ở đây chúng ta có ICoTheChay.
Bước 2.
Chúng ta thực hiện tạo interface ICoTheBoi.
Bước 3.
Chúng ta thực hiện tạo interface ICoTheBay.
Bước 4.
Chúng ta thực hiện tạo interface IHoatDong là giao diện cơ sở của các giao diện: ICoTheChay; ICoTheBay; ICoTheBoi.
Thiết kế Tính đa hình thứ nhất
Bước 1.
Chúng ta đặc tả những đặc trưng của abstract class PhuongTienGiaoThong:
Thuộc tính: soLuongBanhXe; soLuongChoNgoi.
Những phương thức get / set.
Phương thức trừu tượng: GioiThieu().
Chú ý rằng những đặc trưng này sẽ được kế thừa lại hoàn toàn từ những lớp dẫn xuất của PhuongTienGiaoThong trên cây gia phả.
Bước 2.
Chúng ta đặc tả những đặc trưng của class PhuongTienDuongBo:
Thuộc tính. Đầu tiên là kế thừa những thuộc tính từ lớp cơ sở PhuongTienGiaoThong. Tiếp đến là định nghĩa thêm 01 thuộc tính riêng biệt: loaiDongCo.
Phương thức. Đầu tiên là kế thừa trọn vẹn những phương thức get / set đối với những thuộc tính được đặc tả ở lớp cơ sở PhuongTienGiaoThong. Tiếp đến là định nghĩa các phương thức get / set đối với thuộc tính loaiDongCo.
Kế thừa và đặc tả lại phương thức GioiThieu(). Đây là một phương thức được sử dụng trong ví dụ về tính chất đa hình.
Chú ý rằng những đặc trưng này sẽ được kế thừa lại hoàn toàn từ những lớp dẫn xuất của PhuongTienDuongBo trên cây gia phả.
Bước 3.
Chúng ta đặc tả những đặc trưng của classPhuongTienDuongKhong:
Thuộc tính. Đầu tiên là kế thừa những thuộc tính từ lớp cơ sở PhuongTienGiaoThong. Tiếp đến là định nghĩa thêm 02 thuộc tính riêng biệt: soLuongCanh; soLuongQuat.
Phương thức. Đầu tiên là kế thừa trọn vẹn những phương thức get / set đối với những thuộc tính được đặc tả ở lớp cơ sở PhuongTienGiaoThong. Tiếp đến là định nghĩa các phương thức get / set đối với thuộc tính soLuongCanh; soLuongQuat.
Kế thừa và đặc tả lại phương thức GioiThieu(). Đây là một phương thức được sử dụng trong ví dụ về tính chất đa hình.
Chú ý rằng những đặc trưng này sẽ được kế thừa lại hoàn toàn từ những lớp dẫn xuất của PhuongTienDuongKhong trên cây gia phả.
Bước 4.
Chúng ta đặc tả những đặc trưng của class PhuongTienDuongThuy:
Thuộc tính. Đầu tiên là kế thừa những thuộc tính từ lớp cơ sở PhuongTienGiaoThong. Tiếp đến là định nghĩa thêm 01 thuộc tính riêng biệt: loaiBanhLai.
Phương thức. Đầu tiên là kế thừa trọn vẹn những phương thức get / set đối với những thuộc tính được đặc tả ở lớp cơ sở PhuongTienGiaoThong. Tiếp đến là định nghĩa các phương thức get / set đối với thuộc tính loaiBanhLai.
Kế thừa và đặc tả lại phương thức GioiThieu(). Đây là một phương thức được sử dụng trong ví dụ về tính chất đa hình.
Chú ý rằng những đặc trưng này sẽ được kế thừa lại hoàn toàn từ những lớp dẫn xuất của PhuongTienDuongThuy trên cây gia phả.
Bước 5.
Chúng ta đặc tả những đặc trưng của class Oto:
Thuộc tính. Kế thừa trọn vẹn những thuộc tính từ lớp cơ sở PhuongTienDuongBo.
Phương thức. Kế thừa và đặc tả lại phương thức GioiThieu(). Đây là một phương thức được sử dụng trong ví dụ về tính chất đa hình.
Bước 6.
Chúng ta đặc tả những đặc trưng của class XeMay:
Thuộc tính. Kế thừa trọn vẹn những thuộc tính từ lớp cơ sở PhuongTienDuongBo.
Phương thức. Kế thừa và đặc tả lại phương thức GioiThieu(). Đây là một phương thức được sử dụng trong ví dụ về tính chất đa hình.
Bước 7.
Chúng ta đặc tả những đặc trưng của class XeDap:
Thuộc tính. Kế thừa trọn vẹn những thuộc tính từ lớp cơ sở PhuongTienDuongBo.
Phương thức. Kế thừa và đặc tả lại phương thức GioiThieu(). Đây là một phương thức được sử dụng trong ví dụ về tính chất đa hình.
Bước 8.
Chúng ta đặc tả những đặc trưng của class MayBay:
Thuộc tính. Kế thừa trọn vẹn những thuộc tính từ lớp cơ sở PhuongTienDuongKhong.
Phương thức. Kế thừa và đặc tả lại phương thức GioiThieu(). Đây là một phương thức được sử dụng trong ví dụ về tính chất đa hình.
Bước 9.
Chúng ta đặc tả những đặc trưng của class KhinhKhiCau:
Thuộc tính. Kế thừa trọn vẹn những thuộc tính từ lớp cơ sở PhuongTienDuongKhong.
Phương thức. Kế thừa và đặc tả lại phương thức GioiThieu(). Đây là một phương thức được sử dụng trong ví dụ về tính chất đa hình.
Bước 10.
Chúng ta đặc tả những đặc trưng của class TauThuy:
Thuộc tính. Kế thừa trọn vẹn những thuộc tính từ lớp cơ sở PhuongTienDuongThuy.
Phương thức. Kế thừa và đặc tả lại phương thức GioiThieu(). Đây là một phương thức được sử dụng trong ví dụ về tính chất đa hình.
Bước 11.
Chúng ta đặc tả những đặc trưng của class Thuyen:
Thuộc tính. Kế thừa trọn vẹn những thuộc tính từ lớp cơ sở PhuongTienDuongThuy.
Phương thức. Kế thừa và đặc tả lại phương thức GioiThieu(). Đây là một phương thức được sử dụng trong ví dụ về tính chất đa hình.
Bước 12.
Chúng ta đặc tả những đặc trưng của class ThuyPhiCo:
Thuộc tính. Đầu tiên là kế thừa những thuộc tính từ lớp cơ sở PhuongTienGiaoThong. Tiếp đến là định nghĩa thêm 02 thuộc tính riêng biệt: loaiBanhLai; soLuongCanh.
Phương thức. Đầu tiên là kế thừa trọn vẹn những phương thức get / set đối với những thuộc tính được đặc tả ở lớp cơ sở PhuongTienGiaoThong. Tiếp đến là định nghĩa các phương thức get / set đối với thuộc tính loaiBanhLai; soLuongCanh.
Kế thừa và đặc tả lại phương thức GioiThieu(). Đây là một phương thức được sử dụng trong ví dụ về tính chất đa hình.
Bước 13.
Chúng ta thực hiện thử nghiệm tính đa hình như bên dưới.
Chúng ta có thể nhận thấy những điểm rất rõ ở đây là:
Thực thể của đối tượng nào thì sẽ tự biết mình là ai.
Và như vậy sẽ tự thực hiện một cách chính xác phương thức GioiThieu() cũng như các phương thức get / set của các thuộc tính được đặc tả trong lớp trừu tượng PhuongTienGiaoThong.
Bước 14.
Kết quả thực hiện thử nghiệm đa hình thứ nhất như sau:
Thiết kế Tính đa hình thứ hai
Bước 1.
Chúng ta định nghĩa phương thức trừu tượng ThongBao() trong interface cơ sở IHoatDong.
Bước 2.
Chúng ta định nghĩa interface ICoTheChay kế thừa từ interface IHoatDong:
Kế thừa việc định nghĩa các phương thức trừu tượng từ interface IHoatDong.
Định nghĩa phương thức trừu tượng riêng biệt: Chay().
Bước 3.
Chúng ta định nghĩa interface ICoTheBoi kế thừa từ interface IHoatDong:
Kế thừa việc định nghĩa các phương thức trừu tượng từ interface IHoatDong.
Định nghĩa phương thức trừu tượng riêng biệt: Boi().
Bước 4.
Chúng ta định nghĩa interface ICoTheBay kế thừa từ interface IHoatDong:
Kế thừa việc định nghĩa các phương thức trừu tượng từ interface IHoatDong.
Định nghĩa phương thức trừu tượng riêng biệt: Bay().
Bước 5.
Chúng ta điều chỉnh class PhuongTienDuongBo để thuộc phạm vi ảnh hưởng của interface ICoTheChay:
Kế thừa và đặc tả lại toàn bộ các phương thức trừu tượng được định nghĩa trong interface IHoatDong cũng như ICoTheChay.
Bước 6.
Chúng ta điều chỉnh class PhuongTienDuongThuy để thuộc phạm vi ảnh hưởng của interface ICoTheBoi:
Kế thừa và đặc tả lại toàn bộ các phương thức trừu tượng được định nghĩa trong interface IHoatDong cũng như ICoTheBoi.
Bước 7.
Chúng ta điều chỉnh class PhuongTienDuongKhong để thuộc phạm vi ảnh hưởng của interface ICoTheBay:
Kế thừa và đặc tả lại toàn bộ các phương thức trừu tượng được định nghĩa trong interface IHoatDong cũng như ICoTheBay.
Bước 8.
Chúng ta điều chỉnh class ThuyPhiCo để thuộc phạm vi ảnh hưởng của interface ICoTheChay và ICoTheBoi.
Có thể thực thi cùng lúc nhiều interface. Có nghĩa rằng 1 lớp đối tượng có thể cùng lúc chịu ảnh hưởng của nhiều bộ quy tắc khác nhau.
Kế thừa và đặc tả lại toàn bộ các phương thức trừu tượng được định nghĩa trong interface IHoatDong cũng như ICoTheChay, ICoTheBoi.
Bước 9.
Chúng ta điều chỉnh lại ví dụ về tính đa hình như bên dưới.
Những điểm cần chú ý:
Những đối tượng thuộc phạm vi ảnh hưởng của những interface khác nhau sẽ thực thi những phương thức đặc trưng riêng của từng interface.
Chúng ta cần kiểm tra một chút để biết thực thể của đối tượng nào bằng cách sử dụng từ khóa is.
Tổng kết
Trong bài này, chúng ta đã cùng nhau tìm hiểu sự hỗ trợ của Csharp trong việc thực hiện tính chất đa hình trong Lập trình hướng đối tượng.
Hi vọng với bài này thì chúng ta đã có cái nhìn tổng quát hơn về cả 04 tính chất đặc trưng nhất của Lập trình hướng đối tượng.
Trong nội dung bài này, chúng ta cùng nhau tìm hiểu tính chất kế thừa trong tư duy Lập trình hướng đối tượng.
Chúng ta sẽ thử nghiệm tính chất này qua một ví dụ đơn giản về hình chữ nhật và hình vuông.
Nhắc lại đặc điểm của tính chất kế thừa như sau:
Đặc tính này cho phép một đối tượng có thể có sẵn các đặc tính mà đối tượng khác đã có thông qua kế thừa.
Điều này cho phép các đối tượng chia sẻ hay mở rộng các đặc tính sẵn có mà không phải tiến hành định nghĩa lại.
Xây dựng lớp đối tượng HinhChuNhat
Bước 1.
Chúng ta tạo một Console Project trong MonoDevelop và đặt tên là CsharpOOPSecondProject.
Mặc định thì class Program.cs trong namespace CsharpOOPSecondProject với phương thức Main() được tạo ra.
Bước 2.
Chúng ta tạo class HinhChuNhat.cs và điều chỉnh namespace Object.
Bước 3.
Chúng ta định nghĩa 02 thuộc tính cơ bản của một hình chữ nhật:
Những kỹ thuật lập trình cần chú ý:
Như đã trình bày ở phần Giới thiệu về Tính chất kế thừa, một lớp đối tượng có thể được kế thừa và mở rộng những thuộc tính và phương thức nào đó của lớp cơ sở.
Trong ví dụ ở đây, chúng ta đều biết rằng mỗi hình vuông đều là một hình chữ nhật và đều có 02 thuộc tính là chiều dài và chiều rộng. Do vậy chúng ta định nghĩa 02 thuộc tính của class HinhChuNhat theo cách mà có thể được kế thừa.
Chúng ta sử dụng từ khóa protected được Csharp cung cấp. Từ khóa này quy định một thuộc tính hoặc một phương thức là ẩn, cho phép kế thừa và chỉ được truy xuất bên trong một lớp và những lớp con của nó.
Bước 4.
Chúng ta định nghĩa các constructor cho lớp đối tượng:
Bước 5.
Chúng ta định nghĩa các phương thức đặc biệt truy xuất và điều chỉnh dữ liệu, được gọi là các properties với getter và setter:
Những kỹ thuật lập trình cần chú ý:
Chúng ta biết rằng mỗi hình vuông là một hình chữ nhật đặc biệt trong đó chiều dài và chiều rộng là bằng nhau (nên được gọi chung là cạnh). Do vậy trong ví dụ ở đây, chúng ta sẽ cần kế thừa, mở rộng và điều chỉnh setter của propertiesChieuDai và ChieuRong.
Trước tiên, đối với phương thức ở lớp cơ sở mà dự kiến sẽ được kế thừa, mở rộng và điều chỉnh, chúng ta sử dụng từ khóa virtual do Csharp cung cấp.
Bước 6.
Chúng ta định nghĩa các phương thức tính chu vi, diện tích và đường chéo hình chữ nhật:
Những kỹ thuật lập trình cần chú ý:
Có lẽ cũng cần nhắc lại một chút về công thức tính đường chéo ở đây: (đường_chéo)^2 = (chiều_dài)^2 + (chiều_rộng)^2.
Kết quả của công thức tính đường chéo là một số thực có phần thập phân. Do vậy chúng ta sử dụng kiểu dữ liệu float hoặc double do Csharp cung cấp để đặc tả kết quả trả về này.
Tương tự như setter của properties ChieuDai và ChieuRong, chúng ta có thể có nhu cầu kế thừa, mở rộng và điều chỉnh phương thức TinhDuongCheo() trong class HinhVuong. Do vậy chúng ta sử dụng từ khóa virtual ở đây.
Xây dựng lớp đối tượng HinhVuong
Bước 1.
Chúng ta tạo class HinhVuong.cs.
Những kỹ thuật lập trình cần chú ý:
Trong ví dụ ở đây, chúng ta sử dụng ký hiệu “:” phân tách giữa hai lớp để đặc tả sự kế thừa.
Như đã mô tả ở trên về định nghĩa 02 thuộc tính chieuDai và chieuRong. Chúng ta không cần định nghĩa lại 02 thuộc tính này trong class HinhVuong mà kế thừa từ HinhChuNhat.
Nếu phân tích theo một hướng khác, chúng ta có thể định nghĩa thuộc tính canh cho class HinhVuong. Như vậy thì nên thiết lập lại phạm vi là private cho 02 thuộc tính của class HinhChuNhat để không cho kế thừa.
Bước 2.
Chúng ta định nghĩa các constructor cho lớp đối tượng:
Những kỹ thuật lập trình cần chú ý:
Chúng ta định nghĩa 02 constructor cho class HinhVuong tương ứng với 02 constructor cho class HinhChuNhat.
Trong từng constructor cho class HinhVuong, chúng ta có thể thực thi các tác vụ khởi tạo giá trị mặc định nào đó cho riêng class HinhVuong.
Nếu chúng ta muốn gọi constructor của lớp cơ sở để thực thi, ví dụ ở đây là class HinhChuNhat, chúng ta sử dụng phương thức base() và truyền tham số tương ứng với từng constructor cho class HinhChuNhat.
Bước 3.
Chúng ta thực hiện kế thừa và điều chỉnh phương thức setter:
Những kỹ thuật lập trình cần chú ý:
Thuật ngữ để kế thừa, điều chỉnh và mở rộng một phương thức của lớp cơ sở được gọi là nạp chồng hàm (override). Csharp cung cấp một kiểu từ khóa override để đặc tả một phương thức như vậy trong lớp dẫn xuất.
Trong ví dụ ở đây, chúng ta cần điều chỉnh phương thức setter vì trong hình vuông thì chiều dài và chiều rộng là bằng nhau (nên được gọi chung là cạnh).
Cú pháp để thực hiện kế thừa, mở rộng và điều chỉnh properties được thể hiện rõ nét trong ví dụ này. Chúng ta chỉ cần áp dụng tương tự cho những bài tập khác.
Chú ý rằng chúng ta sử dụng phương thức base để gọi đến properties đã được định nghĩa ở lớp dẫn xuất.
Bước 4.
Chúng ta thực hiện kế thừa và điều chỉnh phương thức TinhDuongCheo():
Những kỹ thuật lập trình cần chú ý:
Chúng ta không cần điều chỉnh các phương thức về tính chu vi và diện tích vì thực ra công thức là như nhau. Do vậy trong class HinhVuong chúng ta không đặc tả lại mà kế thừa hoàn toàn từ class HinhChuNhat đối với 02 phương thức TinhChuVi() và TinhDienTich().
Đối với tác vụ tính đường chéo, chúng ta có 03 lựa chọn. Lựa chọn thứ nhất. Tương tự như 02 phương thức TinhChuVi() và TinhDienTich(), chúng ta không đặc tả lại mà kế thừa hoàn toàn từ class HinhChuNhat. Lựa chọn thứ hai. Chúng ta thực hiện kế thừa lại với từ khóa override nhưng sẽ gọi phương thức của class HinhChuNhat để thực thi: base.TinhDuongCheo(). Lựa chọn thứ ba. Chúng ta thực thi theo công thức thu gọn dành riêng cho hình vuông: (đường_chéo) ^2 = 2 * (cạnh)^2.
Thử nghiệm chương trình
Bước 1.
Chúng ta thực hiện thử nghiệm tạo mới 01 hình chữ nhật, 02 hình vuông và tính chu vi, diện tích, đường chéo:
Những kỹ thuật lập trình cần chú ý:
Đối với việc khởi tạo một đối tượng hình vuông. Chúng ta có 02 sự lựa chọn: (i) HinhChuNhat hinhVuong = new HinhVuong(); (ii) HinhVuong hinhVuong = new HinhVuong(). Thực ra cả 02 sự lựa chọn này là như nhau vì class HinhVuong là lớp dẫn xuất của lớp cơ sở class HinhChuNhat.
Chúng ta được khuyến khích là áp dụng sự lựa chọn thứ nhất như trong ví dụ ở đây. Lý do chính là để hiểu rõ hơn về tính chất trừu tượng và đa hình của Lập trình hướng đối tượng mà sẽ được trao đổi kỹ hơn trong các bài tiếp theo.
Bước 2.
Chúng ta thực thi toàn bộ project để kiểm tra kết quả thử nghiệm:
Tổng kết
Trong bài này, chúng ta đã cùng nhau tìm hiểu tính chất kế thừa trong Lập trình hướng đối tượng.
Chúng ta đã cùng nhau thực hiện một ví dụ nhỏ về tính chất kế thừa với ngôn ngữ Csharp.
Trong các bài tiếp theo, chúng ta sẽ tiếp tục tìm hiểu những kiến thức khác xung quanh lập trình hướng đối tượng.
Lập trình hướng đối tượng (tiếng Anh: Object-oriented programming, viết tắt: OOP) là một mô hình kiến trúc lập trình dựa trên khái niệm “công nghệ đối tượng”, mà trong đó, đối tượng chứa đựng các dữ liệu: (i) thuộc tính của đối tượng; (ii) phương thức để thực thi các hành động của đối tượng.
OOP được xem là giúp tăng năng suất, đơn giản hóa độ phức tạp khi bảo trì cũng như mở rộng phần mềm bằng cách cho phép lập trình viên tập trung vào các đối tượng phần mềm ở bậc cao hơn.
Một số khái niệm cơ bản
Khái niệm đầu tiên là “đối tượng”, được hiểu như là 1 thực thể: người, vật hoặc 1 bảng dữ liệu, . . .
Một đối tượng bao gồm 2 thông tin chính:
Thuộc tính. Là những thông tin, đặc điểm của đối tượng. Ví dụ: một hình chữ nhật sẽ có chiều dài, chiều rộng, . . .
Phương thức. Là những thao tác, hành động mà đối tượng đó có thể thực hiện. Ví dụ: một hình chữ nhật sẽ có thao tác tính chu vi, diện tích, . . .
Khái niệm thứ hai là “lớp”, được hiểu như là một khuôn mẫu mà từng đối tượng là một thể hiện cụ thể dựa trên khuôn mẫu đó.
Ví dụ một lớp hình chữ nhật sẽ định nghĩa: (i) các thuộc tính chiều dài / chiều rộng; (ii) các phương thức tính chu vi, tính diện tích. Còn từng đối tượng hình chữ nhật sẽ có số đo cụ thể cho từng thuộc tính cũng như chu vi và diện tích riêng.
Các tính chất của lập trình hướng đối tượng
Tính đóng gói (encapsulation) và che giấu thông tin (information hiding):
Tính chất này không cho phép tác nhân bên ngoài thay đổi trạng thái nội tại của một đối tượng.
Chỉ có các phương thức nội tại của đối tượng cho phép thay đổi trạng thái của nó.
Đây là tính chất đảm bảo sự toàn vẹn của đối tượng.
Tính trừu tượng (abstraction):
Là phương pháp trừu tượng hóa định nghĩa lên những hành động, tính chất của loại đối tượng nào đó cần phải có.
Mỗi đối tượng có thể hoàn tất các công việc một cách nội bộ, báo cáo, thay đổi trạng thái của nó và liên lạc với các đối tượng khác mà không cần cho biết làm cách nào đối tượng tiến hành được các thao tác.
Tính chất này thường được gọi là sự trừu tượng của dữ liệu.
Tính kế thừa (inheritance):
Đặc tính này cho phép một đối tượng có thể có sẵn các đặc tính mà đối tượng khác đã có thông qua kế thừa.
Điều này cho phép các đối tượng chia sẻ hay mở rộng các đặc tính sẵn có mà không phải tiến hành định nghĩa lại.
Tính đa hình (polymorphism):
Thể hiện thông qua việc gửi các thông điệp (message).
Việc gửi các thông điệp này có thể so sánh như việc gọi các phương thức bên trong của một đối tượng.
Các phương thức dùng trả lời cho một thông điệp sẽ tùy theo đối tượng mà thông điệp đó được gửi tới sẽ có phản ứng khác nhau.
Xây dựng lớp đối tượng độc lập
Trong nội dung bài này, chúng ta cùng tìm hiểu cách xây dựng một lớp đối tượng độc lập cùng với tính chất đóng gói (encapsulation) bằng ngôn ngữ Csharp.
Bước 1.
Chúng ta tạo một Console Project trong MonoDevelop và đặt tên là CsharpOOPFirstProject.
Mặc định thì class Program.cs trong namespace CsharpOOPFirstProject với phương thức Main() được tạo ra.
Bước 2.
Chúng ta tạo class HinhChuNhat.cs và điều chỉnh namespace Object.
Những kỹ thuật lập trình cần chú ý:
Như đã trình bày ở phần Giới thiệu về Tính đóng gói (encapsulation) và che giấu thông tin (information hiding). Mỗi namespace có thể được xem như là một hình thức để gom nhóm các lớp đối tượng có cùng chung những đặc điểm nào đó.
Là một ngôn ngữ lập trình hướng đối tượng hoàn toàn, Csharp yêu cầu tất cả các lớp được định nghĩa phải thuộc một namespace nào đó.
Trong ví dụ hiện tại, chúng ta có thể đặt tên namespace là Object (nghĩa là đối tượng nói chung) hoặc Shape (nghĩa là hình vẽ nói chung).
Bước 3.
Chúng ta định nghĩa 02 thuộc tính cơ bản của một hình chữ nhật:
Những kỹ thuật lập trình cần chú ý:
Như đã trình bày ở phần Giới thiệu về đặc trưng của một lớp đối tượng. Các thuộc tính nội tại của một đối tượng thì chỉ có thể được trông thấy và điều chỉnh bởi các phương thức nội tại của chính đối tượng đó.
Chúng ta sử dụng từ khóa private được Csharp cung cấp. Thuộc tính này quy định một thuộc tính hoặc một phương thức là ẩn bên trong một lớp.
Bước 4.
Chúng ta định nghĩa các constructor cho lớp đối tượng:
Những kỹ thuật lập trình cần chú ý:
Constructor là một dạng đặc biệt của phương thức, được sử dụng để khởi tạo các đối tượng.
Constructor được gọi tại thời điểm tạo đối tượng. Nó khởi tạo các giá trị để cung cấp dữ liệu cho các đối tượng, đó là lý do tại sao nó được gọi là constructor.
Chú ý trong Csharp: (i) tên của constructor phải trùng với tên của lớp; (ii) constructor không có kiểu trả về.
Có 02 kiểu constructor: (i) kiểu mặc định không có tham số truyền vào; (ii) kiểu có tham số.
Từ khóa this giúp chúng ta liên hệ đến thuộc tính hoặc phương thức nội tại của lớp đối tượng. Chúng ta sử dụng từ khóa này để phân biệt khi muốn định nghĩa các biến có cùng tên với các thuộc tính hoặc phương thức nội tại của lớp.
Bước 5.
Chúng ta định nghĩa các phương thức đặc biệt truy xuất và điều chỉnh dữ liệu, được gọi là các properties với getter và setter:
Những kỹ thuật lập trình cần chú ý:
Csharp cung cấp một hình thức được gọi là properties để định nghĩa kiểu dữ liệu riêng cho việc truy xuất và điều chỉnh thông tin của các thuộc tính nội tại. Chúng ta có thể sử dụng các properties này như là một thuộc tính của đối tượng.
Theo quy tắc chung, tên của từng properties nên được đặt trùng với tên của thuộc tính, chỉ có một điểm khác là chữ cái đầu viết hoa.
Mỗi thuộc tính nên được theo kèm bởi một properties với cặp get / set tương ứng.
Bước 6.
Chúng ta định nghĩa các phương thức tính chu vi và diện tích hình chữ nhật:
Bước 7.
Chúng ta thực hiện thử nghiệm tạo mới 02 hình chữ nhật và tính chu vi, diện tích:
Những kỹ thuật lập trình cần chú ý:
Để truy xuất đến những lớp đối tượng ở một namespace khác, chúng ta sử dụng từ khóa using. Ví dụ ở đây là using object.
Chúng ta khởi tạo một đối tượng thực bằng cách gọi constructor của lớp đối tượng với toán tử new. Với constructor được gọi thì thuộc tính nội tại sẽ được khởi tạo với giá trị mặc định của nó.
Ví dụ ở đây. Đối tượng hinhChuNhatA được khởi tạo với constructor mặc định không có tham số. Như vậy sẽ sử dụng properties để điều chỉnh thông tin cho thuộc tính của đối tượng. Đối tượng hinhChuNhatB được khởi tạo với constructor có tham số.
Bước 8.
Chúng ta thực thi toàn bộ project để kiểm tra kết quả thử nghiệm:
Tổng kết
Trong bài này, chúng ta đã cùng nhau tìm hiểu những kiến thức cơ bản về lớp đối tượng cũng như những tính chất về lập trình hướng đối tượng.
Chúng ta đã cùng nhau thực hiện một ví dụ nhỏ về lớp đối tượng với ngôn ngữ Csharp.
Trong các bài tiếp theo, chúng ta sẽ tiếp tục tìm hiểu những kiến thức khác xung quanh lập trình hướng đối tượng.
Trong nội dung bài này, chúng ta cùng nhau tìm hiểu một số kiến thức cơ bản xung quanh số nguyên tố.
Một số tự nhiên p (p > 1) là số nguyên tố nếu p có đúng 02 ước số là 1 và p.
Ví dụ các số nguyên tố: 2, 3, 5, 7, 11, 13, 17, 19, 23, …
Chúng ta cùng nhau thực hiện một số giải thuật cơ bản bằng ngôn ngữ Csharp để giải quyết các bài toán con sau:
Kiểm tra xem một số tự nhiên n có phải là số nguyên tố hay không.
Liệt kê các số nguyên tố nằm trong phạm vi [1, n].
Kiểm tra tính nguyên tố
Giải thuật thứ nhất
Ý tưởng giải thuật
Chúng ta kiểm tra xem có tồn tại một số nguyên k (2 ≤ k ≤ n – 1) mà k là ước của n (n chia hết cho k) thì n không phải là số nguyên tố, ngược lại n là số nguyên tố.
Trên thực tế ta chỉ cần kiểm tra k từ 2 đến √n là được.
Bước 1.
Chúng ta tạo một Console Project trong MonoDevelop và đặt tên là CsharpAlgorithmBasicProject.
Mặc định thì class Program.cs với MainClass và phương thức Main() được tạo ra.
Bước 2.
Chúng ta tạo class SoNguyenTo.cs và điều chỉnh namespace Algorithm.
Chúng ta tiếp tục tạo phương thức KiemTraSNTFirst() với:
Tham số cho phương thức này là một số tự nhiên n.
Kiểu dữ liệu trả về là bool. Phương thức trả về kết quả: (i) true nếu n là số nguyên tố; (ii) false nếu ngược lại.
Bước 3.
Chúng ta thực hiện giải thuật bằng ngôn ngữ Csharp như sau:
Những kỹ thuật lập trình cần chú ý:
Phương thức để tính căn bậc 2 của một số tự nhiên n là Math.Sqrt().
Phương thức để lấy phần nguyên của một số thập phân là Math.Round().
Thư viện Math định nghĩa các phương thức dùng tính toán các biểu thức toán học cơ bản. Các phương thức này đều là tĩnh nên được gọi trực tiếp bằng cú pháp Math.phương_thức().
Bước 4.
Chúng ta thực hiện thử nghiệm phương thức KiemTraSNTFirst() trong class Program.cs như sau:
Bước 5.
Chúng ta thực thi toàn bộ project để kiểm tra kết quả thử nghiệm:
Giải thuật thứ hai
Ý tưởng giải thuật
Chúng ta sẽ chỉ kiểm tra các số k có tính chất giống với một trong hai tính chất cơ bản sau của số nguyên tố:
Trừ số 2 và các số nguyên tố là số lẻ.
Trừ số 2, 3, các số nguyên tố có dạng 6k ± 1 (vì số có dạng 6k ± 2 thì chia hết cho 2, số có dạng 6k ± 3 thì chia hết cho 3).
Bước 1.
Chúng ta thực hiện giải thuật bằng ngôn ngữ Csharp như sau:
Bước 2.
Chúng ta thực hiện thử nghiệm phương thức KiemTraSNTSecond() trong class Program.cs như sau:
Bước 3.
Chúng ta thực thi toàn bộ project để kiểm tra kết quả thử nghiệm:
Liệt kê các số nguyên tố trong đoạn [1, N]
Giải thuật thứ nhất
Ý tưởng giải thuật
Chúng ta lần lượt xem xét các số m trong đoạn [1, n], rồi kiểm tra tính nguyên tố của m.
Bước 1.
Chúng ta thực hiện giải thuật bằng ngôn ngữ Csharp như sau:
Những kỹ thuật lập trình cần chú ý:
Csharp cung cấp cho chúng ta một số kiểu dữ liệu lưu trữ tập hợp các phần tử bên cạnh kiểu dữ liệu mảng. Chúng ta thường sử dụng một số dạng sau: (i) List để lưu trữ không giới hạn các phần tử có thể trùng nhau; (ii) HashSet để lưu trữ không giới hạn các phần tử không trùng nhau; (ii) Dictionary để lưu trữ không giới hạn các phần tử theo từng cặp <từ_khóa, giá_trị>. Chúng ta sẽ dần tìm hiểu cụ thể hơn trong những bài tiếp theo.
Csharp cung cấp một phương pháp để xác định kiểu dữ liệu cho toàn bộ các phần tử trong danh sách: định nghĩa ngay từ ban đầu kiểu dữ liệu trong cặp dấu <>. Ví dụ ở đây là List<int>.
Với tham số là một biến riêng lẻ, giá trị của tham số sẽ không bị thay đổi sau khi thực hiện phương thức.
Với tham số là một danh sách, các phần tử của danh sách có thể bị thay đổi sau khi thực hiện phương thức.
Bước 2.
Chúng ta thực hiện thử nghiệm phương thức LietKeSNTFirst() trong class Program.cs như sau:
Bước 3.
Chúng ta thực thi toàn bộ project để kiểm tra kết quả thử nghiệm:
Giải thuật thứ hai
Ý tưởng giải thuật
Chúng ta áp dụng sàng Eratosthenes để tìm các số nguyên tố nhỏ hơn hoặc bằng số tự nhiên n:
Bước 1: Tạo 1 danh sách các số tự nhiên liên tiếp từ 2 đến n: (2, 3, 4,…, n).
Bước 2: Giả sử tất cả các số trong danh sách đều là số nguyên tố. Trong đó, p = 2 là số nguyên tố đầu tiên.
Bước 3: Tất cả các bội số của p: 2p, 3p, 4p,… sẽ bị đánh dấu vì không phải là số nguyên tố.
Bước 4: Tìm các số còn lại trong danh sách mà chưa bị đánh dấu và phải lớn hơn p. Nếu không còn số nào, dừng tìm kiếm. Ngược lại, gán cho p giá trị bằng số nguyên tố tiếp theo và quay lại bước 3.
Khi giải thuật kết thúc, tất các số chưa bị đánh dấu trong danh sách là các số nguyên tố cần tìm.
Bước 1.
Chúng ta thực hiện giải thuật bằng ngôn ngữ Csharp như sau:
Bước 2.
Chúng ta thực hiện thử nghiệm phương thức LietKeSNTSecond() trong class Program.cs như sau:
Bước 3.
Chúng ta thực thi toàn bộ project để kiểm tra kết quả thử nghiệm:
Tổng kết
Trong bài này, chúng ta đã cùng nhau tìm hiểu một số giải thuật cơ bản xung quanh số nguyên tố và thực hiện bằng ngôn ngữ Csharp.
Hy vọng rằng chúng ta có thể áp dụng phù hợp những kỹ thuật và chức năng này cho những bài tiếp theo.
Tiếp theo nội dung của bài trước, trong bài này chúng ta cùng nhau tìm hiểu một số kỹ thuật lập trình cơ bản trong C# đồng thời tìm hiểu một số chức năng cần thiết trong MonoDevelop.
Chúng ta thực hiện tiếp Yêu cầu 2 và Yêu cầu 3 của bài toán cơ bản thông qua những kỹ thuật về lập trình:
Câu lệnh điều khiển và rẽ nhánh.
Các toán tử cơ bản.
Định nghĩa và thực thi các phương thức.
Chúng ta cũng tìm hiểu phương pháp debug trong MonoDevelop để kiểm tra từng câu lệnh cũng như bắt lỗi.
Những kỹ thuật được trình bày sẽ mang tính phổ quát và độc lập ngôn ngữ lập trình. Điều đó có nghĩa rằng chúng ta có thể áp dụng ý tưởng từ các kỹ thuật này khi tìm hiểu các ngôn ngữ khác như PHP / Java / Python.
Xây dựng phương thức trong C#
Một phương thức trong C# là một khối các câu lệnh có tên và có thể được thực thi bằng cách gọi từ một nơi khác trong chương trình.
Chú ý rằng một phương thức phải được định nghĩa bên trong một class. Điều này sẽ được thảo luận kỹ hơn trong các bài tiếp theo về lập trình hướng đối tượng.
Cấu trúc cú pháp của một phương thức như sau:
phạm_vi_truy_cập [static] kiểu_dữ_liệu_trả_về tên_phương_thức (danh_sách_tham_số) { // Thực hiện công việc }
Chúng ta có hai dạng phương thức chính:
Dạng phương thức không trả về kết quả.
Dạng phương thức có trả về kết quả.
Xây dựng phương thức không trả về kết quả
Bước 1.
Chúng ta thực hiện việc tạo một Console Project mới trong MonoDevelop.
Màn hình giao diện MonoDevelop hiển thị nội dung mặc của class MainClass.cs hiện ra.
Bước 2.
Chúng ta lựa chọn tạo class mới bằng cách nhấn chuột phải vào tên của project trong phân vùng màn hình bên trái.
Chúng ta lựa chọn chức năng Add → New File …
Bước 3.
Màn hình New File hiện ra.
Chúng ta lựa chọn mục General trong phân vùng màn hình bên trái.
Chúng ta lựa chọn chức năng Empty Class trong phân vùng màn hình ở giữa.
Chúng ta nhập thông tin như sau:
Name: BaiCoBan
Chú ý rằng, theo quy định trong C# thì chữ cái đầu của file phải được viết hoa.
Chúng ta lựa chọn nút New để thực hiện.
Bước 4.
Hệ thống thực hiện việc tạo mới class BaiCoBan.cs.
Chúng ta điều chỉnh thông tin thứ nhất như sau:
namespace BaiTap
Về cơ bản thì namespace trong C# có ý nghĩa tương tự như package trong Java. Nội dung về namespace và class sẽ được thảo luận sâu hơn trong các bài tiếp theo về lập trình hướng đối tượng.
Chúng ta tiếp tục tạo phương thức:
public void TinhTong() {}
Những điểm cần chú ý ở đây:
Theo quy định trong C# thì chữ cái đầu của phương thức phải được viết hoa.
Về nguyên tắc chung khi viết mã nguồn C#, cặp dấu {} nên để bên dưới phần định nghĩa phương thức. Không giống như Java là dấu { để ngay bên phải phần định nghĩa phương thức.
Từ khóa thứ nhất cho biết phạm vi được phép truy xuất đến phương thức này. Ở đây chúng ta sử dụng từ khóa public. Từ khóa này cho biết phạm vi được truy xuất đến phương thức này là trên toàn bộ project. Điều này sẽ được thảo luận kỹ hơn trong các bài tiếp theo về lập trình hướng đối tượng.
Từ khóa thứ hai cho biết kiểu dữ liệu của kết quả được trả về sau khi thực thi phương thức. Ở đây chúng ta sử dụng từ khóa void. Từ khóa này cho biết phương thức này không trả về kết quả mà chỉ thực hiện các tác vụ bên trong.
Bước 5.
Nội dung đầu tiên bên trong phương thức TinhTong() như sau:
Bước 6.
Nội dung thứ hai bên trong phương thức TinhTong() như sau:
Bước 7.
Nội dung thứ ba bên trong phương thức TinhTong() như sau:
Ở đây chúng ta có một số điểm cần chú ý:
Thứ nhất, câu lệnh điều kiện và rẽ nhánh.
Câu lệnh điều kiện thứ nhất là if có cấu trúc cú pháp như sau:
if (điều_kiện_1) { // Thực thi công việc nếu điều_kiện_1 là đúng } else if (điều_kiện_2) { // Thực thi công việc nếu điều_kiện_2 là đúng } else { // Thực thi công việc nếu cả điều_kiện_1 và điều_kiện_2 đều sai }
Chú ý rằng tùy trường hợp chúng ta mới cần đến rẽ nhánh else if hoặc else.
Câu lệnh điều khiển thứ hai là switch có cấu trúc cú pháp như sau:
switch(biểu_thức) { case giá_trị_1: // thực thi công việc nếu giá trị của biểu_thức trùng với giá_trị_1 break; case giá_trị_2: // thực thi công việc nếu giá trị của biểu_thức trùng với giá_trị_2 break; default: // thực thi công việc nếu giá trị của biểu_thức khác với các giá trị bên trên }
Chúng ta có một số chú ý ở đây:
Từ khóa break thực hiện thoát khỏi một đoạn chương trình bên trong cặp {} hoặc một vòng lặp.
Từ khóa default được sử dụng tùy trường hợp cần thiết.
Thứ hai, một số toán tử cơ bản.
Chúng ta có thể tham khảo một số toán tử cơ bản trong C# như sau:
Toán tử +. Thực hiện phép cộng: x + y.
Toán tử –. Thực hiện phép trừ: x – y.
Toán tử *. Thực hiện phép nhân: x * y.
Toán tử /. Thực hiện phép chia: x / y.
Toán tử %. Thực hiện phép chia lấy số dư: x % y.
Toán tử ++. Thực hiện phép cộng thêm 1 vào số: x ++.
Toán tử --. Thực hiện phép trừ đi 1 vào số: x --.
Bước 8.
Nội dung thứ tư bên trong phương thức TinhTong() như sau:
Bước 9.
Chúng ta thực thi phương thức TinhTong() trong class MainClass.cs như sau:
Xây dựng phương thức có trả về kết quả
Bước 1.
Đối với phương thức TinhTong() có trả về kết quả, chúng ta có một số chú ý như sau:
Chúng ta thay thế từ khóa void bằng kiểu dữ liệu của kết quả được trả về. Ở đây do chúng ta thực hiện tính tổng các số tự nhiên nên kiểu dữ liệu của kết quả được trả về là int.
Chúng ta có thể cung cấp tham số cho phương thức này. Ở đây chúng ta cung cấp 02 tham số là số lượng phần tử n và mảng int[] tapHop để thực hiện việc tính tổng các số tự nhiên.
Do là có trả về kết quả nên ở câu lệnh cuối chúng ta sử dụng từ khóa return. Ở đây chúng ta thực hiện return tong.
Bước 2.
Trong phương thức main() của class MainClass.cs, chúng ta thực hiện một số nội dung trước khi thực thi phương thức TinhTong().
Chúng ta chú ý rằng nên định nghĩa một biến để lưu giá trị được trả về của phương thức TinhTong().
Bước 3.
Chúng ta thực thi toàn bộ project để thử nghiệm những đoạn mã nguồn C# được xây dựng bên trên:
Thực hiện Debug để kiểm tra các dòng lệnh và bắt lỗi trong MonoDevelop
Bước 1.
Chúng ta để con trỏ chuột tại dòng lệnh muốn bắt đầu debug.
Chúng ta lựa chọn chức năng Run → New Breakpoint … trên thanh Toolbars.
Chúng ta cũng nhận thấy trên menu Run có những chức năng cơ bản để debug:
Chức năng Step Into với phím F11. Thực hiện lần lượt chuyển đến phương thức gặp phải tại dòng lệnh đang được debug.
Chức năng Step Over với phím F10. Thực thi dòng lệnh hiện tại và chuyển tiếp đến dòng lệnh tiếp theo bên dưới.
Bước 2.
Màn hình Create a Breakpoint hiện ra.
Chúng ta giữ nguyên các thông tin mặc định.
Chúng ta lựa chọn nút Create để thực hiện.
Bước 3.
Chúng ta nhận thấy xuất hiện một chấm nhỏ màu đỏ bên trái và dòng lệnh đặt con trỏ chuột đã được tô đậm màu hồng.
Bước 4.
Chúng ta lựa chọn nút mũi tên ở góc trái trên thanh Toolbars để thực hiện debug.
Project sẽ được thực thi cho đến dòng lệnh được đặt dấu chấm đỏ debug.
Bước 5.
Màn hình giao diện chính cho tác vụ debug.
Bước 6.
Chúng ta thực hiện chức năng Step Over với phím F10 tại một số dòng lệnh liên tiếp.
Chúng ta thử dừng lại tại dòng lệnh:
Console.WriteLine(tapHop[i] + “ ”);
Chúng ta chú ý tab Locals trong phần màn hình bên dưới.
Giá trị của các biến được định nghĩa trước dòng lệnh hiện tại đã được hiển thị chi tiết.
Tổng kết
Trong bài này, chúng ta đã cùng nhau tìm hiểu một số kỹ thuật lập trình cơ bản trong C# đồng thời tìm hiểu một số chức năng cần thiết trong MonoDevelop.
Hy vọng rằng chúng ta có thể áp dụng phù hợp những kỹ thuật và chức năng này cho những bài tiếp theo.