Các mẫu thiết kế có được sử dụng trong Python không?

Trong phát triển phần mềm, các mẫu thiết kế là một giải pháp đã được chứng minh cho một vấn đề phổ biến trong một ngữ cảnh cụ thể.  

Mục tiêu chính của họ là chỉ cho chúng ta những cách hay để lập trình mọi thứ và giải thích tại sao các tùy chọn khác không hoạt động.  

Sử dụng các mẫu thiết kế phổ biến, bạn có thể

  • Đẩy nhanh quá trình phát triển;
  • Giảm số dòng mã;
  • Đảm bảo mã của bạn được thiết kế tốt;
  • Dự đoán các vấn đề trong tương lai phát sinh từ các vấn đề nhỏ

Các mẫu thiết kế có thể cải thiện đáng kể cuộc sống của nhà phát triển phần mềm bất kể (các) ngôn ngữ lập trình mà anh ta sử dụng.  

Tôi chủ yếu làm việc với Python/Django, vì vậy đây là danh sách các mẫu hàng đầu trong Python mà tôi sử dụng hàng ngày trong công việc của mình

nội dung

Các mẫu thiết kế có được sử dụng trong Python không?

Mẫu hành vi

Trình lặp

Iterator cho phép duyệt qua các phần tử của bộ sưu tập mà không để lộ các chi tiết bên trong.  

Trường hợp sử dụng. Hầu hết, tôi sử dụng nó để cung cấp một cách tiêu chuẩn để duyệt qua các bộ sưu tập.  

➕ Clean client code (Single Responsibility Principle)

➕ Có thể giới thiệu các trình vòng lặp trong các bộ sưu tập mà không cần thay đổi mã của máy khách (Nguyên tắc Mở/Đóng)

➕ Mỗi đối tượng lặp có trạng thái lặp riêng, vì vậy bạn có thể trì hoãn và tiếp tục lặp

➖ Việc sử dụng các trình vòng lặp với các bộ sưu tập đơn giản có thể làm quá tải ứng dụng.  

Cấu trúc

Các mẫu thiết kế có được sử dụng trong Python không?

Ví dụ về mã

from __future__ import annotations
from collections.abc import Iterable, Iterator
from typing import Any, List


class AlphabeticalOrderIterator(Iterator):
    _position: int = None
    _reverse: bool = False

    def __init__(self, collection: WordsCollection, 
                 reverse: bool = False):
        self._collection = collection
        self._reverse = reverse
        self._position = -1 if reverse else 0

    def __next__(self):
        try:
            value = self._collection[self._position]
            self._position += -1 if self._reverse else 1
        except IndexError:
            raise StopIteration()
        return value


class WordsCollection(Iterable):
    def __init__(self, collection: List[Any] = []):
        self._collection = collection

    def __iter__(self) -> AlphabeticalOrderIterator:
        return AlphabeticalOrderIterator(self._collection)

    def get_reverse_iterator(self) -> AlphabeticalOrderIterator:
        return AlphabeticalOrderIterator(self._collection, True)

    def add_item(self, item: Any):
        self._collection.append(item)


if __name__ == "__main__":
    collection = WordsCollection()
    collection.add_item("First")
    collection.add_item("Second")
    collection.add_item("Third")

    print("Straight traversal:")
    print("\n".join(collection))

    print("Reverse traversal:")
    print("\n".join(collection.get_reverse_iterator()))

Tiểu bang

Trạng thái giúp một đối tượng thay đổi hành vi của nó trong trường hợp trạng thái bên trong của nó thay đổi.  

Trường hợp sử dụng. Nhà nước giúp tôi

  • Thay đổi số lượng lớn các trạng thái đối tượng.  
  • Giảm số dòng có mã trùng lặp trong các chuyển đổi và trạng thái tương tự
  • Tránh các điều kiện lớn

➕ Tuân theo nguyên tắc Trách nhiệm duy nhất. các lớp riêng biệt cho mã liên quan đến một trạng thái khác

➕ Không thay đổi ngữ cảnh hoặc trạng thái của lớp khi thêm trạng thái mới (Nguyên tắc Mở/Đóng)

➖ Sử dụng Trạng thái có thể là quá nhiều trong trường hợp máy trạng thái hầu như không thay đổi

Cấu trúc

Các mẫu thiết kế có được sử dụng trong Python không?

Ví dụ về mã

from __future__ import annotations
from abc import ABC, abstractmethod


class Context(ABC):
    _state = None

    def __init__(self, state: State):
        self.transition_to(state)

    def transition_to(self, state: State):
        print(f"Context: Transition to {type(state).__name__}")
        self._state = state
        self._state.context = self

    def request1(self):
        self._state.handle1()

    def request2(self):
        self._state.handle2()


class State(ABC):
    @property
    def context(self) -> Context:
        return self._context

    @context.setter
    def context(self, context: Context):
        self._context = context

    @abstractmethod
    def handle1(self):
        pass

    @abstractmethod
    def handle2(self):
        pass


class ConcreteStateA(State):
    def handle1(self):
        print("ConcreteStateA handles request1.")
        print("ConcreteStateA wants to change the state of the context.")
        self.context.transition_to(ConcreteStateB())

    def handle2(self):
        print("ConcreteStateA handles request2.")


class ConcreteStateB(State):
    def handle1(self):
        print("ConcreteStateB handles request1.")

    def handle2(self):
        print("ConcreteStateB handles request2.")
        print("ConcreteStateB wants to change the state of the context.")
        self.context.transition_to(ConcreteStateA())


if __name__ == "__main__":
    context = Context(ConcreteStateA())
    context.request1()
    context.request2()

người quan sát

Người quan sát thông báo về các sự kiện xảy ra trong các đối tượng khác mà họ quan sát mà không liên kết với các lớp của họ.  

trường hợp sử dụng. Mỗi lần tôi cần thêm cơ chế đăng ký để cho phép một đối tượng đăng ký/hủy đăng ký nhận thông báo về các sự kiện xảy ra với một lớp nhà xuất bản cụ thể, tôi sử dụng mẫu Người quan sát.  

Một ví dụ điển hình là đăng ký tin tức đơn giản từ bất kỳ tạp chí trực tuyến nào, thường có tùy chọn để chọn lĩnh vực bạn quan tâm (khoa học, công nghệ kỹ thuật số, v.v. ). Ngoài ra, nút “Thông báo cho tôi khi có hàng” cho các nền tảng thương mại điện tử là một ví dụ khác

➕ Bạn không phải thay đổi mã của nhà xuất bản để thêm các lớp của người đăng ký

➖ Người đăng ký nhận thông báo theo thứ tự ngẫu nhiên.  

Cấu trúc

Các mẫu thiết kế có được sử dụng trong Python không?

Ví dụ về mã

from __future__ import annotations
from abc import ABC, abstractmethod
from random import randrange
from typing import List


class Subject(ABC):
    @abstractmethod
    def attach(self, observer: Observer):
        pass

    @abstractmethod
    def detach(self, observer: Observer):
        pass

    @abstractmethod
    def notify(self):
        pass


class ConcreteSubject(Subject):
    _state: int = None
    _observers: List[Observer] = []
   
    def attach(self, observer: Observer):
        print("Subject: Attached an observer.")
        self._observers.append(observer)

    def detach(self, observer: Observer):
        self._observers.remove(observer)

    def notify(self):
        print("Subject: Notifying observers...")
        for observer in self._observers:
            observer.update(self)

    def some_business_logic(self):
        print("Subject: I'm doing something important.")
        self._state = randrange(0, 10)
        print(f"Subject: My state has just changed to: {self._state}")
        self.notify()


class Observer(ABC):
    @abstractmethod
    def update(self, subject: Subject):       
        pass


class ConcreteObserverA(Observer):
    def update(self, subject: Subject):
        if subject._state < 3:
            print("ConcreteObserverA: Reacted to the event")


class ConcreteObserverB(Observer):
    def update(self, subject: Subject):
        if subject._state == 0 or subject._state >= 2:
            print("ConcreteObserverB: Reacted to the event")


if __name__ == "__main__":    
    subject = ConcreteSubject()

    observer_a = ConcreteObserverA()
    subject.attach(observer_a)

    observer_b = ConcreteObserverB()
    subject.attach(observer_b)

    subject.some_business_logic()
    subject.some_business_logic()

    subject.detach(observer_a)

    subject.some_business_logic()

mô hình cấu trúc

mặt tiền

Mặt tiền cung cấp giao diện đơn giản nhưng hạn chế để giảm độ phức tạp của ứng dụng. Các hệ thống con phức tạp với nhiều bộ phận chuyển động có thể được “che dấu” bởi Facade.  

trường hợp sử dụng. Tôi tạo lớp Mặt tiền trong trường hợp tôi phải làm việc với các thư viện và API phức tạp và/hoặc tôi chỉ cần một phần chức năng của chúng.  

➕ Độ phức tạp của hệ thống được tách biệt khỏi mã

➖ Sử dụng mẫu Mặt tiền, bạn có thể tạo đối tượng thần.  

Cấu trúc

Các mẫu thiết kế có được sử dụng trong Python không?

Ví dụ về mã

class Addition:
    def __init__(self, field1: int, field2: int):
        self.field1 = field1
        self.field2 = field2

    def get_result(self):
        return self.field1 + self.field2


class Multiplication:
    def __init__(self, field1: int, field2: int):
        self.field1 = field1
        self.field2 = field2

    def get_result(self):
        return self.field1 * self.field2


class Subtraction:
    def __init__(self, field1: int, field2: int):
        self.field1 = field1
        self.field2 = field2

    def get_result(self):
        return self.field1 - self.field2


class Facade:
    @staticmethod
    def make_addition(*args) -> Addition:
        return Addition(*args)

    @staticmethod
    def make_multiplication(*args) -> Multiplication:
        return Multiplication(*args)

    @staticmethod
    def make_subtraction(*args) -> Subtraction:
        return Subtraction(*args)


if __name__ == "__main__":
    addition_obj = Facade.make_addition(5, 5)
    multiplication_obj = Facade.make_multiplication(5, 2)
    subtraction_obj = Facade.make_subtraction(15, 5)

    print(addition_obj.get_result())
    print(multiplication_obj.get_result())
    print(subtraction_obj.get_result())

Người trang trí

Trình trang trí gắn các hành vi mới vào các đối tượng mà không sửa đổi cấu trúc của chúng.  

Mẫu tạo ra một lớp trang trí để bọc lớp gốc và thêm chức năng mới.   

trường hợp sử dụng. Tôi sử dụng mẫu Trình trang trí mỗi khi tôi cần thêm các hành vi bổ sung cho các đối tượng mà không cần nhập mã.  

➕ Thay đổi hành vi của đối tượng mà không tạo lớp con

➕ Bạn có thể kết hợp một số hành vi bằng cách gói một đối tượng vào nhiều trang trí

➖ Khó có thể xóa một trình trang trí cụ thể khỏi ngăn xếp trình bao bọc.  

Cấu trúc

Các mẫu thiết kế có được sử dụng trong Python không?

Ví dụ về mã

class my_decorator:
    def __init__(self, func):
        print("inside my_decorator.__init__()")
        func() # Prove that function definition has completed

    def __call__(self):
        print("inside my_decorator.__call__()")


@my_decorator
def my_function():
    print("inside my_function()")


if __name__ == "__main__":    
    my_function()

bộ chuyển đổi

Bộ điều hợp đóng vai trò là lớp trung gian để tham gia các chức năng của các giao diện độc lập hoặc không tương thích

trường hợp sử dụng. Thiết lập sự cộng tác giữa các giao diện, tôi sử dụng mẫu Adapter để giải quyết vấn đề định dạng không tương thích.  

Ví dụ, Adapter có thể giúp chuyển đổi định dạng dữ liệu XML sang JSON để phân tích sâu hơn.  

➕ Cho phép tách giao diện khỏi logic nghiệp vụ

➕ Thêm bộ điều hợp mới không làm hỏng mã của máy khách

➖ Tăng độ phức tạp của mã

Cấu trúc

Các mẫu thiết kế có được sử dụng trong Python không?

Ví dụ về mã

class Target:
    def request(self):
        return "Target: The default target's behavior."


class Adaptee:
    def specific_request(self):
        return ".eetpadA eht fo roivaheb laicepS"


class Adapter(Target, Adaptee):
    def request(self):
        return f"Adapter: (TRANSLATED) {self.specific_request()[::-1]}"


def client_code(target: "Target"):
    print(target.request())


if __name__ == "__main__":
    print("Client: I can work just fine with the Target objects:")

    target = Target()
    client_code(target)

    adaptee = Adaptee()
    
    print("Client: The Adaptee class has a weird interface. "
          "See, I don't understand it:")
    print(f"Adaptee: {adaptee.specific_request()}")

    print("Client: But I can work with it via the Adapter:")
    
    adapter = Adapter()
    client_code(adapter)

mô hình sáng tạo

Độc thân

Singleton hạn chế một lớp có nhiều hơn một phiên bản và đảm bảo một điểm truy cập toàn cầu cho phiên bản này.  

trường hợp sử dụng. Singleton giúp tôi với

  • Quản lý tài nguyên được chia sẻ. tôi. e. một cơ sở dữ liệu, trình quản lý tệp hoặc bộ đệm máy in được chia sẻ bởi nhiều phần của ứng dụng.  
  • Lưu trữ trạng thái chung (trợ giúp filepath, ngôn ngữ người dùng, đường dẫn ứng dụng, v.v. )
  • Tạo một logger đơn giản

➕ Lớp có một thể hiện duy nhất

➖ Vi phạm SRP (Nguyên tắc Trách nhiệm Đơn lẻ).  

➖ Khó kiểm tra mã đơn vị vì phần lớn các khung kiểm tra sử dụng tính kế thừa khi tạo các đối tượng giả.  

Cấu trúc

Các mẫu thiết kế có được sử dụng trong Python không?

Ví dụ về mã

class Singleton:
    def __new__(cls):
        if not hasattr(cls, 'instance'):
            cls.instance = super(Singleton, cls).__new__(cls)
        return cls.instance


if __name__ == "__main__":
    s = Singleton()
    print("Object created:", s)

    s1 = Singleton()
    print("Object created:", s1)

Khi nào nên sử dụng các mẫu thiết kế cho Python?

Mặt tiền phù hợp khi bạn cần một giao diện hợp nhất cho một số tùy chọn API. Tôi. e. bạn nên tích hợp một hệ thống thanh toán trong ứng dụng, để lại khả năng thay đổi nó. Trong trường hợp này, bạn có thể sử dụng mẫu Mặt tiền và bạn sẽ chỉ phải tạo một mặt tiền mới mà không cần viết lại toàn bộ ứng dụng

Vấn đề ở đây có thể xuất hiện nếu chỉ có các API khá khác biệt, vì việc thiết kế giao diện chung cho các mặt tiền không phải là một nhiệm vụ dễ dàng.   

Trạng thái được sử dụng để quản lý nhiều thành phần độc lập của một ứng dụng với điều kiện là kiến ​​trúc ban đầu hàm ý sự độc lập của chúng. Vì vậy, tạo một mô-đun riêng để quản lý trạng thái có thể là một ý tưởng hay, cũng như sử dụng mẫu Người quan sát.  

Trình trang trí có lẽ là mẫu Python được sử dụng nhiều nhất, vì hỗ trợ trình trang trí tích hợp sẵn. Ví dụ: Trình trang trí cung cấp một cách thuận tiện và rõ ràng để sử dụng một số thư viện và tạo cơ hội ngày càng phong phú hơn cho thiết kế và quản lý ứng dụng. Mẫu cũng đảm bảo nhiều khả năng cho thành phần chức năng và khám phá các cơ hội mới trong lập trình chức năng.  

Bộ điều hợp phù hợp khi làm việc với một lượng lớn dữ liệu ở các định dạng khác nhau. Mẫu cho phép sử dụng một thuật toán thay vì nhiều thuật toán cho mọi định dạng dữ liệu.  

Các lợi ích tương tự mà Iterator có, vì vậy chúng có thể được sử dụng cùng nhau. Ngoài ra, một trong những biến thể của Iterator được gọi là Trình tạo (được giới thiệu trong Python từ lâu) cho phép sử dụng bộ nhớ hiệu quả hơn để làm việc với lượng dữ liệu lớn có giá trị cao đối với một số loại dự án.  

Cuối cùng, không thể đánh giá thấp tầm quan trọng của Singleton. kết nối cơ sở dữ liệu, làm việc với API, làm việc với tệp… Tất cả đều là những thời điểm mà nhà phát triển nên có ý tưởng rõ ràng về quy trình diễn ra như thế nào để tránh mắc lỗi. Và Singleton có thể làm tốt công việc này, chưa kể đến khả năng giảm mức tiêu thụ bộ nhớ bằng cách sử dụng cùng một phiên bản mỗi lần thay vì sao chép nó.  

Các mẫu thiết kế có liên quan trong Python không?

Một số mẫu thiết kế được tích hợp sẵn trong Python, vì vậy chúng tôi sử dụng chúng ngay cả khi không biết. Các mẫu khác là không cần thiết do bản chất của ngôn ngữ . Ví dụ: Factory là một mẫu thiết kế cấu trúc Python nhằm mục đích tạo các đối tượng mới, ẩn logic khởi tạo khỏi người dùng.

Mẫu thiết kế nào được sử dụng nhiều nhất trong Python?

Decorator có lẽ là mẫu Python được sử dụng nhiều nhất vì có hỗ trợ trình trang trí sẵn có.

Mẫu thiết kế trong Python là gì?

Mẫu thiết kế là kỹ thuật được nhà phát triển sử dụng để giải quyết vấn đề thiết kế phần mềm thường xảy ra . Nói một cách đơn giản, đó là một mẫu xác định trước để giải quyết vấn đề định kỳ trong mã. Các mẫu này chủ yếu được thiết kế dựa trên phân tích yêu cầu. Mẫu thiết kế là một phần của quá trình phát triển phần mềm.

Ngôn ngữ nào là tốt nhất cho các mẫu thiết kế?

Để học các mẫu thiết kế, bạn có thể muốn Java hoặc C# . Những ngôn ngữ đó có xu hướng được sử dụng bởi những người coi các mẫu thiết kế là cách viết ngôn ngữ thành ngữ. tôi. e. mọi người coi việc sử dụng nhiều mẫu thiết kế trong Java hoặc C# là cách viết C# hoặc Java "đúng".