Bài giảng Ngôn ngữ C# - Bài 5: Kế thừa, đa nhiệm trong C# - Chử Đức Hoàng

1.1.1. GIỚI THIỆU CHUNG • Thừa kế là cách tạo một lớp mới từ các lớp có sẵn. Nó cho phép tái sử dụng lại mã nguồn đã viết trong lớp có sẵn. • Lớp và các thể hiện của lớp (tức đối tượng) tuy không tồn tại trong cùng một khối, nhưng chúng tồn tại trong một mạng lưới sự phụ thuộc và quan hệ lẫn nhau. • Ví dụ như: sinh viên và công nhân đều là con người có tên, có tuổi, • Quan hệ “là -một” (is-a) là một sự đặc biệt hóa. • Quan hệ đặc biệt hóa và tổng quát hóa là hai mối quan hệ đối ngẫu và phân cấp với nhau bởi vì chúng ta tạo ra một cây quan hệ.  Đặc biệt hoá là những nhánh của tổng quát hoá.  Nếu di chuyển lên trên cùng thì được trường hợp tổng quát hóa.  Nếu di chuyển xuống thì được trường hợp đặc biệt hóa.

pdf34 trang | Chia sẻ: thanhle95 | Lượt xem: 478 | Lượt tải: 1download
Bạn đang xem trước 20 trang tài liệu Bài giảng Ngôn ngữ C# - Bài 5: Kế thừa, đa nhiệm trong C# - Chử Đức Hoàng, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
v1.0011106202 1 BÀI 5 KẾ THỪA, ĐA NHIỆM TRONG C# GV. Chử Đức Hoàng v1.0011106202 2 TÌNH HUỐNG DẪN NHẬP • Khi thực hiện viết chương trình để quản lý học viên, của trường đại học Quốc gia bằng ngôn ngữ lập trình C# thì các vấn đề như: tránh trùng lặp khi phải viết lại nhiều đoạn chương trình giống nhau trong các lớp, khả năng tái sử dụng lại chương trình trong các lớp là vấn đề rất được quan tâm. • Trong chương trình quản lý học viên có nhiều luồng công việc khác nhau. Việc quản lý thực thi các luồng công việc thực hiện bởi ngôn ngữ lập trình để thực hiện các phần công việc khác nhau mà người dùng yêu cầu.  • Ngôn ngữ C# có cho phép kế thừa không và việc kế thừa được thực hiện như thế nào? • Các luồng công việc được thực hiện như thế nào cũng như cách xử lý khi có sự xung đột xảy ra giữa các luồng trong C#? v1.0011106202 3 MỤC TIÊU Trình bày được các khái niệm về kế thừa trong C# Trình bày được khái niệm về luồng và đa nhiệm trong C# Xây dựng một chương trình C# đơn giản sử dụng tính kế thừa Xây dựng một chương trình C# sử dụng tính đa nhiệm. v1.0011106202 4 NỘI DUNG 1.1.1. Giới thiệu chung1 1.1.2. Đơn kế thừa2 1.1.3. Đa kế thừa3 1.1.4. Tính đa hình4 2.2.1. Khái niệm luồng5 2.2.3. Ứng dụng đa nhiệm7 2.2.2. Tạo luồng6 v1.0011106202 5 1.1.1. GIỚI THIỆU CHUNG • Thừa kế là cách tạo một lớp mới từ các lớp có sẵn. Nó cho phép tái sử dụng lại mã nguồn đã viết trong lớp có sẵn. • Lớp và các thể hiện của lớp (tức đối tượng) tuy không tồn tại trong cùng một khối, nhưng chúng tồn tại trong một mạng lưới sự phụ thuộc và quan hệ lẫn nhau. • Ví dụ như: sinh viên và công nhân đều là con người có tên, có tuổi, • Quan hệ “là -một” (is-a) là một sự đặc biệt hóa. • Quan hệ đặc biệt hóa và tổng quát hóa là hai mối quan hệ đối ngẫu và phân cấp với nhau bởi vì chúng ta tạo ra một cây quan hệ.  Đặc biệt hoá là những nhánh của tổng quát hoá.  Nếu di chuyển lên trên cùng thì được trường hợp tổng quát hóa.  Nếu di chuyển xuống thì được trường hợp đặc biệt hóa. v1.0011106202 6 • Kế thừa là việc một lớp có thể thừa hưởng những thuộc tính và phương thức từ một lớp khác. • Cú pháp: class : 1.1.2. ĐƠN KẾ THỪA s name age id v1.0011106202 7 Đặc điểm • Lớp dẫn xuất sẽ kế thừa tất cả các thành viên của lớp cơ sở, bao gồm tất cả các phương thức và biến thành viên của lớp cơ sở. • Lớp dẫn xuất được tự do thực thi các phiên bản của một phương thức của lớp cơ sở. • Lớp dẫn xuất cũng có thể tạo một phương thức mới và thuộc tính mới. • C# chỉ cho phép đơn thừa kế giữa các lớp. • Trong C# một lớp bắt buộc phải thừa kế từ một lớp nào đó. 1.1.2. ĐƠN KẾ THỪA (tiếp theo) v1.0011106202 8 Ví dụ: 1. class Student 2. { 3. string name; 4. int age; 5. public void Birthday() { age++; } 6. int id; 7. public double Calpoint(); 8. } 9. class Employee 10. { 11. string name; 12. int age; 13. public void Birthday() { age++; } 14. double salary; 15. public double Calsalary(); 16. } 17. class Person 18. { 19. string name; 20. int age; 21. public void Birthday() { age++; } 22. } 23. class Student : Person 24. { 25. int id; 26. public double Calpoint(); 27. } 28. class Employee : Person 29. { 30. double salary; 31. public double Calsalary(); 32. } Lặp lại giống nhau 1.1.2. ĐƠN KẾ THỪA (tiếp theo) v1.0011106202 9 Cấp phát bộ nhớ Khi tạo một đối tượng ở lớp thừa kế thì nó sẽ cấp phát bộ nhớ cho tất cả các trường của cả lớp cơ sở và lớp dẫn xuất. 33. class Person 34. { 35. string name; 36. int age; 37. ... 38. } 39. class Student : Person 40. { 41. int id; 42. ... 43. } 44. Public static void Main() 45. { 46. Student s = new Student(); 47. } s name age id 1.1.2. ĐƠN KẾ THỪA (tiếp theo) v1.0011106202 10 Thực thi phương thức lớp cơ sở 49. class Person 50. { 51. public void Birthday() 52. { 53. age++; 54. } 55. ... 56. } 57. class Student : Person 58. { 59. ... 60. } 61. Public static void Main() 62. { 63. Student s = new Student(); 64. s.Birthday(); 65. } Gọi phương thức lớp cơ sở từ đối tượng của lớp kế thừa • Có thể gọi phương thức lớp cơ sở từ phương thức lớp dẫn xuất bằng từ khoá “base” • Có thể ẩn các phương thức lớp cơ sở bằng cách sử dụng từ khoá “new” 1.1.2. ĐƠN KẾ THỪA (tiếp theo) v1.0011106202 11 Gọi phương thức khởi dựng lớp cơ sở 33. class Person 34. { 35. string name; 36. int age; 37. public Person(string name, int age) 38. { 39. this.name = “Nguyễn văn X”; 40. this.age = 23; 41. } 42. ... 43. } 44. class Student : Person 45. { 46. //gọi hàm tạo lớp cơ sở 47. public Student( string name, int age, int pointin):base(name, age) 48. int id; 49. ... 50. } Không kế thừa phương thức khởi dựng. Cách gọi được thực hiện bằng việc đặt dấu hai chấm ngay sau phần khai báo danh sách tham số và tham chiếu đến lớp cơ sở thông qua từ khóa base Có thể gọi hàm tạo lớp cơ sở từ hàm tạo lớp dẫn xuất 1.1.2. ĐƠN KẾ THỪA (tiếp theo) v1.0011106202 12 Chọn hàm tạo lớp cơ sở Khi lớp cơ sở “Person” có nhiều hàm tạo: Ở lớp kế thừa gọi đến hàm tạo thứ 3 1. class Person 2. { 3. public Person() { ... } 4. public Person(string name) { ... } 5. public Person(string name, int age) { ... } 6. ... 7. } 1. class Student : Person 2. { 3. int id; 4. public Student(string name, int age, int id) 5. :base( name, age) 6. { 7. this.id = id; 8. } 9. } • Khi lớp kế thừa không gọi đích danh hàm tạo nào của lớp cơ sở thì trình biên dịch sẽ tự động gọi hàm tạo không đối số của lớp cơ sở. • Nếu lớp cơ sở chỉ định nghĩa hàm tạo có đối số mà lớp dẫn xuất không gọi hàm tạo này thì sẽ báo lỗi biên dịch. 1.1.2. ĐƠN KẾ THỪA (tiếp theo) v1.0011106202 13 Gọi phương thức lớp cơ sở • Khi lớp kế thừa muốn định nghĩa lại phương thức đã được định nghĩa trong lớp cơ sở thì phải thực hiện theo cấu trúc: new ; • Sau khi phương thức được định nghĩa lại trong lớp kế thừa, thì nó sẽ làm ẩn đi phương thức của lớp cơ sở và thay thế bằng phương thức mới được định nghĩa lại. • Nếu muốn gọi phương thức của lớp cơ sở thì phải dùng từ khoá “base”: base.; 1.1.2. ĐƠN KẾ THỪA (tiếp theo) v1.0011106202 14 1. class Person 2. { 3. int id; 4. public void SetId(int id) { this.id = id; } 5. public void Print() 6. {Console.WriteLine(name); 7. Console.WriteLine(age);} 8. } 9. class Student : Person 10. { 11. int id; 12. public new void SetId(int id) { this.id = id; } 13. public new void Print() 14. { 15. base.Print(); 16. Console.WriteLine(id); 17. } 18. } Định nghĩa lại phương thức lớp cơ sở thông qua từ khoá “new” Gọi phương thức lớp cơ sở thông qua từ khoá “base” 1.1.2. ĐƠN KẾ THỪA (tiếp theo) v1.0011106202 15 Chỉ cho phép đơn kế thừa: 1. class Student : Person 2. { 3. ... 4. } 5. class Employee : Person 6. { 7. ... 8. } Không cho phép đa kế thừa, nếu thực hiện đa kế thừa lớp thì sẽ báo lỗi: 1. class Graduate : Student, Employee 2. { 3. ... 4. } Chỉ cho phép đa kế thừa giao diện 1. class Graduate : IStudent, Iemployee, 2. { 3. ... 4. } 1.1.3. ĐA KẾ THỪA v1.0011106202 16 Phân cấp kế thừa 1. class Person 2. { 3. string name; 4. int age; 5. ... 6. } 7. class Student : Person 8. { 9. int id; 10. ... 11. } 12. class Graduate : Student 13. { 14. string advisor; 15. ... 16. } 61. Public static void Main() 62. { 63. Graduate g = new Graduate(); 64. } g name age id advisor Khi tạo một đối tượng lớp kế thừa thì thứ tự khởi tạo sẽ bắt đầu từ lớp cơ sở rồi sau đó mới khởi tạo đến lớp dẫn xuất. 1.1.3. ĐA KẾ THỪA (tiếp theo) v1.0011106202 17 CÂU HỎI THẢO LUẬN So sánh hai từ khai báo mới đó là kiểu "new" và "override" giống và khác nhau gì? v1.0011106202 18 Lớp lồng nhau • Lớp đựơc khai báo bên trong thân của lớp khác gọi là lớp nội: inner class hay nested class, lớp kia gọi là lớp ngoài outer class. • Lớp nội có thể truy cập tất cả thành viên của lớp ngoài, kể cả private. • Lớp nội nằm trong lớp ngoài nên nó có thể là private với lớp ngoài. • Khi lớp nội khai báo là public thì có thể truy xuất thông qua tên của lớp ngoài: outer_class.inner_class. 1.1.4. ĐA HÌNH v1.0011106202 19 public class Student { private int mathpoint; private int phypoint; public Student(int mathpoint, int phypoint) { this.mathpoint = mathpoint; this.phypoint = phypoint; } public override string ToString() { string str = mathpoint.ToString() + "/" + phypoint.ToString(); return s; } public class StudentDisplay { public void Display(Student f) { Console.WriteLine(“Display Math Point {0}", f.mathpoint); Console.WriteLine("Display Physical Point {0}", f.phypoint); } } } Ví dụ: Truy xuất được thành phần Private của lớp outer Lớp nested class 1.1.4. ĐA HÌNH (tiếp theo) v1.0011106202 20 class Tester { static void Main() { Student f1 = new Student(3, 4); Console.WriteLine("f1: {0}", f1.ToString()); Student.StudentDisplay fa = new Student.StudentDisplay(); fa.Display(f1); } } Ví dụ: Truy xuất lớp inner qua lớp outer, lớp outer tương tự như manespace 1.1.4. ĐA HÌNH (tiếp theo) v1.0011106202 21 • Luồng (thread): Là một chuỗi liên tiếp các lệnh mà máy tính thực thi. • Trong một chương trình C# , việc thực thi bắt đầu bằng phương thức Main() và tiếp tục cho đến khi kết thúc hàm Main(). Do vậy, phương thức Main() là phương thức mà .NET runtime lấy để bắt đầu cho các luồng. • Trong một chương trình thường muốn làm nhiều nhiệm vụ khác nhau cùng một lúc. • Lớp luồng  Mỗi luồng Win32 được thông qua một hàm để chạy khi nó được tạo ra. Khi một luồng quay trở lại từ hàm thì nó chấm dứt.  Trong C#, các luồng được thao tác bằng cách dùng lớp Thread nằm trong namespace “System.Threading”.  Một thể hiện của luồng đaị diện cho một luồng.  Có thể tạo các luồng khác bằng cách khởi tạo một đối tượng luồng. 2.2.1. KHÁI NIỆM LUỒNG v1.0011106202 22 2.2.2. TẠO LUỒNG • Tạo luồng: Thread thread = new Thread(new ThreadStart(ThreadFunc)); thread.Start(); • ThreadFunc có thể là:  ThreadStart(SomeClass.aStaticFunction);  ThreadStart(someClassInstance.aNonStaticFunction); • Các trạng thái của luồng  Start(): cho chạy luồng.  Suspend(): Đình chỉ tạm thời luồng để bắt đầu một luồng khác.  Resume(): Gọi phục hồi luồng.  Sleep(): cho luồng ngủ một khoảng thời gian.  Abort(): huỷ luồng. v1.0011106202 23 Các đặc tính của luồng: • IsBackground – get, set  Quy trình không kết thúc cho đến khi các luồng “Foreground” kết thúc  Các luồng “Background” được chấm dứt khi ứng dụng kết thúc. • CurrentThread – get, static  Trả về luồng tham chiếu để gọi luồng • IsAlive – get  Luồng đã bắt đầu nhưng chưa kết thúc • Priority – get, set  Highest, AboveNormal, Normal, BelowNormal, Lowest • ThreadState – get  Unstarted, Running, Suspended, Stopped, WaitSleepJoin, 2.2.2. TẠO LUỒNG (tiếp theo) v1.0011106202 24 • Một ứng dụng cần thực hiện nhiều hơn một công việc nên cần thực thi nhiều luồng công việc thì được gọi là ứng dụng đa nhiệm. Khi đó thì phải đăng kí các độ ưu tiên khác nhau cho các luồng khác nhau trong một tiến trình. Luồng có độ ưu tiên cao hơn thì nó sẽ chiếm quyền ưu tiên so với các luồng khác trong tiến trình. • Cần thận trọng khi cấp quyền ưu tiên cho các luồng. • Một luồng không được không được phép hoạt động nếu có một luồng có độ ưu tiên cao hơn đang làm việc. • Luồng hệ thống thường có quyền ưu tiên cao hơn. Ví dụ trong Windows có khuynh hướng đặt độ ưu tiên cao cho các luồng của hệ điều hành. • Các mức độ ưu tiên của luồng (ThreadPriority) là:  Highest  AboveNormal  Normal  BelowNormal  Lowest 2.2.3. ỨNG DỤNG ĐA NHIỆM v1.0011106202 25 • Sự đồng bộ • Sự đồng bộ là việc truy nhập một biến bởi nhiều luồng vào cùng thời điểm. Nếu không đảm bảo được sự đồng bộ thì sẽ gây ra các lỗi. • C# cung cấp một cách thức dễ dàng để giải quyết việc đồng bộ trong việc truy nhập biến bằng từ khóa lock: lock (x) { DoSomething(); } • Câu lệnh lock sẽ bao một đối tượng gọi là mutual exclusion lock hay mutex. Trong khi mutex bao một biến thì không một luồng nào được quyền truy nhập vào biến đó. • Trong đoạn mã trên khi câu lệnh hợp thực thi và nếu time slice của luồng này kết thúc và luồng kế tiếp thử truy xuất vào biến x , việc truy xuất đến biến sẽ bị từ chối. thay vào đó window đơn giản đặt luồng đó ngủ cho đến khi mutex được giải phóng. Mutex là một cơ chế đơn giản được dùng để điều khiển việc truy nhập vào các biến. Tất cả việc điều khiển này nằm trong lớp System.Threading.Monitor. Câu lệnh lock gồm một số phương thức gọi đến lớp này. 2.2.3. ỨNG DỤNG ĐA NHIỆM (tiếp theo) v1.0011106202 26 Các vấn đề đồng bộ Việc đồng bộ các luồng là quan trọng trong các ứng dụng đa luồng. Tuy nhiên có một số lỗi tinh vi và khó có thể xuất hiện: • “deadlock”: là một lỗi xuất hiện khi hai luồng cần truy nhập vào các tài nguyên bị khoá lẫn nhau. • “race condition”: xuất hiện khi nhiều hơn một luồng cố gắng truy nhập vào cùng một dữ liệu và không quan tâm đến các luồng khác làm gì. Khi gặp lỗi này thì nó ít khi dừng thực thi quá trình nhưng nó lại làm lỗi dữ liệu. 2.2.3. ỨNG DỤNG ĐA NHIỆM (tiếp theo) v1.0011106202 27 CÂU HỎI THẢO LUẬN Có mấy mức ứng dụng đa nhiệm? So sánh ưu tiên đa nhiệm của Windows với các chương trình của hệ thống? v1.0011106202 28 Ví dụ “deadlock” • Luồng 1: 1. lock (a) 2. {// do something 3. lock (b) 4. { 5. // do something 6. } 7. } • Luồng 2: 1. lock (b) 2. { // do something 3. lock (a) 4. { 5. // do something 6. } 7. } Trong đó a, b là hai đối tượng tham chiếu mà cả hai luồng cần truy cập. Hai luồng cùng làm việc: • Luồng 1: lock a, luồng 2 lock b • Luồng 1: lock b thì rơi vào trạng thái ngủ chờ luồng 2 giải phóng b và ngược lại. 2.2.3. ỨNG DỤNG ĐA NHIỆM (tiếp theo) v1.0011106202 29 Kết quả và khắc phục lỗi deadlock • lock trên a sẽ không bao giờ được giải phóng bởi vì luồng đầu tiên đã lock trên a đang ngủ và không thức dậy. Cho đến khi lock trên b được giải phóng điều này cũng không thể xảy ra cho đến khi nào luồng thứ hai thức dậy. • Kết quả là deadlock, cả hai luồng đều không làm gì cả, đợi lẫn nhau để giải phóng lock . • Loại lỗi này làm toàn ứng dụng bị treo và phải dùng Task Manager để hủy nó. • Deadlock có thể được tránh nếu cả hai luồng yêu cầu lock trên đối tượng theo cùng thứ tự. • Ví dụ: luồng 2 yêu cầu lock cùng thứ tự với luồng 1: a đầu rồi tới b thì những luồng mà lock trên a đầu sẽ hoàn thành nhiệm vụ của nó sau đó các luồng khác sẽ bắt đầu. 2.2.3. ỨNG DỤNG ĐA NHIỆM (tiếp theo) PROPERTIES On passing, 'Finish' button: Goes to Next Slide On failing, 'Finish' button: Goes to Next Slide Allow user to leave quiz: At any time User may view slides after quiz: At any time User may attempt quiz: Unlimited times v1.0011106202 31 TÓM LƯỢC CUỐI BÀI • Mô tả cách thức xây dựng một lớp mới dựa trên lớp đã có và khai thác cũng như phạm vi truy cập các thuộc tính và phương thức của lớp nền và lớp dẫn xuất của ngôn ngữ C#. • Lớp trừu tượng, lớp lồng và vấn đề override phương thức trong lớp kế thừa của C#. • Mô tả khái niệm luồng và cách tạo một luồng và các vấn đề phát sinh khi thực hiện các luồng. Cách khắc phục lỗi sảy ra khi sử dụng đa luồng trong ngôn ngữ C#. • Xây dựng các modul trong chương trình quản lý học viên sử dụng tính kế thừa trong C#. • Xây dựng phần mềm có tạo luồng trong chương trình quản lý học viên. PROPERTIES On passing, 'Finish' button: Goes to Next Slide On failing, 'Finish' button: Goes to Next Slide Allow user to leave quiz: At any time User may view slides after quiz: At any time User may attempt quiz: Unlimited times PROPERTIES Allow user to leave interaction: Anytime Show ‘Next Slide’ Button: Don't show Completion Button Label: Next Slide PROPERTIES Allow user to leave interaction: Anytime Show ‘Next Slide’ Button: Don't show Completion Button Label: Next Slide