Okej, låt oss utforska några enkla designmönster som kan vara till hjälp i olika projekt. Dessa mönster är relativt enkla att förstå och implementera, och de kan förbättra kodkvaliteten, underhållbarhet och återanvändbarhet.
1. Singleton
* Syfte: Säkerställer att endast en instans av en klass skapas och ger en global åtkomstpunkt till den instansen.
* När man ska använda: När du behöver en singel, delad resurs (t.ex. konfigurationshanterare, databasanslutningspool, logger).
* Simple Exempel (Python):
`` `python
klass singleton:
_Instance =ingen
def __new __ (cls, *args, ** kwargs):
Om inte cls._instance:
CLS._Instance =Super (Singleton, CLS) .__ Ny __ (CLS, *args, ** Kwargs)
# Initiera instansen här om det behövs
returnera cls._instance
# Användning
instans1 =singleton ()
instans2 =singleton ()
utskrift (instans1 är instans2) # utgång:sant (de är samma objekt)
`` `
* Anmärkningar: Var försiktig med Singletons i kraftigt multittrade miljöer. Du kan behöva lägga till låsmekanismer för att säkerställa trådsäkerhet under skapandet av instanser. Överanvändning av singletoner kan leda till snäv koppling och göra det svårt att testa.
2. Fabriksmetod
* Syfte: Definierar ett gränssnitt för att skapa ett objekt, men låter underklasser bestämma vilken klass du ska instansera. Det frikopplar klientkoden från den specifika klassen som skapas.
* När man ska använda: När du behöver skapa objekt av olika typer baserat på något skick eller konfiguration, och du vill undvika att hårdkodning av objektskapande logik direkt i klientkoden.
* Simple Exempel (Python):
`` `python
Klassknapp:
def render (self):
höja notimplementEdError ()
klass htmlButton (knapp):
def render (self):
returnera "
html -knapp
"
Klass Windows -knapp (knapp):
def render (self):
Return "Windows -knapp (UI -specifik)"
Klassknappfaktory:
def create_button (self, knapp_type):
om knapp_typ =="html":
returnera htmlButton ()
ELIF Button_Type =="Windows":
Return WindowsButton ()
annan:
höja ValueError ("Ogiltig knapptyp")
# Användning
Factory =ButtonFactory ()
html_Button =Factory.Create_Button ("html")
Windows_Button =Factory.Create_Button ("Windows")
utskrift (html_button.render ()) # utgång:
html -knapp
Skriv ut (Windows_Button.Render ()) # Output:Windows -knapp (UI -specifik)
`` `
* Anmärkningar: Fabriksmetoden låter dig lägga till nya knapptyper utan att modifiera klassen "ButtonFactory" direkt (öppen/stängd princip).
3. Strategi
* Syfte: Definierar en familj av algoritmer, kapslar in var och en och gör dem utbytbara. Strategi låter algoritmen variera oberoende från klienter som använder den.
* När man ska använda: När du har flera sätt att utföra en specifik uppgift och vill kunna växla mellan dem enkelt vid körning.
* Simple Exempel (Python):
`` `python
Klassbetalningstrategi:
def pay (själv, belopp):
höja notimplementEdError ()
Klass CreditCardPayment (betalningstrategi):
def __init __ (self, card_number, expiry_date, cvv):
self.card_number =card_number
self.expiry_date =expiry_date
self.cvv =cvv
def pay (själv, belopp):
utskrift (f "betala $ {belopp} med kreditkort:{self.card_number}")
klass PayPalPayment (betalningstrategi):
def __init __ (själv, e -post):
self.email =e -post
def pay (själv, belopp):
utskrift (f "betala $ {belopp} med PayPal:{self.email}")
Klass Shopping Cart:
def __init __ (Self, Payment_Strategy:PaymentStrategy):# Strategi injicerad här
Self.Payment_Strategy =Payment_Strategy
self.total =0
def add_item (själv, pris):
self.total +=pris
def checkout (self):
self.payment_strategy.pay (self.total)
# Användning
Credit_card =CreditCardPayment ("1234-5678-9012-3456", "12/24", "123")
PayPal =PayPalPayment ("user@example.com")
cart1 =shoppingcart (credit_card)
Cart1.Add_Item (100)
Cart1.Add_Item (50)
Cart1.Checkout () # Output:Betala $ 150 med kreditkort:1234-5678-9012-3456
cart2 =shoppingcart (PayPal)
cart2.add_item (200)
cart2.Checkout () # Output:Betala $ 200 med PayPal:user@example.com
`` `
* Anmärkningar: "ShoppingCart" behöver inte veta den specifika betalningsmetoden. Den använder helt enkelt den injicerade "betalningstrategin" för att utföra betalningen. Detta gör det enkelt att lägga till nya betalningsmetoder utan att ändra klassen "ShoppingCart".
4. Observatör
* Syfte: Definierar ett en-till-många-beroende mellan objekt så att när ett objekt ändras tillstånd, meddelas och uppdateras alla dess beroende automatiskt.
* När man ska använda: När en förändring i ett objekt kräver att du ändrar andra objekt och du inte vill att objekten ska vara tätt kopplade. Exempel:Händelsehantering, UI-uppdateringar, Model-View-Controller (MVC) Architecture.
* Simple Exempel (Python):
`` `python
Klassämne:
def __init __ (själv):
self._observers =[]
def bifogas (själv, observatör):
self._observers.append (observatör)
def lossning (själv, observatör):
self._observers.remove (observatör)
Def meddela (själv, meddelande):
för observatör i self._observers:
observatör.update (meddelande)
Klassobservatör:
DEF -uppdatering (själv, meddelande):
höja notimplementEdError ()
Klass ConcreteObServera (observatör):
DEF -uppdatering (själv, meddelande):
tryck (f "Observer A mottagen:{meddelande}")
Klass BetongetoBserverB (Observer):
DEF -uppdatering (själv, meddelande):
utskrift (f "observatör b mottagen:{message.upper ()}")
# Användning
ämne =ämne ()
observatör_a =concretetoBServera ()
observatör_b =betongetoBserverB ()
Ämne.Attach (observatör_a)
ämne.Attach (observatör_b)
Ämne.notify ("Hej, värld!") # UTGÅNG:Observatör A mottagen:Hej, värld!
# Observer B Mottaget:Hej, världen!
Ämne.Detach (observatör_a)
Ämne.notify ("Goodbye!") # UTGÅNG:Observatör B Mottagen:Goodbye!
`` `
* Anmärkningar: "Ämnet" upprätthåller en lista över "observatörer". När "ämnets" -stillstånd förändras (i detta fall, när "meddela" kallas), itereras det genom listan och kallar "Update" -metoden på varje "observatör".
5. Mallmetod
* Syfte: Definierar skelettet i en algoritm i en basklass men låter underklasser åsidosätta specifika steg i algoritmen utan att ändra strukturen.
* När man ska använda: När du har en uppsättning steg som måste utföras i en specifik ordning, men några av dessa steg kan variera beroende på den specifika implementeringen.
* Simple Exempel (Python):
`` `python
klass dataprocessor:
def process_data (self):
self.read_data ()
self.validate_data ()
self.transform_data ()
self.save_data ()
Skriv ut ("Databehandling komplett.")
def read_data (själv):
höja notimplementEdError ()
def validate_data (self):
Skriv ut ("Standardvalidering:Kontroll för nollvärden.")
def transform_data (self):
höja notimplementEdError ()
def save_data (själv):
höja notimplementEdError ()
Klass CSVDataProcessor (DataProcessor):
def read_data (själv):
Skriv ut ("Läsdata från CSV -fil.")
def transform_data (self):
Skriv ut ("Transformering av CSV -data.")
def save_data (själv):
Skriv ut ("Spara data i databasen.")
Klass JSONDATAPROCESSOR (DATAPROCESSOR):
def read_data (själv):
Skriv ut ("Läsdata från JSON -filen.")
def validate_data (self):
Skriv ut ("Anpassad validering för JSON -data:Kontrollering av schema.")
def transform_data (self):
tryck ("Transformering JSON Data.")
def save_data (själv):
Skriv ut ("Spara data i JSON -fil.")
# Användning
CSV_PROCESSOR =CSVDataProcessor ()
csv_processor.process_data ()
# Output:
# Att läsa data från CSV -filen.
# Standardvalidering:Kontrollera för nollvärden.
# Transformering av CSV -data.
# Spara data i databasen.
# Databehandling Komplett.
JSON_PROCESSOR =JSONDATAPROCESSOR ()
JSON_PROCESSOR.PROCESS_DATA ()
# Output:
# Läser data från JSON -filen.
# Anpassad validering för JSON -data:Kontrollering av schema.
# Transformering av JSON -data.
# Spara data i JSON -filen.
# Databehandling Komplett.
`` `
* Anmärkningar: "DataProcessor" definierar den övergripande strukturen för databehandlingsalgoritmen. Underklasser som `CSVDataProcessor` och` JSondataProcessor 'ger specifika implementeringar för stegen' Read_data ',' transform_data 'och' Save_Data '. Steget `validat_data 'kan åsidosättas eller använda standardimplementeringen.
6. Dekoratör
* Syfte: Dynamiskt lägger ansvar för ett objekt utan att modifiera dess klass. Dekoratörer ger ett flexibelt alternativ till underklassning för att utöka funktionaliteten.
* När man ska använda: När du vill lägga till funktionalitet till ett objekt vid körning utan att påverka andra objekt i samma klass. Användbart för att lägga till loggning, cachning eller auktorisation.
* Simple Exempel (Python):
`` `python
Klasskaffe:
def get_cost (self):
Retur 5
def get_description (self):
returnera "kaffe"
Klass CoffeeDecorator:
def __init __ (själv, kaffe):
self._coffee =kaffe
def get_cost (self):
returnera self._coffee.get_cost ()
def get_description (self):
returnera self._coffee.get_description ()
Klass Milkdecorator (CoffeeDecorator):
def get_cost (self):
returnera self._coffee.get_cost () + 2
def get_description (self):
returnera self._coffee.get_description () + ", mjölk"
Klass SugardeCorator (CoffeeDecorator):
def get_cost (self):
returnera self._coffee.get_cost () + 1
def get_description (self):
returnera self._coffee.get_description () + ", socker"
# Användning
kaffe =kaffe ()
utskrift (f "{Coffee.get_Description ()} - Kostnad:$ {Coffee.get_cost ()}") # Output:Kaffe - Kostnad:$ 5
Milk_Coffee =Milkdecorator (kaffe)
utskrift (f "{mjölk_coffee.get_description ()} - kostnad:$ {mjölk_coffee.get_cost ()}") # utgång:kaffe, mjölk - kostnad:$ 7
Sugar_Milk_Coffee =sugardeCorator (MILK_COFFEE)
utskrift (f "{socker_milk_coffee.get_description ()} - kostnad:$ {socker_milk_coffee.get_cost ()}") # utgång:kaffe, mjölk, socker - kostnad:$ 8
`` `
* Anmärkningar: "CoffeeDecorator" tillhandahåller en basklass för dekoratörer. Varje dekoratör (t.ex. "Milkdecorator", "SugardeCorator") lindar det ursprungliga "kaffe" -objektet och lägger till sin egen funktionalitet (i detta fall lägger till kostnad och beskrivning).
Nyckelöverväganden för att välja ett mönster:
* Förstå problemet: Definiera tydligt problemet du försöker lösa innan du når ett mönster. Använd inte blindt mönster; Använd dem som verktyg för att förbättra din kod.
* enkelhet: Börja med den enklaste lösningen som uppfyller dina behov. Inte överkonstruktör saker för tidigt.
* Kontext: Det bästa mönstret beror på det specifika sammanhanget för ditt projekt, språket du använder och den befintliga kodbasen.
* testning: Designmönster bör göra din kod mer testbar, inte mindre. Se till att du enkelt kan skriva enhetstester för de komponenter du använder.
Det här är bara några exempel på enkla designmönster. När du får mer erfarenhet lär du dig att känna igen situationer där dessa och andra mönster kan tillämpas för att skapa mer robusta, underhållbara och återanvändbara kod. Lycka till!