Design Patterns with Python – Creational Design Patterns

python.png

bài trước tôi có giới thiệu với các bạn về khái niệm Design Patterns và điểm qua các Design Patterns. Hôm nay tôi sẽ đi sâu vào một số Pattern qua các ví dụ được viết bằng ngôn ngữ Python.

Phần I – Creational Design Patterns (Mẫu kiến tạo)

  1. Abstract Factory

Mục đích của Abstract Factory là nhằm trừu tượng hoá việc tạo ra các objects tuỳ theo business logic, platform, vân vân.

Ví dụ như chúng ta tạo ra các con vật nuôi (pet) phụ thuộc vào Factory ta chọn (Dog, Cat, hay random_animal). Chúng ta sẽ tạo ra các con vật một cách trừu tượng và sau đó mới quyết định lựa chọn con vật cụ thể nào dựa theo một số tiêu chí nhất định, chẳng hạn chó được ưu tiên hơn so với mèo.

Hãy xem đoạn code sau:


import random
class PetShop(object):
"""Cửa hàng thú cưng"""
def __init__(self, animal_factory=None):
"""pet_factory là abstract factory. Chúng ta có thể tuỳ ý lựa chọn pet"""
self.pet_factory = animal_factory
def show_pet(self):
"""Tạo và hiển thị pet bằng abstract factory"""
pet = self.pet_factory()
print("We have a lovely {}".format(pet))
print("It says {}".format(pet.speak()))
class Dog(object):
def speak(self):
return "woof"
def __str__(self):
return "Dog"
class Cat(object):
def speak(self):
return "meow"
def __str__(self):
return "Cat"
# Tạo random animal
def random_animal():
"""Thú cưng được chọn ngẫu nhiên!"""
return random.choice([Dog, Cat])()
# Hiển thị pets với các factory khác nhau
if __name__ == "__main__":
# Shop này chỉ bán mèo
cat_shop = PetShop(Cat)
cat_shop.show_pet()
print("")
# Shop này bán pet ngẫu nhiên
shop = PetShop(random_animal)
for i in range(3):
shop.show_pet()
print("=" * 20)
### OUTPUT ###
# We have a lovely Cat
# It says meow
#
# We have a lovely Dog
# It says woof
# ====================
# We have a lovely Cat
# It says meow
# ====================
# We have a lovely Cat
# It says meow
# ====================

view raw

pet.js

hosted with ❤ by GitHub

Ở ví dụ trên ta có thể thấy PetShop là một abstract factory và tạo ra một pet trừu tượng pet = self.pet_factory() trong đó self.pet_factory() được truyền vào động (dynamically), có thể là Cat hoặc Dog, hoặc một hàm trả về giá trị Cat hoặc Dog dựa vào các yếu tố nhất định.

2. Builder (Người xây dựng)

Nhằm mục đích phân tách việc tạo ra một object phức tạp ra khỏi biễu diễn của nó, nhờ đó mà tiến trình giống nhau có thể tạo ra các object từ cùng một họ.

Cùng xem ví dụ sau:

# Abstract Building
class Building(object):

    def __init__(self):
        self.build_floor()
        self.build_size()

    def build_floor(self):
        raise NotImplementedError

    def build_size(self):
        raise NotImplementedError

    def __repr__(self):
        return 'Floor: {0.floor} | Size: {0.size}'.format(self)


# Concrete Buildings
class House(Building):

    def build_floor(self):
        self.floor = 'One'

    def build_size(self):
        self.size = 'Big'

class Flat(Building):

    def build_floor(self):
        self.floor = 'More than One'

    def build_size(self):
        self.size = 'Small'

if __name__ == "__main__": 
    house = House() 
    print(house) 
    flat = Flat() 
    print(flat) 

### OUTPUT ### 
# Floor: One | Size: Big 
# Floor: More than One | Size: Small

Ở đây việc tạo ra object được định nghĩa ở abstract class thông qua hàm __init__(). Trong một số trường hợp phức tạp, có thể chúng ta muốn tách việc tạo object thành một function riêng (hoặc một method của một class khác).

class ComplexBuilding(object):
    def __repr__(self):
        return 'Floor: {0.floor} | Size: {0.size}'.format(self)

class ComplexHouse(ComplexBuilding):
    def build_floor(self):
        self.floor = 'One'

    def build_size(self):
        self.size = 'Big and fancy'

def construct_building(cls):
    building = cls()
    building.build_floor()
    building.build_size()
    return building

if __name__ == "__main__":
    # Dùng hàm khởi tạo bên ngoài class:
    complex_house = construct_building(ComplexHouse)
    print(complex_house)

### OUTPUT ###
# Floor: One | Size: Big and fancy

Như vậy ComplexBuilding không còn có hàm tạo object __init__() nữa, thay vào đó ta định nghĩa một hàm có tên construct_building() để tạo ra một object dựa vào class truyền vào.

3. Factory Method (Phương pháp nhà máy)

Factory Method dùng để tạo ra một giao diện của một method, và việc thực thi method đó sẽ do class được khởi tạo thực hiện.

class GreekGetter(object):

    def __init__(self):
        self.trans = dict(dog="σκύλος", cat="γάτα")

    def get(self, msgid):
    """We'll punt if we don't have a translation"""
        return self.trans.get(msgid, str(msgid))


class EnglishGetter(object):

    def get(self, msgid):
        return str(msgid)

def get_localizer(language="English"):
"""factory method"""
    languages = dict(English=EnglishGetter, Greek=GreekGetter)
    return languages[language]()


if __name__ == '__main__':
    # Create our localizers
    e, g = get_localizer(language="English"), get_localizer(language="Greek")
    # Localize some text
    for msgid in "dog parrot cat bear".split():
        print(e.get(msgid), g.get(msgid))

### OUTPUT ###
# dog σκύλος
# parrot parrot
# cat γάτα
# bear bear

Trong ví dụ trên, hàm get_localizer() không trực tiếp translate mà chỉ khởi tạo một object từ một class khác, sau đó việc translate được thực hiện thông qua method get() của class đó. Cụ thể e = get_localizer(language=”English”) tương đương với gọi việc khởi tạo e =  EnglishGetter() và sau đó gọi e.get(msgidđể thực hiện việc translate.

Việc tạo động class như vậy sẽ giúp chúng ta có sự linh hoạt trong việc thực thi code. Ở đây ta chỉ cần truyền vào một giá trị language (một biến mà người dùng chọn trên trang web để chọn ngôn ngữ). Và ta gọi hàm e = get_localizer(language) để tạo ra một instance của class thực thi translate, sau đó gọi hàm e.get(msgid) .  Chú ý là ta không cần để ý e thuộc class nào bởi vì các class ta tạo ra có cùng cấu trúc, như vậy sẽ che giấu được việc thực hiện cụ thể ở mức dưới.

Leave a comment