Mẫu trạng thái
Thuộc phần Lập trình hướng đối tượng trong hành trình Python của Coddy. Bài học 53 trên 64.
Mẫu trạng thái (State Pattern) cho phép một đối tượng thay đổi hành vi khi trạng thái nội bộ của nó thay đổi. Đối tượng trông như thể thay đổi lớp dựa trên trạng thái hiện tại của nó.
Đây là các lớp trạng thái đơn giản cho đèn giao thông:
class RedState:
def next_state(self, light):
print("Red -> Green")
light.state = GreenState()
def current_color(self):
return "Red"
class GreenState:
def next_state(self, light):
print("Green -> Yellow")
light.state = YellowState()
def current_color(self):
return "Green"
class YellowState:
def next_state(self, light):
print("Yellow -> Red")
light.state = RedState()
def current_color(self):
return "Yellow"Mỗi trạng thái xác định điều gì xảy ra khi chuyển sang trạng thái tiếp theo.
Tạo một lớp ngữ cảnh lưu trạng thái hiện tại:
class TrafficLight:
def __init__(self):
self.state = RedState() # Bắt đầu với màu đỏ
def change(self):
self.state.next_state(self)
def get_color(self):
return self.state.current_color()Đèn giao thông giao việc xử lý cho đối tượng trạng thái hiện tại.
Sử dụng đèn giao thông:
light = TrafficLight()
print(f"Current: {light.get_color()}")
light.change() # Đỏ sang xanh lá
print(f"Current: {light.get_color()}")
light.change() # Xanh lá sang vàng
print(f"Current: {light.get_color()}")
light.change() # Vàng sang đỏ
print(f"Current: {light.get_color()}")Tạo thêm một ví dụ với trình phát nhạc đơn giản:
class PlayingState:
def play(self, player):
print("Already playing")
def stop(self, player):
print("Stopping music")
player.state = StoppedState()
class StoppedState:
def play(self, player):
print("Starting music")
player.state = PlayingState()
def stop(self, player):
print("Already stopped")
class MusicPlayer:
def __init__(self):
self.state = StoppedState()
def play(self):
self.state.play(self)
def stop(self):
self.state.stop(self)
player = MusicPlayer()
player.play() # Đang bắt đầu phát nhạc
player.play() # Đang phát nhạc rồi
player.stop() # Đang dừng phát nhạc
player.stop() # Đã dừng phát nhạc rồiĐầu ra:
Current: Red
Red -> Green
Current: Green
Green -> Yellow
Current: Yellow
Yellow -> Red
Current: Red
Starting music
Already playing
Stopping music
Already stoppedÝ chính: Mẫu trạng thái đóng gói hành vi riêng của từng trạng thái trong các lớp riêng biệt và cho phép đối tượng ngữ cảnh ủy quyền cho trạng thái hiện tại. Khi trạng thái thay đổi, hành vi cũng tự động thay đổi. Nhờ đó, bạn không cần dùng các câu lệnh if/else phức tạp và có thể thêm trạng thái mới dễ dàng hơn.
Thử thách
DễTriển khai mẫu State trong state.py cho một chiếc đèn có một nút bấm. Mỗi lần nhấn, đèn chuyển qua ba trạng thái theo chu kỳ: tắt, sáng yếu, sáng mạnh, rồi quay lại trạng thái tắt. Thay vì dùng một chuỗi if, mỗi trạng thái là một đối tượng riêng và biết điều gì xảy ra khi bạn nhấn nút.
LampStatelà lớp cơ sở cópress(lamp)vàdescribe().OffState,LowStatevàHighStatetriển khai các phương thức này:pressgọilamp.set_state(...)với trạng thái tiếp theo (tắt sang sáng yếu, sáng yếu sang sáng mạnh, sáng mạnh sang tắt), còndescribetrả vềLamp is off,Lamp is on lowhoặcLamp is on high.Lamplà ngữ cảnh: đèn bắt đầu ở trạng tháiOffState,set_statethay thế đối tượng trạng thái,press_buttonủy quyền cho trạng thái hiện tại, cònstatustrả về mô tả trạng thái hiện tại.
driver.py bị khóa: tệp này nhấn nút và in trạng thái. Lưu ý rằng Lamp không bao giờ kiểm tra mình đang ở trạng thái nào; các đối tượng trạng thái sẽ quyết định.
Tự làm thử
from state import Lamp
# Phần xử lý test case (không thay đổi)
test_case = input()
lamp = Lamp()
if test_case == "initial_test":
print(lamp.status())
elif test_case == "one_press_test":
lamp.press_button()
print(lamp.status())
elif test_case == "cycle_test":
for _ in range(4):
print(lamp.status())
lamp.press_button()
elif test_case == "many_presses_test":
for _ in range(7):
lamp.press_button()
print(lamp.status())
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng về lập trình hướng đối tượng
Tệp bên ngoàiGiới thiệu về lập trình hướng đối tượngLớp và đối tượngTham số selfPhương thứcThuộc tínhPhương thức khởi tạo (__init__)Ôn tập: máy tính đơn giản4Kế thừa
Kế thừa cơ bảnHàm super()Ghi đè phương thứcKế thừa đa lớpThứ tự phân giải phương thứcÔn tập: hệ thống phân cấp nhân viên2Decorator
Giới thiệu về decoratorDecorator thuộc tínhDecorator phương thức tĩnhDecorator phương thức lớp5Tính đa hình
Xem lại cách ghi đè phương thứcKiểu gõ vịtLớp và phương thức trừu tượngThiết kế giao diệnÔn tập: máy tính hình học8Các khái niệm OOP nâng cao
Kết hợp và kế thừaMixinPhương thức tĩnh và phương thức lớpDecorator lớpTrình quản lý ngữ cảnh11Mẫu thiết kế phần 2
Mẫu lệnhMẫu bộ chuyển đổiMẫu trang tríMẫu phương thức khuôn mẫuMẫu trạng tháiMẫu tổng hợpTự luyện tập: Trình biên dịch Python online