Bỏ qua nội dung

Lập trình nâng cao

Khoa học máy tính A-Level · Chủ đề 20

Bài học video cho chủ đề này Mở trang video
13:52

Mô hình lập trình

Đây là một công việc: liệt kê tất cả sinh viên có điểm A. Một lập trình viên viết một vòng lặp — bắt đầu từ bản ghi đầu tiên, kiểm tra điểm, thêm tên vào danh sách, di chuyển…

Giọng đọc tiếng Anh · phụ đề tiếng Anh + 中文 được ghi trực tiếp

20.1

Các mô hình lập trình

Chương trình
Thí sinh cần có thể: Ghi chú và hướng dẫn
Hiểu rõ ý nghĩa của một programming paradigm.
Thể hiện sự hiểu biết về các đặc điểm của nhiều programming paradigms:
• Low-level Low-level Programming: • hiểu biết và khả năng viết mã mức thấp sử dụng các addressing modes khác nhau: immediate, direct, indirect, indexed và relative.
• Nhân lệnh (Thủ tục) Lập trình Nhân lệnh (Thủ tục): • Kiến thức và sự hiểu biết về Lập trình Cấu trúc (xem chi tiết trong phần nội dung AS 11.3) • Hiểu và có khả năng viết mã lập trình nhân lệnh (thủ tục) sử dụng biến, cấu trúc, thủ tục và hàm. Xem chi tiết trong phần nội dung AS
• Hướng đối tượng Lập trình Hướng đối tượng (OOP): • Hiểu các thuật ngữ liên quan đến OOP (bao gồm đối tượng, thuộc tính/đặc điểm, phương thức, lớp, kế thừa, đa hình, sự chứa đựng (gộp), bao bọc, getter, setter, thực thể) • Hiểu cách giải quyết vấn đề bằng cách thiết kế các lớp phù hợp • Hiểu và có khả năng viết mã thể hiện việc sử dụng OOP
• Khẳng định Lập trình Khẳng định: • Hiểu và có khả năng giải quyết vấn đề bằng cách viết các sự thật và luật lệ phù hợp dựa trên thông tin đã cung cấp • Hiểu và có khả năng viết mã có thể thỏa mãn một mục tiêu bằng cách sử dụng sự thật và luật lệ

Nguồn: Chương trình Cambridge International

Một mô hình lập trình là một phong cách lập trình — cách cấu trúc chương trình, đi kèm với những ý tưởng và tính năng ngôn ngữ riêng. Có bốn mô hình lập trình trong chương trình này.

"Mô tả ý nghĩa của một ngôn ngữ mệnh lệnh (thủ tục)" (hai điểm). Một ngôn ngữ mà trong đó chương trình là một dãy lệnh được thực thi theo thứ tự và làm thay đổi trạng thái của chương trình; người lập trình nói lên cách thức thực hiện tác vụ, sử dụng thủ tục, dãy lệnh, lựa chọn và lặp. "Mô tả ý nghĩa của một ngôn ngữ khai báo": chương trình nêu sự thật và quy tắc (điều đã biết và điều mong muốn) và bộ suy luận của ngôn ngữ sẽ xác định cách tìm câu trả lời; người lập trình không cung cấp dãy bước thực hiện.

Xác định mô hình từ một đoạn mã (một câu hỏi Paper 3 thông thường): LDD 200, ADD #5, STO 201 là cấp thấp (mnemonic, thanh ghi, địa chỉ bộ nhớ); FOR Count ← 1 TO 10 … NEXT Count với các thủ tục và gán giá trị là mệnh lệnh; CLASS Dog … PRIVATE Name : STRING … PUBLIC PROCEDURE NEW(…) là hướng đối tượng; type(lion, wild). và dangerous(X) IF type(X, wild) là khai báo (logic). Trong câu hỏi ghép đôi: cấp thấp ghép với "mnemonic tương ứng trực tiếp với lệnh máy", mệnh lệnh với "dãy câu lệnh thay đổi trạng thái", OOP với "đối tượng kết hợp thuộc tính và phương thức", khai báo với "sự thật và quy tắc, không có thứ tự thực thi nào được đưa ra".

Bốn mô hình: cấp thấp, mệnh lệnh, hướng đối tượng và khai báo
Bốn mô hình: cấp thấp, mệnh lệnh, hướng đối tượng và khai báo

Lập trình cấp thấp

Lập trình gần với phần cứng trong ngôn ngữ máy hoặc ngôn ngữ assembly, nơi mỗi lệnh ánh xạ đến những gì CPU thực thi. Nó cung cấp truy cập trực tiếp đến thanh ghi và địa chỉ bộ nhớ, sử dụng các kiểu định址 mode khác nhau (ngay, trực tiếp, gián tiếp, chỉ số và tương đối). Nó rất nhanh và nhỏ gọn, nhưng phụ thuộc kiến trúc, tẻ nhạt và khó bảo trì. Đây là lập trình cấp thấp, được sử dụng cho driver thiết bị, firmware và bootloader.

Năm kiểu định址 mode. Chương trình yêu cầu mã cấp thấp sử dụng mỗi kiểu định址 mode (tập lệnh nằm trong Chủ đề 4). Toán hạng của lệnh load có thể đọc theo năm cách, và bài thi cung cấp nội dung bộ nhớ và hỏi thanh ghi tích lũy chứa gì:

Bảng bộ nhớ với các địa chỉ 105, 106, 107, 27 và 145 cùng nội dung của chúng, bên cạnh năm hàng hiển thị thanh ghi tích lũy nhận được từ LDM #105, LDD 105, LDI 105, LDX 105 với IX = 2, và một lệnh nhảy tương đối
Cùng một toán hạng, 105, được đọc theo năm cách: như một giá trị, như một địa chỉ, như địa chỉ của một địa chỉ, như địa chỉ cộng thanh ghi chỉ số, và như độ lệch so với lệnh hiện tại
  • ngay (LDM #105): toán hạng là giá trị; ACC trở thành 105.
  • trực tiếp (LDD 105): toán hạng là địa chỉ của giá trị; ACC trở thành nội dung của 105, ở đây là 27.
  • gián tiếp (LDI 105): toán hạng là địa chỉ của một địa chỉ; ACC trở thành nội dung của 27, ở đây là 91. Được sử dụng cho con trỏ và dữ liệu whose vị trí được quyết định tại thời gian chạy.
  • chỉ số (LDX 105): địa chỉ là toán hạng cộng thanh ghi chỉ số IX; với IX = 2, ACC trở thành nội dung của 107. Được sử dụng để duyệt qua mảng bằng cách tăng IX.
  • tương đối (JMR +65): đích là độ lệch so với địa chỉ của lệnh hiện tại, điều này làm cho mã có thể di chuyển được.

Ví dụ có lời giải. Bộ nhớ: 105 chứa 27, 106 chứa 64, 200 chứa 0. Viết mã để cộng nội dung của 105 và 106, lưu kết quả vào 200 và xuất ra. LDD 105 (ACC = 27), ADD 106 (ACC = 91), STO 200, OUT. Để nhân đôi giá trị trong 105 thay vì: LDD 105, ADD 105, STO 105. Nêu nội dung thanh ghi sau mỗi dòng khi yêu cầu vẽ lại.

Lập trình mệnh lệnh (thủ tục)

Trong lập trình mệnh lệnh, người lập trình viết một dãy lệnh thay đổi trạng thái chương trình — gán giá trị, điều kiện, vòng lặp, gọi hàm. Biến giữ trạng thái; câu lệnh thay đổi nó; mã được tổ chức thành các thủ tục và hàm (còn được gọi là lập trình có cấu trúc). Đây là phong cách của Chủ đề 9 và 11 (Python, C). Mạnh mẽ khi thuật toán có các bước tuần tự rõ ràng.

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

Trong lập trình hướng đối tượng, chương trình được xây dựng từ các đối tượng — đơn vị kết hợp dữ liệu (thuộc tính) và thao tác (phương thức). Đối tượng là thể hiện của lớp. Bốn trụ cột:

  • bao gói — dữ liệu của đối tượng bị ẩn sau các phương thức của nó; mã bên ngoài chỉ sử dụng các phương thức công khai, không truy cập dữ liệu trực tiếp. Điều này bảo vệ đối tượng và cho phép nội bộ thay đổi mà không làm hỏng người gọi. Ví dụ, một BankAccount ẩn balance của nó; bạn chỉ thay đổi nó thông qua deposit() và withdraw(), những cái có thể áp dụng quy tắc như "không bao giờ đi xuống dưới 0".
  • kế thừa — một lớp con chuyên hóa một lớp cha, kế thừa các thuộc tính và phương thức của nó và thêm vào hoặc ghi đè chúng. Mô hình hóa "is-a" ("a Manager is an Employee").
  • đa hình — các đối tượng khác nhau phản hồi với cùng một lời gọi phương thức theo cách khác nhau; người gọi không cần biết chính xác loại. Mọi Shape đều có Area(), và một Circle và một Rectangle mỗi cái triển khai nó theo cách riêng của mình.
  • trừu tượng — hiển thị một giao diện đơn giản và ẩn Implementation.

Các thuật ngữ khác:

  • một constructor là một phương thức đặc biệt được chạy khi đối tượng được tạo ra, để thiết lập các thuộc tính của nó.
  • getters và setters đọc và ghi các thuộc tính của đối tượng (các property của chúng) thông qua các phương thức.
  • tích hợp và bao hàm xây dựng một đối tượng từ các đối tượng khác (mối quan hệ "có-a").

OOP được sử dụng cho các hệ thống lớn, giao diện đồ họa (GUI), mô phỏng và trò chơi.

Cùng một cú gọi Shape.Area() chạy mã khác nhau cho mỗi đối tượng: Circle tính pi nhân r bình phương, Rectangle tính chiều rộng nhân chiều cao
Đa hình thái: cùng một lời gọi phương thức chạy mã riêng của từng đối tượng
Sơ đồ lớp UML cho Shape: hộp ba phần với tên lớp, thuộc tính riêng tư (Name, Area, Perimeter, đánh dấu bằng dấu trừ) và phương thức công khai (SetShape, calculateArea, calculatePerimeter, đánh dấu bằng dấu cộng)
Sơ đồ lớp cho Shape: thuộc tính riêng tư và phương thức công khai
Sơ đồ kế thừa UML: lớp cha employee ở trên, với hai lớp con partTime và fullTime bên dưới, mỗi lớp nối với lớp cha bằng mũi tên tổng quát hóa tam giác rỗng và thêm các thuộc tính và phương thức riêng của nó
Kế thừa: partTime và fullTime là các lớp con của employee
Đối tượng BankAccount với số dư riêng tư chỉ truy cập được qua các phương thức công khai deposit() và withdraw(); mã bên ngoài không thể trực tiếp tác động vào dữ liệu
Bao đóng: dữ liệu của đối tượng là riêng tư, chỉ truy cập được thông qua các phương thức công khai của nó

OOP theo cách giám khảo chấm điểm

Định nghĩa. Lớp (Class): một bản mẫu (kế hoạch thiết kế) xác định các thuộc tính và phương thức của các đối tượng thuộc loại đó. Đối tượng (Object): một thực thể của lớp, được tạo ra từ lớp đó, có các giá trị riêng cho các thuộc tính ("một sự xuất hiện của đối tượng" là cụm từ trong đề thi để chỉ thực thể). Thuộc tính (Attribute/Property): một mục dữ liệu thuộc về một lớp. Phương thức (Method): một thủ tục hoặc hàm thuộc về một lớp hoạt động trên các thuộc tính của nó. Bao đóng (Encapsulation): kết hợp các thuộc tính và phương thức vào một lớp và hạn chế truy cập từ bên ngoài đối với dữ liệu: các thuộc tính là riêng tư và chỉ có thể đọc hoặc thay đổi thông qua các phương thức công khai. Kế thừa (Inheritance): một lớp con thừa nhận các thuộc tính và phương thức của lớp cha (lớp siêu cấp) của nó và có thể thêm các thuộc tính/phương thức mới hoặc ghi đè lên chúng. Đa hình thái (Polymorphism): các phương thức có cùng tên nhưng hành vi khác nhau trong các lớp khác nhau; thường thì một lớp con định nghĩa lại phương thức của lớp cha, và phiên bản đúng sẽ chạy cho mỗi đối tượng. Bao hàm (Containment): một lớp có một đối tượng của lớp khác làm thuộc tính (một chiếc ô tô có động cơ). "Xác định tính năng hạn chế truy cập từ bên ngoài đối với dữ liệu" chính là bao đóng; "thuật ngữ chỉ sự xuất hiện của một đối tượng" là thực thể.

"Tóm tắt cấu trúc của một lớp (ba điểm): các thuộc tính (tính chất) chứa dữ liệu của đối tượng, thường được khai báo là riêng tư; các phương thức (thủ tục và hàm) hoạt động trên các thuộc tính đó, thường là công khai; và một hàm khởi tạo (constructor), là phương thức chạy khi đối tượng được tạo ra để khởi tạo các thuộc tính. "Nêu ba lợi ích của OOP:" mã nguồn được tái sử dụng thông qua kế thừa; dữ liệu được bảo vệ bởi bao đóng, do đó chỉ có thể bị thay đổi bởi các phương thức riêng của lớp; một chương trình lớn được chia thành các lớp được viết và kiểm thử độc lập, giúp dễ bảo trì và mở rộng hơn; các lớp mô phỏng các thực thể thực tế, nên việc thiết kế dễ hiểu hơn; đa hình thái cho phép cùng một lời gọi hoạt động cho các đối tượng khác nhau.

Lớp trong伪代码, như Paper 3 yêu cầu:

CLASS Car
    PRIVATE Registration : STRING
    PRIVATE Year : INTEGER
    PRIVATE Mileage : INTEGER
    PUBLIC PROCEDURE NEW(NewReg : STRING, NewYear : INTEGER)
        Registration ← NewReg
        Year ← NewYear
        Mileage ← 0
    ENDPROCEDURE
    PUBLIC FUNCTION GetMileage() RETURNS INTEGER
        RETURN Mileage
    ENDFUNCTION
    PUBLIC PROCEDURE AddMileage(Extra : INTEGER)
        Mileage ← Mileage + Extra
    ENDPROCEDURE
ENDCLASS

Một đối tượng được tạo ra bằng MyCar ← NEW Car("AB12 CDE", 2020) và sử dụng với MyCar.AddMileage(150) và OUTPUT MyCar.GetMileage(). Một lớp con tái sử dụng hàm khởi tạo của lớp cha thông qua SUPER:

CLASS ElectricCar INHERITS Car
    PRIVATE BatteryCapacity : REAL
    PUBLIC PROCEDURE NEW(NewReg : STRING, NewYear : INTEGER, NewCapacity : REAL)
        SUPER.NEW(NewReg, NewYear)
        BatteryCapacity ← NewCapacity
    ENDPROCEDURE
ENDCLASS

Cùng lớp đó trong Python, như Paper 4 yêu cầu: các thuộc tính được làm riêng tư bằng cách thêm hai gạch underscore, hàm khởi tạo là __init__, và một lớp con đặt tên lớp cha trong ngoặc vuông và gọi super().__init__(…):

class Car:
    def __init__(self, reg, year):
        self.__registration = reg
        self.__year = year
        self.__mileage = 0
    def get_mileage(self):
        return self.__mileage
    def add_mileage(self, extra):
        self.__mileage = self.__mileage + extra

class ElectricCar(Car):
    def __init__(self, reg, year, capacity):
        super().__init__(reg, year)
        self.__capacity = capacity

cars = []
cars.append(Car("AB12 CDE", 2020))
cars.append(ElectricCar("EV21 XYZ", 2023, 75.0))
cars[1].add_mileage(150)
print(cars[1].get_mileage())

Trong Java, các khái niệm tương tự là private/public trường (fields), một hàm khởi tạo mang tên lớp, extends và super(…); trong VB.NET là Private/Public, Sub New, Inherits và MyBase.New. Một phương thức đa hình thái được viết trong lớp cha và ghi đè trong lớp con với cùng tên; một lời gọi thông qua biến kiểu cha sẽ chạy phiên bản của lớp con.

Cấu trúc dữ liệu như các đối tượng. Paper 4 xây dựng một ngăn xếp (stack), danh sách liên kết (linked list) hoặc cây nhị phân từ một lớp Node mà các thuộc tính của nó là dữ liệu và một hoặc hai tham chiếu đến các nút khác; một lớp Tree (hoặc LinkedList) chứa gốc (hoặc điểm bắt đầu) và các phương thức.

Cây nhị phân các đối tượng Node: Root của đối tượng Tree trỏ đến node 15,oman Left và Right trỏ đến các node 8 và 19, v.v., với None cho các tham chiếu rỗng
Cây nhị phân được xây dựng từ các đối tượng: mỗi Node chứa Data cùng các tham chiếu Left và Right, và Tree chứa Root; việc chèn dữ liệu sẽ duyệt xuống theo các tham chiếu
CLASS Node
    PUBLIC Data : INTEGER
    PUBLIC Left : Node          // NULL when there is no child
    PUBLIC Right : Node
    PUBLIC PROCEDURE NEW(NewData : INTEGER)
        Data ← NewData
        Left ← NULL
        Right ← NULL
    ENDPROCEDURE
ENDCLASS

CLASS Tree
    PRIVATE Root : Node
    PUBLIC PROCEDURE Insert(NewData : INTEGER)
        DECLARE NewNode, Current : Node
        DECLARE Placed : BOOLEAN
        NewNode ← NEW Node(NewData)
        IF Root = NULL THEN
            Root ← NewNode
        ELSE
            Current ← Root
            Placed ← FALSE
            WHILE NOT Placed
                IF NewData < Current.Data THEN
                    IF Current.Left = NULL THEN
                        Current.Left ← NewNode
                        Placed ← TRUE
                    ELSE
                        Current ← Current.Left
                    ENDIF
                ELSE
                    IF Current.Right = NULL THEN
                        Current.Right ← NewNode
                        Placed ← TRUE
                    ELSE
                        Current ← Current.Right
                    ENDIF
                ENDIF
            ENDWHILE
        ENDIF
    ENDPROCEDURE
ENDCLASS

Một phương thức find đi cùng một tuyến đường và trả về TRUE khi Current.Data = Target, FALSE khi nó đạt đến NULL; một phương thức output theo thứ tự trung tâm (in-order) là đệ quy: xuất cây con trái, node, sau đó cây con phải. Đối với danh sách liên kết, node có một tham chiếu, Next, và lớp danh sách lưu giữ Start; đối với ngăn xếp được xây dựng từ một danh sách, push và pop đều hoạt động tại Start.

Ví dụ đã giải. Một trò chơi có các nhân vật. Mỗi nhân vật có tên, sức khỏe (bắt đầu từ 100) và vị trí được xác định bởi X và Y. Viết một lớp Character với hàm khởi tạo và phương thức Move(DX, DY); sau đó một lớp con Wizard thêm Mana (bắt đầu từ 50) và một phương thức CastSpell() tiêu thụ 10 mana và trả về TRUE nếu đủ.

CLASS Character
    PRIVATE Name : STRING
    PRIVATE Health : INTEGER
    PRIVATE X : INTEGER
    PRIVATE Y : INTEGER
    PUBLIC PROCEDURE NEW(NewName : STRING, StartX : INTEGER, StartY : INTEGER)
        Name ← NewName
        Health ← 100
        X ← StartX
        Y ← StartY
    ENDPROCEDURE
    PUBLIC PROCEDURE Move(DX : INTEGER, DY : INTEGER)
        X ← X + DX
        Y ← Y + DY
    ENDPROCEDURE
ENDCLASS

CLASS Wizard INHERITS Character
    PRIVATE Mana : INTEGER
    PUBLIC PROCEDURE NEW(NewName : STRING, StartX : INTEGER, StartY : INTEGER)
        SUPER.NEW(NewName, StartX, StartY)
        Mana ← 50
    ENDPROCEDURE
    PUBLIC FUNCTION CastSpell() RETURNS BOOLEAN
        IF Mana >= 10 THEN
            Mana ← Mana - 10
            RETURN TRUE
        ELSE
            RETURN FALSE
        ENDIF
    ENDFUNCTION
ENDCLASS

Các điểm được trao cho các thuộc tính riêng tư, hàm khởi tạo thiết lập mọi thuộc tính, dòng kế thừa, lời gọi hàm khởi tạo của lớp cha, và phương thức sử dụng cũng như thay đổi dữ liệu riêng của đối tượng. Khi câu hỏi yêu cầu vẽ sơ đồ lớp, hãy vẽ một hộp ba phần (tên; thuộc tính với - cho riêng tư; phương thức với + cho công khai) và nối lớp con với lớp cha bằng mũi tên trỏ về phía lớp cha.

Lập trình khai báo

Trong lập trình khai báo (declarative programming), bạn nói cái gì cần tính toán, không phải cách nào — thời gian chạy sẽ tự xác định các bước. Có hai loại:

  • lập trình hàm (functional programming) — được xây dựng từ các hàm thuần túy (không có tác dụng phụ; cùng một đầu vào luôn cho cùng một đầu ra) kết hợp với nhau. Ví dụ: Haskell, Lisp.
  • lập trình logic (logic programming) — khai báo sự thật và quy tắc; động cơ trả lời một mục tiêu (truy vấn) bằng suy luận. Ví dụ: Prolog.

Một ví dụ quen thuộc về lập trình khai báo là SQL: SELECT * FROM Customer WHERE Country = 'UK' nói cái gì bạn muốn, không phải cách duyệt qua các bản ghi.

Sự thật, quy tắc và mục tiêu là những gì đề thi kiểm tra trong mô hình lập trình khai báo. Với các sự thật này (các mệnh đề đúng) và một quy tắc (kết luận đúng khi các điều kiện của nó đúng):

01 type(leopard, wild).
02 type(lion, wild).
03 type(tabby, domestic).
04 size(leopard, large).
05 size(lion, large).
06 size(tabby, small).
07 dangerous(X) IF type(X, wild) AND size(X, large).

"Viết kết quả của mục tiêu type(X, wild)":* X = leopard, X = lion. Động cơ khớp mục tiêu với từng sự thật lần lượt; mỗi sự khớp là một giải pháp, và chữ cái in hoa là một biến mà sự khớp điền vào. "Viết một sự thật để chỉ ra rằng một con báo leo núi là hoang dã": type(cheetah, wild). "Giải thích dòng 07 làm gì": nó định nghĩa một quy tắc với kết luận dangerous(X), điều này đúng với mọi X vừa hoang dã vừa lớn, vì vậy dangerous(A) trả về A = leopard, A = lion. "Viết một quy tắc: một đặc điểm F có thể có sẵn cho kiểu thân xe B nếu F là một đặc điểm và B là một kiểu thân xe và F không bị loại bỏ đối với B": may_be_available(F, B) IF feature(F) AND body_style(B) AND NOT unavailable(F, B).Sao chép chính xác tên vị từ và thứ tự tham số được sử dụng trong các sự thật của câu hỏi; một sự thật mới kết thúc bằng dấu chấm, và các điều kiện của quy tắc được nối với nhau bằng AND.

So sánh các mô hình

Mô hình Điểm mạnh Các ngôn ngữ điển hình
Mức thấp kiểm soát tối đa, tốc độ assembly
Mệnh lệnh trực tiếp, dễ hiểu C, Python
Hướng đối tượng phân mô-đun, mô phỏng thực thể Java, C#, Python
Hàm rõ ràng, không có tác dụng phụ Haskell, F#
Logic suy luận, quy tắc Prolog
Cơ sở dữ liệu truy vấn dữ liệu SQL

Các ngôn ngữ hiện đại thường kết hợp nhiều mô hình — Python hỗ trợ tất cả các phong cách thủ tục, OOP và hàm. Cách chọn đúng phụ thuộc vào bài toán.

Khám phá

Phòng thí nghiệm khái niệm lập trình

Connect examples to the programming idea they show.

Từ vựng Luyện tập
English Tiếng Việt
programming paradigm/ˈprəʊɡræmɪŋ ˈpærədaɪm/ paradigm lập trình
facts/fækts/ sự thật
rule/ruːl/ quy tắc
low-level/ləʊ ˈlevl/ cấp thấp
registers/ˈredʒɪstəz/ thanh ghi
memory addresses/ˈmeməri əˈdresɪz/ địa chỉ bộ nhớ
objects/ˈɒbdʒekts/ đối tượng
attributes/ˈætrɪbjuːts/ thuộc tính
methods/ˈmeθədz/ phương thức
machine code/məˈʃiːn kəʊd/ mã máy
assembly language/əˈsemblɪ ˈlæŋɡwɪdʒ/ ngôn ngữ assembly
addressing modes/əˈdresɪŋ məʊdz/ chế độ địa chỉ hóa
array/əˈreɪ/ mảng (array)
imperative programming/ɪmˈperətɪv ˈprəʊɡræmɪŋ/ lập trình mệnh lệnh
Variables/ˈveərɪəblz/ Biến (Variables)
object-oriented programming/ˈɒbdʒekt ˈɔːrɪəntɪd ˈprəʊɡræmɪŋ/ lập trình hướng đối tượng
instances/ˈɪnstənsɪz/ thể hiện
classes/ˈklæsɪz/ lớp
encapsulation/ɪnˌkæpsjʊˈleɪʃn/ encapsulation
inheritance/ɪnˈherɪtəns/ di sản
subclass/ˈsʌbklæs/ lớp con
superclass/ˈsuːpəklæs/ siêu lớp
overriding/ˌəʊvəˈraɪdɪŋ/ ghi đè
polymorphism/ˈpɒlɪmɔːfɪzəm/ đa hình
abstraction/əbˈstrækʃn/ trừu tượng hóa
constructor/kənˈstrʌktə/ constructor
aggregation/ˌæɡrɪˈɡeɪʃn/ tổng hợp
containment/kənˈteɪnmənt/ bao hàm
declarative programming/dɪˈklærətɪv ˈprəʊɡræmɪŋ/ lập trình khai báo
functional programming/ˈfʌŋkʃənl ˈprəʊɡræmɪŋ/ lập trình hàm
pure functions/pjʊə ˈfʌŋkʃnz/ hàm thuần túy
side effects/saɪd ɪˈfekts/ tác dụng phụ
logic programming/ˈlɒdʒɪk ˈprəʊɡræmɪŋ/ lập trình logic
SQL/ˌes kjuː ˈel/ SQL
20.2

Xử lý tập tin

Chương trình
Thí sinh cần có thể: Ghi chú và hướng dẫn
Viết mã để thực hiện các thao tác xử lý tập tin Mở (ở chế độ đọc, ghi, kéo dài) và đóng tập tin Đọc một bản ghi từ tập tin và ghi một bản ghi vào tập tin Thực hiện các thao tác xử lý tập tin trên các tập tin dãy, liên tiếp, ngẫu nhiên
Thể hiện sự hiểu biết về ngoại lệ và tầm quan trọng của xử lý ngoại lệ Biết khi nào thích hợp để sử dụng xử lý ngoại lệ Viết mã chương trình để sử dụng xử lý ngoại lệ

Nguồn: Chương trình Cambridge International

Điều này mở rộng phần xử lý tập tin từ Chủ đề 10, bao gồm các tập tin thường (serial), dãy (sequential) và ngẫu nhiên (direct-access). Các thao tác伪码: OPENFILE name FOR READ | WRITE | APPEND (READ mở một tập tin đã tồn tại, WRITE tạo/mở rộng, APPEND thêm vào cuối); READFILE name, line; WRITEFILE name, value; CLOSEFILE name; và EOF(name) là TRUE ở cuối.

Đọc toàn bộ tập tin:

OPENFILE "names.txt" FOR READ
WHILE NOT EOF("names.txt") DO
    READFILE "names.txt", thisName
    OUTPUT thisName
ENDWHILE
CLOSEFILE "names.txt"

Tìm kiếm trong tập tin (dừng khi tìm thấy):

found ← FALSE
OPENFILE "people.txt" FOR READ
WHILE NOT EOF("people.txt") AND NOT found DO
    READFILE "people.txt", line
    IF line = target THEN
        found ← TRUE
    ENDIF
ENDWHILE
CLOSEFILE "people.txt"

Cập nhật tập tin tại chỗ

Hầu hết các ngôn ngữ không thể chỉnh sửa trực tiếp một tập tin văn bản. Thay vào đó: mở tập tin gốc để READ và tập tin tạm để WRITE; với mỗi dòng, viết phiên bản mới nếu nó cần thay đổi, ngược lại viết bản gốc; đóng cả hai; sau đó thay thế tập tin gốc bằng tập tin temp. Mẫu mã tương tự cũng áp dụng cho việc xóa dòng (bỏ qua chúng) và chèn dòng.

Cập nhật tập tin tại chỗ: đọc tập tin gốc, viết các dòng đã sửa sang tập tin temp, sau đó thay thế tập tin gốc bằng tập tin temp
Cập nhật tập tin tại chỗ: đọc tập tin gốc, viết các thay đổi sang tập tin temp, sau đó thay thế tập tin gốc

Bản ghi và tập tin truy cập ngẫu nhiên

Các chế độ mở. READ: tệp phải tồn tại và việc đọc bắt đầu từ đầu. WRITE: một tệp mới được tạo ra, và một tệp có tên tương tự sẽ bị ghi đè. APPEND: việc ghi sẽ thêm vào cuối của một tệp đã tồn tại. Mọi tệp mở đều được đóng bằng CLOSEFILE, và EOF(name) sẽ là TRUE khi mục cuối cùng đã được đọc.

Ba tổ chức tập tin. Trong một tập tin thường (serial), các bản ghi nằm theo thứ tự chúng được thêm vào; trong một tập tin dãy (sequential), chúng nằm theo thứ tự khóa (key); cả hai đều được đọc từ đầu. Một tập tin ngẫu nhiên (tập tin truy cập trực tiếp) lưu trữ mỗi bản ghi tại một địa chỉ được tính từ khóa của nó thông qua một hàm băm (hashing function), do đó tìm thấy một bản ghi mà không cần đọc các bản ghi khác. Các bản ghi được khai báo như một kiểu do người dùng định nghĩa:

TYPE AccountRecord
    DECLARE AccNo : INTEGER
    DECLARE Name : STRING
    DECLARE Balance : REAL
    DECLARE Active : BOOLEAN
ENDTYPE
Khóa 2317 được băm với MOD 1000 thành địa chỉ 317, sau đó SEEK và GETRECORD trên file Acc.dat, hiển thị dưới dạng hàng các ô chứa bản ghi kích thước bằng nhau với ô 317 được đánh dấu
Tìm một bản ghi trong tập tin ngẫu nhiên: khóa được băm thành địa chỉ, con trỏ tập tin di chuyển thẳng đến ô đó và bản ghi được đọc; không bản ghi nào khác bị chạm tới

Các thao tác trên tệp ngẫu nhiên trong giả mã là OPENFILE "Acc.dat" FOR RANDOM, SEEK "Acc.dat", Address (di chuyển con trỏ tệp đến bản ghi đó), GETRECORD "Acc.dat", Rec (đọc bản ghi ở đó) và PUTRECORD "Acc.dat", Rec (ghi bản ghi ở đó). Tìm kiếm khách hàng theo số tài khoản, như Paper 3 thiết lập:

DECLARE Rec : AccountRecord
DECLARE Target, Address : INTEGER
INPUT Target
Address ← Target MOD 1000              // the hashing function
OPENFILE "Acc.dat" FOR RANDOM
SEEK "Acc.dat", Address
GETRECORD "Acc.dat", Rec
WHILE Rec.AccNo <> Target AND Rec.AccNo <> 0    // 0 marks an empty slot
    Address ← Address + 1               // a collision: try the next slot
    SEEK "Acc.dat", Address
    GETRECORD "Acc.dat", Rec
ENDWHILE
IF Rec.AccNo = Target THEN
    OUTPUT Rec.Name, Rec.Balance
ELSE
    OUTPUT "No such account"
ENDIF
CLOSEFILE "Acc.dat"

Để lưu trữ một bản ghi, băm khóa của nó, SEEK đến địa chỉ và PUTRECORD, vượt qua bất kỳ ô nào đã được chiếm giữ. Điểm được trao cho hàm băm, Seek trước Get hoặc Put, so sánh với mục tiêu, xử lý va chạm, và đóng tập tin.

Ví dụ đã giải. ActiveFile.dat chứa AccountRecord bản ghi. Viết伪码 sao chép mọi bản ghi mà trường Active của nó là FALSE vào cuối ArchiveFile.dat.

DECLARE Rec : AccountRecord
OPENFILE "ActiveFile.dat" FOR READ
OPENFILE "ArchiveFile.dat" FOR APPEND
WHILE NOT EOF("ActiveFile.dat")
    READFILE "ActiveFile.dat", Rec
    IF Rec.Active = FALSE THEN
        WRITEFILE "ArchiveFile.dat", Rec
    ENDIF
ENDWHILE
CLOSEFILE "ActiveFile.dat"
CLOSEFILE "ArchiveFile.dat"

Tệp văn bản trong Python (Paper 4): file = open("HighScore.txt", "r"), sau đó for line in file: với line.strip() và line.split(",") để tách các trường, int(…) để chuyển đổi điểm số, và file.close(); để ghi, open(name, "w") (hoặc "a" để thêm vào cuối) và file.write(str(score) + "\n"). Bảng xếp hạng cao nhất được đọc vào một danh sách các bản ghi, điểm mới được chèn vào đúng vị trí, và toàn bộ danh sách được ghi trở lại. Giám khảo chấm điểm dựa trên việc mở với chế độ đúng, vòng lặp đọc từng dòng, chuyển đổi văn bản sang số, và đóng tệp.

Những bẫy

Quên đóng tập tin (dữ liệu có thể bị mất); mở để WRITE khi ý là APPEND (ghi đèEverything); đọc vượt quá EOF; đường dẫn cứng-coded — một đường dẫn như /Users/Admin/data.txt sẽ lỗi trên máy khác, vì vậy hãy sử dụng hằng tương đối như DataFile = "./data/scores.txt".

Khám phá

Đường dẫn truy cập tập tin

Theo dõi tập tin từ bộ lưu trữ đến chương trình và trở lại an toàn.

Từ vựng Luyện tập
English Tiếng Việt
file/faɪl/ tệp
random file/ˈrændəm faɪl/ tệp ngẫu nhiên
hashing/ˈhæʃɪŋ/ hashing
20.2

Xử lý ngoại lệ

Một lỗi ngoại lệ là một lỗi hoặc điều kiện không mong muốn xảy ra trong quá trình thực thi — chia cho số 0, không tìm thấy tập tin, lỗi mạng, chỉ mục mảng vượt quá giới hạn. Xử lý lỗi ngoại lệ cho phép chương trình phát hiện nó và phản hồi một cách thanh lịch thay vì bị dừng đột ngột.

Điều này quan trọng vì các chương trình thực tế đối mặt với những lỗi không thể ngăn chặn từ trước (tập tin bị di chuyển, mạng ngừng hoạt động, dữ liệu đầu vào sai); nếu không có nó, mỗi thao tác đều cần kiểm tra IF riêng; và nó tách biệt luồng bình thường khỏi xử lý lỗi, giúp đường dẫn chính dễ đọc hơn. Ví dụ, một tập tin có thể bị xóa bởi người dùng khác giữa lúc chương trình của bạn kiểm tra sự tồn tại của nó và thực sự mở nó ra — bạn không thể ngăn chặn điều đó, chỉ có thể xử lý sự cố khi nó xảy ra.

"Mô tả, kèm theo ví dụ, ý nghĩa của một lỗi ngoại lệ" (hai điểm). Một sự kiện bất ngờ hoặc lỗi xảy ra trong quá trình thực thi của chương trình (thời gian chạy) và ngắt ngang luồng hoạt động bình thường của nó; ví dụ như chia cho số 0, mở một tập tin không tồn tại, chuyển đổi đầu vào không phải số thành số nguyên, chỉ mục mảng vượt quá giới hạn, hoặc hết bộ nhớ. "Xác định hai nguyên nhân có thể gây ra lỗi ngoại lệ" được trả lời dựa trên danh sách đó, cộng thêm "một thiết bị hoặc mạng không khả dụng" và "dữ liệu loại không hợp lệ đã nhập".

"Nêu lý do để bao gồm xử lý lỗi ngoại lệ" (ba điểm). Để ngăn chương trình bị dừng đột ngột (kết thúc không mong muốn); để xuất ra thông điệp có ý nghĩa cho người dùng thay vì lỗi hệ thống; để cho phép chương trình phục hồi và tiếp tục, ví dụ bằng cách yêu cầu nhập lại, hoặc đóng các tập tin an toàn trước khi kết thúc; và vì một số lỗi không thể dự đoán được khi viết chương trình. "Mô tả cách tránh việc kết thúc chương trình do lỗi ngoại lệ": đặt các câu lệnh có thể sinh ra lỗi ngoại lệ bên trong khối THỬ; viết một khối TRỪ (bắt) cho lỗi ngoại lệ đó để xử lý nó, ví dụ bằng cách xuất thông điệp, để việc thực thi tiếp tục sau khối thay vì dừng lại. "Giải thích ý nghĩa của việc xử lý lỗi ngoại lệ": phát hiện lỗi ngoại lệ khi nó xảy ra và chạy mã (gọi là xử lý viên) giải quyết vấn đề đó để chương trình tiếp tục hoạt động.

Mẫu

TRY
    OPENFILE "data.txt" FOR READ
    READFILE "data.txt", line
    OUTPUT line
    CLOSEFILE "data.txt"
EXCEPT FileNotFound
    OUTPUT "Sorry, the file does not exist."
EXCEPT ReadError
    OUTPUT "Sorry, error reading the file."
ENDTRY

Khối TRY chứa mã code có thể thất bại; khối EXCEPT khớp đầu tiên sẽ chạy. Các ngôn ngữ thực tế còn có một khối bắt tất cả EXCEPT và một khối FINALLY chạy dù có hay không có lỗi ngoại lệ xảy ra — hữu ích cho việc dọn dẹp (đóng tập tin).

Luồng xử lý lỗi ngoại lệ: nếu khối THỬ sinh ra lỗi ngoại lệ, điều khiển nhảy sang khối TRỪ tương ứng; không có lỗi thì bỏ qua. Dù thế nào thì khối CUỐI CÙNG cũng chạy, sau đó chương trình tiếp tục *Luồng xử lý lỗi ngoại lệ: một lỗi ngoại lệ nhảy sang khối TRỪ tương ứng; CUỐI CÙNG luôn chạy trước khi chương trình tiếp tục

Đẩy lên một lỗi ngoại lệ

Một hàm con phát hiện ra lỗi có thể đẩy lên một lỗi ngoại lệ để người gọi xử lý:

PROCEDURE Divide(a : INTEGER, b : INTEGER) RETURNS INTEGER
    IF b = 0 THEN
        RAISE DivideByZero
    ENDIF
    RETURN a DIV b
ENDPROCEDURE

Nơi xử lý lỗi ngoại lệ

Xử lý chúng gần với lỗi nếu phản hồi đơn giản (thông điệp, thử lại), hoặc ở phía trên ngàn gọi nếu chỉ mã code ngoài cùng mới biết phải làm gì (vòng lặp giao diện đồ họa cấp cao ghi log lỗi và hiển thị hộp thoại thân thiện). Không吞 chửng lỗi ngoại lệ im lặng — ít nhất hãy ghi log chúng, nếu không việc gỡ lỗi sẽ trở nên bất khả thi.

Các lỗi ngoại lệ phổ biến: FileNotFound, IOError, DivisionByZero, IndexOutOfRange, InvalidArgument, NullReference, OutOfMemory. Bao bọc mỗi thao tác thất bại trong một TRY với các xử lý viên EXCEPT phù hợp mang lại cho chương trình khả năng giảm nhẹ gracefully thay vì bị dừng đột ngột.

Ví dụ có lời giải (Paper 4). Viết một hàm đọc các số nguyên, mỗi số trên một dòng, từ một tệp có tên được truyền dưới dạng tham số và trả về chúng trong một danh sách. Hàm không được lỗi nếu tệp không tồn tại hoặc một dòng không phải là số nguyên.

def read_scores(filename):
    scores = []
    try:
        file = open(filename, "r")
        for line in file:
            scores.append(int(line))
        file.close()
    except FileNotFoundError:
        print("The file", filename, "does not exist")
    except ValueError:
        print("A line in the file was not a whole number")
    return scores

Khối try chứa mã code có thể thất bại (lệnh mở và lệnh chuyển đổi); mỗi except nêu tên một lỗi ngoại lệ và thực hiện một hành động hữu ích; hàm vẫn trả về một danh sách, nên người gọi tiếp tục. Trong Java, cấu trúc tương tự là try { … } catch (FileNotFoundException e) { … } catch (NumberFormatException e) { … }; trong VB.NET là Try … Catch ex As FileNotFoundException … End Try. Điểm số: các câu lệnh rủi ro bên trong try, tên lỗi ngoại lệ đúng, thông điệp cho mỗi trường hợp, và chương trình tiếp tục sau đó; một khối bắt tất cả except: sẽ mất điểm nhưng không mất điểm "lỗi ngoại lệ phù hợp".

Ví dụ đã giải. Một tập tin văn bản chứa danh sách thành viên cần thay đổi số điện thoại của một thành viên. Tại sao chương trình không thể chỉ ghi đè lên dòng đó, và mẫu là gì? Các dòng của tập tin văn bản có chiều dài khác nhau, và tập tin không có khoảng trống để hấp thụ sự chênh lệch: một dòng thay thế dài hơn sẽ tràn sang bản ghi tiếp theo, và một dòng ngắn hơn sẽ để lại phần của dòng cũ. Vì vậy, mẫu là mở tập tin gốc để ĐỌC và một tập tin tạm thời để GHI, đọc từng dòng lần lượt, viết phiên bản mới cho dòng thay đổi và dòng gốc cho tất cả các dòng khác, đóng cả hai, sau đó thay thế tập tin gốc bằng tập tin tạm thời. Cấu trúc tương tự cũng áp dụng cho việc xóa (bỏ qua dòng) và chèn (viết dòng bổ sung). Lưu ý rằng mọi dòng đều được viết, không chỉ dòng bị thay đổi - chỉ viết bản ghi mới và mất đi phần còn lại của file là lỗi sai lầm điển hình.

Khám phá

Cách xử lý ngoại lệ vận hành

Trình tự những gì xảy ra khi mã thất bại. Ngoại lệ nhảy ra khỏi luồng bình thường sang một trình xử lý, FINALLY làm sạch dù có hay không có lỗi, và chương trình tiếp tục thay vì sập.

Từ vựng Luyện tập
English Tiếng Việt
exception/ekˈsepʃn/ trạng thái ngoại lệ
exception handling/ekˈsepʃn ˈhændlɪŋ/ xử lý trạng thái ngoại lệ
raise/reɪz/ tăng
call stack/kɔːl stæk/ ngăn xếp gọi
20.2

Các định nghĩa mà giám khảo chấp nhận

Câu hỏi định nghĩa được chấm dựa trên văn phong cố định. Hãy học thuộc những định nghĩa này và chỉ đưa ra một đáp án duy nhất.

Thuật ngữ Định nghĩa
mô hình lập trình một phong cách hoặc cách thức lập trình, với phương pháp riêng để cấu trúc hóa chương trình
ngôn ngữ mệnh lệnh chương trình là một chuỗi các câu lệnh thay đổi trạng thái của chương trình; lập trình viên nói rõ cách thực hiện nhiệm vụ
ngôn ngữ khai báo chương trình nêu các sự thật và quy tắc, và động cơ suy luận tìm ra cách tìm đáp án
lớp một khuôn khổ xác định các thuộc tính và phương thức của các đối tượng thuộc loại đó
đối tượng (thể hiện) một sự xuất hiện của một lớp, với các giá trị riêng cho các thuộc tính
thuộc tính một mục dữ liệu thuộc về một lớp
phương thức một thủ tục hoặc hàm thuộc về một lớp và tác động lên các thuộc tính của nó
封装 将属性和方法组合在类中,并限制外部对数据的访问,使其仅通过公共方法进行更改
继承 子类获得其父类的属性和方法,并可添加或覆盖它们
多态 名称相同但针对不同类表现不同的方法
构造器 对象创建时运行并初始化其属性的方法
包含 一个类将另一个类的对象作为其属性之一
事实 声明式程序中为真的语句
规则 当条件为真时成立的结论
顺序、串行、随机文件 记录按添加顺序排列;记录按键值顺序排列;每个记录位于根据其键值计算出的地址处
异常 执行期间意外发生的中断正常流程的错误或事件
异常处理 检测到异常发生时运行相应的代码来处理它,从而使程序继续运行
20.2

Mẹo làm bài thi

  • 范式:掌握每种范式的单行描述,并能根据代码示例识别该范式;低级问题涉及五种寻址模式以及累加器接收的内容。
  • OOP定义每次考试都会出现:类、对象、属性、方法、封装、继承、多态、构造器。用伪代码编写一个带有私有属性、公有NEW和获取器的类;一个带有INHERITS和SUPER.NEW的子类。
  • 声明式:带有变量的目标会返回所有匹配的事实;规则是IF(条件由AND连接)的结论;准确复制题目中的谓词名称。
  • 文件:三种模式及其对现有文件的作用;WHILE NOT EOF循环中的READFILE;随机文件使用哈希、SEEK、GETRECORD和PUTRECORD,并存在碰撞时的覆盖风险。
  • 异常:带例子的定义、处理异常的三个原因,以及允许程序继续运行的TRY和命名EXCEPT。

Lỗi thường gặp

  • 将声明式程序描述为“给出答案的一系列步骤”;它陈述什么是真的以及想要什么,而不是怎么做。
  • 混淆对象与类,或实例与属性;题目问“对象的实例”时应回答instance。
  • 将属性声明为PUBLIC,或从类外部直接访问而非通过获取器,这会破坏封装标记。
  • 子类构造器直接设置父类属性而未调用SUPER.NEW。
  • 解释多态为“许多对象”;实际上是相同的方法名在不同类中表现不同。
  • 以FOR WRITE方式打开文件以添加记录,这会销毁现有内容;应使用APPEND。
  • 从头读取随机文件;首先SEEK至哈希地址。
  • 将异常处理器包裹在不会出错的代码周围,或使用无消息捕获一切,或将异常处理描述为“用IF检查输入”。

Bài học tương tác về chủ đề này

Làm theo từng bước, kèm theo bài tập kiểm tra ngay lập tức.

Đề thi cũ

Nhiều chủ đề hơn trong Khoa học máy tính A-Level

Đăng nhập hoặc tạo tài khoản

IGCSE, A-Level & AP