Uurige Pythoni loomisdisaini malle: Singleton, Factory, Abstract Factory, Builder ja Prototype. Siit saate teada nende rakendused, eelised ja rakendused.
Pythoni disainimallid: sĂĽgav sukeldumine loomismallidesse
Disainimallid on korduvkasutatavad lahendused tavalistele probleemidele tarkvara disainis. Need pakuvad malli nende probleemide lahendamiseks, soodustades koodi korduvkasutatavust, hooldatavust ja paindlikkust. Loomisdisaini mallid, täpsemalt, tegelevad objektide loomise mehhanismidega, püüdes luua objekte vastavalt olukorrale sobival viisil. Käesolev artikkel pakub põhjalikku ülevaadet Pythoni loomisdisaini mallidest, sealhulgas üksikasjalikke selgitusi, koodinäiteid ja praktilisi rakendusi, mis on relevantseid globaalsele publikule.
Mis on loomisdisaini mallid?
Loomisdisaini mallid abstraheerivad instansseerimisprotsessi. Nad lahutavad kliendikoodi konkreetsetest instansseeritavatest klassidest, võimaldades suuremat paindlikkust ja kontrolli objektide loomise üle. Nende mallide abil saate luua objekte, ilma et peaksite täpsustama objekti täpset klassi, mida hakatakse looma. See vastutuse eraldamine muudab koodi robustsemaks ja kergemini hooldatavaks.
Loomismallide peamine eesmärk on abstraheerida objektide instansseerimisprotsess, varjates objektide loomise keerukust kliendi eest. See võimaldab arendajatel keskenduda oma rakenduste kõrgtasemelisele loogikale, ilma et nad oleksid koormatud objektide loomise pisiasjadega.
Loomisdisaini mallide tĂĽĂĽbid
Käesolevas artiklis käsitleme järgmisi loomisdisaini malle:
- Singleton: tagab, et klassil on ainult üks eksemplar ja pakub sellele globaalset juurdepääsupunkti.
- Factory Method: määratleb objekti loomise liidese, kuid laseb alamklassidel otsustada, millist klassi instansseerida.
- Abstract Factory: pakub liidest seotud või sõltuvate objektide perekondade loomiseks, ilma nende konkreetseid klasse täpsustamata.
- Builder: eraldab keeruka objekti loomise selle esitusest, võimaldades sama loomisprotsessi abil luua erinevaid esitusi.
- Prototype: määratleb loomiseks vajalike objektide tüübi prototüüpse eksemplari abil ja loob uusi objekte selle prototüübi kopeerides.
1. Singletoni mall
Singletoni mall tagab, et klassil on ainult üks eksemplar ja pakub sellele globaalset juurdepääsupunkti. See mall on kasulik, kui süsteemi toimingute koordineerimiseks on vaja täpselt ühte objekti. Seda kasutatakse sageli ressursside, logimise või konfiguratsiooniseadete haldamiseks.
Rakendamine
Siin on Pythoni rakendus Singletoni mallile:
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance
# Näitekasutus
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # Väljund: True
Selgitus:
_instance: see klassimuutuja salvestab klassi ĂĽhe eksemplari.__new__: seda meetodit kutsutakse enne__init__, kui objekt luuakse. See kontrollib, kas eksemplar juba eksisteerib. Kui ei, siis loob see uue eksemplari, kasutadessuper().__new__(cls), ja salvestab selle_instancemuutujasse. Kui eksemplar juba eksisteerib, tagastab see olemasoleva eksemplari.
Kasutusjuhud
- Andmebaasi ĂĽhendus: tagab, et korraga on avatud ainult ĂĽks ĂĽhendus andmebaasiga.
- Konfiguratsioonihaldur: pakub ühte juurdepääsupunkti rakenduse konfiguratsiooniseadetele.
- Logija: loob ühe logimise eksemplari, et hallata kõiki rakenduse logimistoiminguid.
Näide
Vaatleme lihtsat konfiguratsioonihalduri näidet, mis on rakendatud Singletoni malli abil:
class ConfigurationManager(Singleton):
def __init__(self):
if not hasattr(self, 'config'): # Tagab, et __init__ kutsutakse ainult ĂĽks kord
self.config = {}
def set_config(self, key, value):
self.config[key] = value
def get_config(self, key):
return self.config.get(key)
# Näitekasutus
config_manager1 = ConfigurationManager()
config_manager1.set_config('database_url', 'localhost:5432')
config_manager2 = ConfigurationManager()
print(config_manager2.get_config('database_url')) # Väljund: localhost:5432
2. Factory Methodi mall
Factory Methodi mall määratleb objekti loomise liidese, kuid laseb alamklassidel otsustada, millist klassi instansseerida. Factory Method laseb klassil instansseerimise alamklassidele edasi lükata. See mall soodustab nõrka sidumist ja võimaldab teil lisada uusi toote tüüpe ilma olemasolevat koodi muutmata.
Rakendamine
Siin on Pythoni rakendus Factory Methodi mallile:
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
pass
class Dog(Animal):
def speak(self):
return "Woof!"
class Cat(Animal):
def speak(self):
return "Meow!"
class AnimalFactory(ABC):
@abstractmethod
def create_animal(self):
pass
class DogFactory(AnimalFactory):
def create_animal(self):
return Dog()
class CatFactory(AnimalFactory):
def create_animal(self):
return Cat()
# Kliendikood
def get_animal(factory: AnimalFactory):
animal = factory.create_animal()
return animal.speak()
dog_sound = get_animal(DogFactory())
cat_sound = get_animal(CatFactory())
print(f"Dog says: {dog_sound}") # Väljund: Dog says: Woof!
print(f"Cat says: {cat_sound}") # Väljund: Cat says: Meow!
Selgitus:
Animal: abstraktne baasklass, mis määratleb kõigi loomade tüüpide liidese.DogjaCat: konkreetsed klassid, mis rakendavadAnimalliidest.AnimalFactory: abstraktne baasklass, mis määratleb loomade loomise liidese.DogFactoryjaCatFactory: konkreetsed klassid, mis rakendavadAnimalFactoryliidest ja on vastutavadDogjaCateksemplaride loomise eest.get_animal: kliendifunktsioon, mis kasutab tehast looma loomiseks ja kasutamiseks.
Kasutusjuhud
- UI raamistikud: platvormispetsiifiliste UI elementide (nt nupud, tekstiväljad) loomine, kasutades erinevaid tehaseid erinevate operatsioonisüsteemide jaoks.
- Mängude arendus: erinevat tüüpi mängutegelaste või objektide loomine mängutaseme või kasutaja valiku põhjal.
- Dokumentide töötlemine: erinevat tüüpi dokumentide (nt PDF, Word, HTML) loomine, kasutades erinevaid tehaseid vastavalt soovitud väljundvormingule.
Näide
Vaatleme stsenaariumi, kus soovite luua erinevat tĂĽĂĽpi makseviise vastavalt kasutaja valikule. Siin on, kuidas saate seda Factory Methodi malli abil rakendada:
from abc import ABC, abstractmethod
class Payment(ABC):
@abstractmethod
def process_payment(self, amount):
pass
class CreditCardPayment(Payment):
def process_payment(self, amount):
return f"Processing credit card payment of ${amount}"
class PayPalPayment(Payment):
def process_payment(self, amount):
return f"Processing PayPal payment of ${amount}"
class PaymentFactory(ABC):
@abstractmethod
def create_payment_method(self):
pass
class CreditCardPaymentFactory(PaymentFactory):
def create_payment_method(self):
return CreditCardPayment()
class PayPalPaymentFactory(PaymentFactory):
def create_payment_method(self):
return PayPalPayment()
# Kliendikood
def process_payment(factory: PaymentFactory, amount):
payment_method = factory.create_payment_method()
return payment_method.process_payment(amount)
credit_card_payment = process_payment(CreditCardPaymentFactory(), 100)
paypal_payment = process_payment(PayPalPaymentFactory(), 50)
print(credit_card_payment) # Väljund: Processing credit card payment of $100
print(paypal_payment) # Väljund: Processing PayPal payment of $50
3. Abstract Factory mall
Abstract Factory mall pakub liidest seotud või sõltuvate objektide perekondade loomiseks, ilma nende konkreetseid klasse täpsustamata. See võimaldab teil luua objekte, mis on loodud koos töötama, tagades ühtluse ja ühilduvuse.
Rakendamine
Siin on Pythoni rakendus Abstract Factory mallile:
from abc import ABC, abstractmethod
class Button(ABC):
@abstractmethod
def paint(self):
pass
class Checkbox(ABC):
@abstractmethod
def paint(self):
pass
class GUIFactory(ABC):
@abstractmethod
def create_button(self):
pass
@abstractmethod
def create_checkbox(self):
pass
class WinFactory(GUIFactory):
def create_button(self):
return WinButton()
def create_checkbox(self):
return WinCheckbox()
class MacFactory(GUIFactory):
def create_button(self):
return MacButton()
def create_checkbox(self):
return MacCheckbox()
class WinButton(Button):
def paint(self):
return "Rendering a Windows button"
class MacButton(Button):
def paint(self):
return "Rendering a Mac button"
class WinCheckbox(Checkbox):
def paint(self):
return "Rendering a Windows checkbox"
class MacCheckbox(Checkbox):
def paint(self):
return "Rendering a Mac checkbox"
# Kliendikood
def paint_ui(factory: GUIFactory):
button = factory.create_button()
checkbox = factory.create_checkbox()
return button.paint(), checkbox.paint()
win_button, win_checkbox = paint_ui(WinFactory())
mac_button, mac_checkbox = paint_ui(MacFactory())
print(win_button) # Väljund: Rendering a Windows button
print(win_checkbox) # Väljund: Rendering a Windows checkbox
print(mac_button) # Väljund: Rendering a Mac button
print(mac_checkbox) # Väljund: Rendering a Mac checkbox
Selgitus:
ButtonjaCheckbox: abstraktsete baasklassid, mis määratlevad UI elementide liidesed.WinButton,MacButton,WinCheckboxjaMacCheckbox: konkreetsed klassid, mis rakendavad Windowsi ja Maci platvormide UI elementide liideseid.GUIFactory: abstraktne baasklass, mis määratleb UI elementide perekondade loomise liidese.WinFactoryjaMacFactory: konkreetsed klassid, mis rakendavadGUIFactoryliidest ja on vastutavad vastavalt Windowsi ja Maci platvormide UI elementide loomise eest.paint_ui: kliendifunktsioon, mis kasutab tehast UI elementide loomiseks ja maalrimiseks.
Kasutusjuhud
- UI raamistikud: UI elementide loomine, mis on kooskõlas konkreetse operatsioonisüsteemi või platvormi välimuse ja tundega.
- Mängude arendus: mänguelementide loomine, mis on kooskõlas konkreetse mängutaseme või teema stiiliga.
- Andmete juurdepääs: andmete juurdepääsu objektide loomine, mis ühilduvad konkreetse andmebaasi või andmeallikaga.
Näide
Vaatleme stsenaariumi, kus soovite luua erinevat tüüpi mööblit (nt toole, laudu) erinevate stiilidega (nt modernne, viktoriaanlik). Siin on, kuidas saate seda Abstract Factory malli abil rakendada:
from abc import ABC, abstractmethod
class Chair(ABC):
@abstractmethod
def create(self):
pass
class Table(ABC):
@abstractmethod
def create(self):
pass
class FurnitureFactory(ABC):
@abstractmethod
def create_chair(self):
pass
@abstractmethod
def create_table(self):
pass
class ModernFurnitureFactory(FurnitureFactory):
def create_chair(self):
return ModernChair()
def create_table(self):
return ModernTable()
class VictorianFurnitureFactory(FurnitureFactory):
def create_chair(self):
return VictorianChair()
def create_table(self):
return VictorianTable()
class ModernChair(Chair):
def create(self):
return "Creating a modern chair"
class VictorianChair(Chair):
def create(self):
return "Creating a Victorian chair"
class ModernTable(Table):
def create(self):
return "Creating a modern table"
class VictorianTable(Table):
def create(self):
return "Creating a Victorian table"
# Kliendikood
def create_furniture(factory: FurnitureFactory):
chair = factory.create_chair()
table = factory.create_table()
return chair.create(), table.create()
modern_chair, modern_table = create_furniture(ModernFurnitureFactory())
victorian_chair, victorian_table = create_furniture(VictorianFurnitureFactory())
print(modern_chair) # Väljund: Creating a modern chair
print(modern_table) # Väljund: Creating a modern table
print(victorian_chair) # Väljund: Creating a Victorian chair
print(victorian_table) # Väljund: Creating a Victorian table
4. Builderi mall
Builderi mall eraldab keeruka objekti loomise selle esitusest, võimaldades sama loomisprotsessi abil luua erinevaid esitusi. See on kasulik, kui peate looma keerukaid objekte mitmete valikuliste komponentidega ja soovite vältida suure hulga konstruktorite või konfiguratsiooniparameetrite loomist.
Rakendamine
Siin on Pythoni rakendus Builderi mallile:
class Pizza:
def __init__(self):
self.dough = None
self.sauce = None
self.topping = None
def __str__(self):
return f"Pizza with dough: {self.dough}, sauce: {self.sauce}, and topping: {self.topping}"
class PizzaBuilder:
def __init__(self):
self.pizza = Pizza()
def set_dough(self, dough):
self.pizza.dough = dough
return self
def set_sauce(self, sauce):
self.pizza.sauce = sauce
return self
def set_topping(self, topping):
self.pizza.topping = topping
return self
def build(self):
return self.pizza
# Kliendikood
pizza_builder = PizzaBuilder()
pizza = pizza_builder.set_dough("Thin crust").set_sauce("Tomato").set_topping("Pepperoni").build()
print(pizza) # Väljund: Pizza with dough: Thin crust, sauce: Tomato, and topping: Pepperoni
Selgitus:
Pizza: klass, mis esindab loodavat keerukat objekti.PizzaBuilder: ehitajaklass, mis pakub meetodeidPizzaobjekti erinevate komponentide seadistamiseks.
Kasutusjuhud
- Dokumentide loomine: keerukate dokumentide (nt aruanded, arved) loomine erinevate jaotiste ja vorminguvalikutega.
- Mängude arendus: keerukate mänguelementide (nt tegelased, tasemed) loomine erinevate atribuutide ja komponentidega.
- Andmete töötlemine: keerukate andmestruktuuride (nt graafid, puud) loomine erinevate sõlmede ja seostega.
Näide
Vaatleme stsenaariumi, kus soovite luua erinevat tĂĽĂĽpi arvuteid erinevate komponentidega (nt CPU, RAM, salvestusruum). Siin on, kuidas saate seda Builder malli abil rakendada:
class Computer:
def __init__(self):
self.cpu = None
self.ram = None
self.storage = None
self.graphics_card = None
def __str__(self):
return f"Computer with CPU: {self.cpu}, RAM: {self.ram}, Storage: {self.storage}, Graphics Card: {self.graphics_card}"
class ComputerBuilder:
def __init__(self):
self.computer = Computer()
def set_cpu(self, cpu):
self.computer.cpu = cpu
return self
def set_ram(self, ram):
self.computer.ram = ram
return self
def set_storage(self, storage):
self.computer.storage = storage
return self
def set_graphics_card(self, graphics_card):
self.computer.graphics_card = graphics_card
return self
def build(self):
return self.computer
# Kliendikood
computer_builder = ComputerBuilder()
computer = computer_builder.set_cpu("Intel i7").set_ram("16GB").set_storage("1TB SSD").set_graphics_card("Nvidia RTX 3080").build()
print(computer)
# Väljund: Computer with CPU: Intel i7, RAM: 16GB, Storage: 1TB SSD, Graphics Card: Nvidia RTX 3080
5. Prototype mall
Prototype mall määratleb loomiseks vajalike objektide tüübi prototüüpse eksemplari abil ja loob uusi objekte selle prototüübi kopeerides. See võimaldab teil luua uusi objekte olemasoleva objekti kloonides, vältides vajadust luua objekte algusest peale. See võib olla kasulik, kui objektide loomine on kallis või keeruline.
Rakendamine
Siin on Pythoni rakendus Prototype mallile:
import copy
class Prototype:
def __init__(self):
self._objects = {}
def register_object(self, name, obj):
self._objects[name] = obj
def unregister_object(self, name):
del self._objects[name]
def clone(self, name, **attrs):
obj = copy.deepcopy(self._objects.get(name))
if attrs:
obj.__dict__.update(attrs)
return obj
class Car:
def __init__(self):
self.name = ""
self.color = ""
self.options = []
def __str__(self):
return f"Car: Name={self.name}, Color={self.color}, Options={self.options}"
# Kliendikood
prototype = Prototype()
car = Car()
car.name = "Generic Car"
car.color = "White"
car.options = ["AC", "GPS"]
prototype.register_object("generic", car)
car1 = prototype.clone("generic", name="Sports Car", color="Red", options=["AC", "GPS", "Spoiler"])
car2 = prototype.clone("generic", name="Family Car", color="Blue", options=["AC", "GPS", "Sunroof"])
print(car1)
# Väljund: Car: Name=Sports Car, Color=Red, Options=['AC', 'GPS', 'Spoiler']
print(car2)
# Väljund: Car: Name=Family Car, Color=Blue, Options=['AC', 'GPS', 'Sunroof']
Selgitus:
Prototype: klass, mis haldab prototĂĽĂĽpe ja pakub meetodit nende kloonimiseks.Car: klass, mis esindab kloonitavat objekti.
Kasutusjuhud
- Mängude arendus: sarnaste mänguelementide loomine, nagu vaenlased või jõuallikad.
- Dokumentide töötlemine: mallil põhinevate dokumentide loomine.
- Konfiguratsioonihaldus: vaikimisi konfiguratsioonil põhinevate konfiguratsioonielementide loomine.
Näide
Vaatleme stsenaariumi, kus soovite luua erinevat tüüpi töötajaid erinevate atribuutidega (nt nimi, roll, osakond). Siin on, kuidas saate seda Prototype malli abil rakendada:
import copy
class Employee:
def __init__(self):
self.name = None
self.role = None
self.department = None
def __str__(self):
return f"Employee: Name={self.name}, Role={self.role}, Department={self.department}"
class Prototype:
def __init__(self):
self._objects = {}
def register_object(self, name, obj):
self._objects[name] = obj
def unregister_object(self, name):
del self._objects[name]
def clone(self, name, **attrs):
obj = copy.deepcopy(self._objects.get(name))
if attrs:
obj.__dict__.update(attrs)
return obj
# Kliendikood
prototype = Prototype()
employee = Employee()
employee.name = "Generic Employee"
employee.role = "Developer"
employee.department = "IT"
prototype.register_object("generic", employee)
employee1 = prototype.clone("generic", name="John Doe", role="Senior Developer")
employee2 = prototype.clone("generic", name="Jane Smith", role="Project Manager", department="Management")
print(employee1)
# Väljund: Employee: Name=John Doe, Role=Senior Developer, Department=IT
print(employee2)
# Väljund: Employee: Name=Jane Smith, Role=Project Manager, Department=Management
Kokkuvõte
Loomisdisaini mallid pakuvad võimsaid vahendeid objektide loomise paindlikuks ja hooldatavaks haldamiseks. Neid malle mõistes ja rakendades saate kirjutada puhtama, robustsema koodi, mida on lihtne laiendada ja kohandada muutuvate nõuetega. Käesolev artikkel on uurinud viit peamist loomismalli – Singleton, Factory Method, Abstract Factory, Builder ja Prototype – koos praktiliste näidetega ja reaalmaailma kasutusjuhtudega. Nende mallide omandamine on oluline samm, et saada Pythoni arendajaks.
Pidage meeles, et õige malli valimine sõltub konkreetsetest probleemidest, mida proovite lahendada. Kaaluge objektide loomise keerukust, paindlikkuse vajadust ja võimalust tulevasteks muudatusteks, kui valite oma projekti jaoks loomismalli. Seda tehes saate ära kasutada disainimallide jõudu, et luua elegantseid ja tõhusaid lahendusi tavalistele tarkvara disaini väljakutsetele.