Wzorzec fabryki
Część sekcji Programowanie obiektowe ścieżki C# w Coddy. Lekcja 53 z 70.
Wzorzec fabryki to wzorzec kreacyjny, który deleguje tworzenie obiektów do osobnej metody lub klasy. Zamiast używać bezpośrednio new w swoim kodzie, prosisz fabrykę o utworzenie obiektów. Dzięki temu logika tworzenia jest scentralizowana, a kod staje się bardziej elastyczny.
Rozważmy sytuację, w której musisz tworzyć różne typy dokumentów. Bez fabryki Twój kod staje się ściśle powiązany z konkretnymi klasami:
// Bez Factory - rozproszona logika tworzenia
IDocument doc;
if (type == "pdf")
doc = new PdfDocument();
else if (type == "word")
doc = new WordDocument();Fabryka hermetyzuje podejmowanie tej decyzji w jednym miejscu:
public interface IDocument
{
void Open();
}
public class PdfDocument : IDocument
{
public void Open() => Console.WriteLine("Opening PDF");
}
public class WordDocument : IDocument
{
public void Open() => Console.WriteLine("Opening Word");
}
public class DocumentFactory
{
public IDocument Create(string type)
{
switch (type)
{
case "pdf":
return new PdfDocument();
case "word":
return new WordDocument();
default:
throw new ArgumentException("Unknown type");
}
}
}Teraz kod klienta po prostu żąda tego, czego potrzebuje, nie znając konkretnych klas:
var factory = new DocumentFactory();
IDocument doc = factory.Create("pdf");
doc.Open(); // Otwieranie PDFWzorzec Fabryki sprawdza się, gdy później trzeba dodać nowe typy. Dodanie SpreadsheetDocument wymaga zmian tylko w fabryce, a nie we wszystkich miejscach, w których tworzone są dokumenty. Ten podział ułatwia utrzymanie i testowanie bazy kodu.
Wyzwanie
ŁatwyZbudujmy system powiadomień z użyciem wzorca Fabryka. Zamiast tworzyć różne typy powiadomień bezpośrednio w całym kodzie, scentralizujesz logikę ich tworzenia w klasie fabryki, która na podstawie prostego identyfikatora tekstowego zdecyduje, które powiadomienie utworzyć.
Podzielisz kod na trzy pliki:
Notification.cs: Zdefiniuj interfejsINotificationw przestrzeni nazwNotificationsz jedną metodąSend(string message), która zwraca ciąg znaków. Następnie utwórz trzy klasy implementujące ten interfejs:EmailNotification— zwraca"Email: {message}"SmsNotification— zwraca"SMS: {message}"PushNotification— zwraca"Push: {message}"
NotificationFactory.cs: Utwórz klasęNotificationFactoryw tej samej przestrzeni nazw, z metodąCreate(string type), która zwraca odpowiedni obiektINotificationna podstawie ciągu określającego typ:"email"zwraca obiektEmailNotification"sms"zwraca obiektSmsNotification"push"zwraca obiektPushNotification
EmailNotification.Program.cs: Połącz wszystko, tworząc instancję fabryki i używając jej do tworzenia powiadomień na podstawie danych wejściowych. Fabryka zajmuje się podejmowaniem wszystkich decyzji dotyczących tego, którą konkretną klasę utworzyć.
Otrzymasz dwa dane wejściowe:
- Typ powiadomienia (np.
sms) - Wiadomość do wysłania (np.
Your order has shipped)
Użyj fabryki, aby utworzyć odpowiedni typ powiadomienia, następnie wywołaj jego metodę Send z wiadomością i wyświetl wynik.
Na przykład, jeśli danymi wejściowymi są push i Meeting in 5 minutes, wynikiem powinno być:
Push: Meeting in 5 minutesZauważ, że główny kod nigdy nie używa new EmailNotification() ani podobnego wyrażenia — po prostu prosi fabrykę o to, czego potrzebuje. Jeśli później dodasz klasę SlackNotification, wystarczy zaktualizować fabrykę, a nie każde miejsce, w którym tworzone są powiadomienia!
Spróbuj swoich sił
using System;
using Notifications;
class Program
{
public static void Main(string[] args)
{
// Wczytaj dane wejściowe
string type = Console.ReadLine();
string message = Console.ReadLine();
// TODO: Utwórz instancję NotificationFactory
// TODO: Użyj fabryki, aby utworzyć odpowiednie powiadomienie
// TODO: Wywołaj metodę Send i wypisz wynik
}
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrznePrzestrzenie nazw i dyrektywyWprowadzenie do klas i obiektówSłowo kluczowe „this”Metody i parametryPola a właściwościKonstruktoryInicjalizatory obiektówPodsumowanie — prosty kalkulator4Dziedziczenie
Podstawowa składnia dziedziczenia (:)Słowo kluczowe 'base'Słowa kluczowe virtual i overrideKlasy sealedBazowa klasa 'object'Powtórzenie – hierarchia pracowników7Zaawansowane funkcje
Przeciążanie operatorówIndeksery (this[])Nadpisywanie ToString()Metody rozszerzającePodsumowanie – własna lista10Wzorce projektowe — część 1
Wprowadzenie do wzorców projektowychSingleton bezpieczny wątkowoWzorzec fabrykiWzorzec obserwatora (zdarzenia)Wzorzec strategii2Właściwości i składowe statyczne
Właściwości automatyczneWłaściwości tylko do odczytu i zapisuPola i metody statyczneKlasy statyczneSkładowe z ciałem wyrażeniowym5Polimorfizm i interfejsy
Polimorfizm czasu kompilacji a czasu wykonaniaInterfejs a klasa abstrakcyjnaWiele interfejsówJawne implementowanie interfejsówRzutowanie w górę i w dółPowtórka — kalkulator kształtów8Zaawansowane koncepcje OOP
Kompozycja zamiast dziedziczeniaTypy generyczne (klasy i metody)Delegaty i zdarzeniaAtrybuty i refleksjaIDisposable i instrukcja usingPodstawy wstrzykiwania zależności11Wzorce projektowe, część 2
Wzorzec poleceniaWzorzec adapteraWzorzec dekoratoraWzorzec metody szablonowejWzorzec stanuWzorzec kompozytu3Architektura klas
Dane instancji a dane statyczneSłowa kluczowe 'readonly' i 'const'Pola zapasowePowtórzenie — menedżer kont bankowych6Hermetyzacja
Modyfikatory dostępuWłaściwości w hermetyzacjiImplementacja ukrywania danychWzorce niezmiennościPowtórka — dane studentów9Argumenty zmiennej liczby
Słowo kluczowe „params”Parametry opcjonalneArgumenty nazwanePrzeciążanie metodPoćwicz samodzielnie: Kompilator C# online