new se volá tovární metoda, kterou podtřídy přepisují (polymorfismus)Factory Method se vyplatí použít, když v době psaní kódu nevíš, s jakým konkrétním typem objektu budeš pracovat – třeba parsování různých formátů (JSON, XML, CSV), napojení na různé platební brány, notifikace přes různé kanály (e-mail, SMS, push), nebo generování dokumentů v různých formátech. Kdykoli máš společné rozhraní a konkrétní implementaci volíš až za běhu podle konfigurace, vstupu uživatele nebo prostředí, je Factory Method čistý způsob, jak se vyhnout rostoucím if/switch blokům a umožnit přidání nového typu bez zásahu do existujícího kódu.
public interface ITransport
{
string Deliver();
}
public class Truck : ITransport
{
public string Deliver() => "Dodávka po silnici kamionem.";
}
public class Ship : ITransport
{
public string Deliver() => "Dodávka po moři lodí.";
}
public abstract class Logistics
{
public abstract ITransport CreateTransport();
public string PlanDelivery()
{
ITransport transport = CreateTransport();
return transport.Deliver();
}
}
public class RoadLogistics : Logistics
{
public override ITransport CreateTransport() => new Truck();
}
public class SeaLogistics : Logistics
{
public override ITransport CreateTransport() => new Ship();
}
Logistics logistics = new SeaLogistics();
Console.WriteLine(logistics.PlanDelivery());
Abstract Factory se vyplatí, když potřebuješ vytvářet skupiny objektů, které musí být konzistentní – třeba UI komponenty pro různé platformy (Windows/Mac/Linux tlačítka, checkboxy, dialogy), databázové konektory s příslušnými command a reader objekty, nebo herní prostředí s odpovídajícími nepřáteli, zbraněmi a terénem. Kdykoli máš více produktů, které musí k sobě stylově/logicky pasovat a nesmíš je míchat, je Abstract Factory správná volba.
public interface IButton
{
string Render();
}
public interface ICheckbox
{
string Render();
}
public class WinButton : IButton
{
public string Render() => "Windows button";
}
public class WinCheckbox : ICheckbox
{
public string Render() => "Windows checkbox";
}
public class MacButton : IButton
{
public string Render() => "Mac button";
}
public class MacCheckbox : ICheckbox
{
public string Render() => "Mac checkbox";
}
public interface IGUIFactory
{
IButton CreateButton();
ICheckbox CreateCheckbox();
}
public class WinFactory : IGUIFactory
{
public IButton CreateButton() => new WinButton();
public ICheckbox CreateCheckbox() => new WinCheckbox();
}
public class MacFactory : IGUIFactory
{
public IButton CreateButton() => new MacButton();
public ICheckbox CreateCheckbox() => new MacCheckbox();
}
IGUIFactory factory = new MacFactory();
IButton button = factory.CreateButton();
ICheckbox checkbox = factory.CreateCheckbox();
Console.WriteLine(button.Render()); // "Mac button"
Console.WriteLine(checkbox.Render()); // "Mac checkbox"
Builder se vyplatí, když objekt má hodně volitelných parametrů nebo konfiguračních kroků – třeba sestavování SQL dotazů, HTTP requestů, konfigurace UI komponent, generování dokumentů (HTML, PDF), nebo vytváření herních postav s různým vybavením. Kdykoli bys jinak měl konstruktor s 10+ parametry, je Builder čistější řešení.
public class Pizza
{
public string Dough { get; set; } = "";
public string Sauce { get; set; } = "";
public string Topping { get; set; } = "";
public override string ToString() => $"{Dough}, {Sauce}, {Topping}";
}
public interface IPizzaBuilder
{
IPizzaBuilder SetDough(string dough);
IPizzaBuilder SetSauce(string sauce);
IPizzaBuilder SetTopping(string topping);
Pizza Build();
}
public class PizzaBuilder : IPizzaBuilder
{
private Pizza _pizza = new();
public IPizzaBuilder SetDough(string dough) { _pizza.Dough = dough; return this; }
public IPizzaBuilder SetSauce(string sauce) { _pizza.Sauce = sauce; return this; }
public IPizzaBuilder SetTopping(string topping) { _pizza.Topping = topping; return this; }
public Pizza Build() { Pizza result = _pizza; _pizza = new(); return result; }
}
Pizza pizza = new PizzaBuilder()
.SetDough("thin crust")
.SetSauce("tomato")
.SetTopping("mozzarella")
.Build();
Console.WriteLine(pizza);
Clone(), která vrátí jeho kopiiPrototype se hodí, když vytváření objektu je drahé (načítání z DB, složitá inicializace) a potřebuješ více kopií s drobnými změnami – třeba šablony dokumentů, předkonfigurované herní jednotky, kopie grafických objektů v editoru, nebo prototypy záznamů v databázi, které uživatel mírně upraví a uloží jako nové.
public abstract class Shape
{
public int X { get; set; }
public int Y { get; set; }
public Shape() { }
protected Shape(Shape source)
{
X = source.X;
Y = source.Y;
}
public abstract Shape Clone();
}
public class Circle : Shape
{
public int Radius { get; set; }
public Circle() { }
private Circle(Circle source) : base(source)
{
Radius = source.Radius;
}
public override Shape Clone() => new Circle(this);
}
Circle original = new() { X = 10, Y = 20, Radius = 5 };
Circle copy = (Circle)original.Clone();
Console.WriteLine($"{copy.X}, {copy.Y}, {copy.Radius}");
Singleton se používá pro sdílené prostředky, kde více instancí nedává smysl – databázové připojení, logger, konfigurace aplikace, cache, nebo thread pool. V moderním C# se ale často nahrazuje registrací jako singleton v DI kontejneru (services.AddSingleton<T>()).
public sealed class Logger
{
private static readonly Lazy<Logger> _instance = new(() => new Logger());
public static Logger Instance => _instance.Value;
private Logger() { }
public void Log(string message) => Console.WriteLine($"[LOG] {message}");
}
Logger.Instance.Log("Aplikace spuštěna.");
Adapter se hodí vždy, když integrujete 3rd-party knihovnu nebo legacy kód s jiným rozhraním – třeba napojení starého XML API na nový JSON klient, použití různých loggerů přes jednotné rozhraní, nebo adaptace externích platebních bran na vaše interní rozhraní.
public interface ITarget
{
string GetData();
}
public class LegacyService
{
public string GetSpecificData() => "data z legacy systému";
}
public class LegacyAdapter : ITarget
{
private readonly LegacyService _service;
public LegacyAdapter(LegacyService service) => _service = service;
public string GetData() => _service.GetSpecificData();
}
ITarget target = new LegacyAdapter(new LegacyService());
Console.WriteLine(target.GetData());
Bridge se hodí, když máš dvě nezávislé dimenze variability – třeba UI ovládání + různá zařízení (Remote × TV/Radio), rendering + platformy (OpenGL/Vulkan/DirectX), nebo business logika + persistence (SQL/NoSQL/File).
public interface IRenderer
{
string Render(string shape);
}
public class VectorRenderer : IRenderer
{
public string Render(string shape) => $"Vykresluji {shape} jako vektory";
}
public class RasterRenderer : IRenderer
{
public string Render(string shape) => $"Vykresluji {shape} jako pixely";
}
public abstract class Shape
{
protected IRenderer Renderer;
protected Shape(IRenderer renderer) => Renderer = renderer;
public abstract string Draw();
}
public class CircleShape : Shape
{
public CircleShape(IRenderer renderer) : base(renderer) { }
public override string Draw() => Renderer.Render("kruh");
}
Shape circle = new CircleShape(new VectorRenderer());
Console.WriteLine(circle.Draw());
Composite se hodí na cokoliv stromového – souborový systém (soubory + složky), UI komponenty (panely obsahující tlačítka i další panely), organizační struktury, menu s podmenu, nebo výpočet ceny objednávky (produkty + balíčky produktů).
public interface IComponent
{
decimal GetPrice();
}
public class Product : IComponent
{
public string Name { get; }
public decimal Price { get; }
public Product(string name, decimal price) { Name = name; Price = price; }
public decimal GetPrice() => Price;
}
public class Box : IComponent
{
private readonly List<IComponent> _children = [];
public void Add(IComponent component) => _children.Add(component);
public decimal GetPrice() => _children.Sum(c => c.GetPrice());
}
Box box = new();
box.Add(new Product("Telefon", 15000));
box.Add(new Product("Nabíječka", 500));
Box innerBox = new();
innerBox.Add(new Product("Sluchátka", 2000));
box.Add(innerBox);
Console.WriteLine(box.GetPrice()); // 17500
Decorator se hodí, když potřebuješ flexibilně kombinovat chování – třeba streamy (buffering + komprese + šifrování), middleware pipeline (logging + auth + caching), formátování textu, nebo rozšiřování notifikací (email + SMS + Slack).
public interface IDataSource
{
string ReadData();
void WriteData(string data);
}
public class FileDataSource(string filename) : IDataSource
{
public string ReadData() => $"[data z {filename}]";
public void WriteData(string data) => Console.WriteLine($"Zápis do {filename}: {data}");
}
public abstract class DataSourceDecorator(IDataSource wrappee) : IDataSource
{
public virtual string ReadData() => wrappee.ReadData();
public virtual void WriteData(string data) => wrappee.WriteData(data);
}
public class EncryptionDecorator(IDataSource wrappee) : DataSourceDecorator(wrappee)
{
public override string ReadData() => $"Decrypt({base.ReadData()})";
public override void WriteData(string data) => base.WriteData($"Encrypt({data})");
}
public class CompressionDecorator(IDataSource wrappee) : DataSourceDecorator(wrappee)
{
public override string ReadData() => $"Decompress({base.ReadData()})";
public override void WriteData(string data) => base.WriteData($"Compress({data})");
}
IDataSource source = new CompressionDecorator(new EncryptionDecorator(new FileDataSource("data.txt")));
Console.WriteLine(source.ReadData());
Facade se hodí, když máš složitou knihovnu nebo framework a klient potřebuje jen zlomek funkcionality – třeba zjednodušení video konverze, inicializace herního enginu jedním voláním, nebo obalení složitého API (platební brána, e-mail služba) do jednoduché třídy s jednou/dvěma metodami.
public class VideoFile(string name) { public string Name => name; }
public class Codec { public string Extract(VideoFile file) => $"codec({file.Name})"; }
public class AudioMixer { public string Fix(string input) => $"mixed({input})"; }
public class VideoConverterFacade
{
public string Convert(string filename, string format)
{
VideoFile file = new(filename);
Codec codec = new();
AudioMixer mixer = new();
string buffer = codec.Extract(file);
return mixer.Fix(buffer) + $" -> {format}";
}
}
VideoConverterFacade converter = new();
Console.WriteLine(converter.Convert("video.ogg", "mp4"));
Flyweight se hodí při obrovském množství podobných objektů – třeba částice ve hře (tisíce kulek/střepin sdílejí texturu a barvu), znaky v textovém editoru (font a velikost se sdílí), stromy v herním lese, nebo ikony v UI gridu.
public class TreeType(string name, string color)
{
public string Name => name;
public string Color => color;
public string Draw(int x, int y) => $"{Name}({Color}) na [{x},{y}]";
}
public static class TreeFactory
{
private static readonly Dictionary<string, TreeType> _types = [];
public static TreeType GetTreeType(string name, string color)
{
string key = $"{name}_{color}";
if (!_types.ContainsKey(key))
_types[key] = new TreeType(name, color);
return _types[key];
}
}
public class Tree(int x, int y, TreeType type)
{
public string Draw() => type.Draw(x, y);
}
Tree t1 = new(10, 20, TreeFactory.GetTreeType("Dub", "zelená"));
Tree t2 = new(30, 40, TreeFactory.GetTreeType("Dub", "zelená"));
Console.WriteLine(ReferenceEquals(
TreeFactory.GetTreeType("Dub", "zelená"),
TreeFactory.GetTreeType("Dub", "zelená"))); // True
Proxy se hodí pro lazy loading těžkých objektů (obrázky, DB spojení), caching výsledků (opakované API volání), logování přístupů, řízení přístupu (ověření oprávnění před voláním), nebo smart reference (počítání referencí).
public interface IImage
{
string Display();
}
public class RealImage : IImage
{
private readonly string _filename;
public RealImage(string filename)
{
_filename = filename;
Console.WriteLine($"Načítám {_filename} z disku...");
}
public string Display() => $"Zobrazuji {_filename}";
}
public class ProxyImage(string filename) : IImage
{
private RealImage? _realImage;
public string Display()
{
_realImage ??= new RealImage(filename);
return _realImage.Display();
}
}
IImage image = new ProxyImage("photo.jpg");
Console.WriteLine(image.Display()); // teprve teď se načte
Console.WriteLine(image.Display()); // už se nenačítá znovu
Chain of Responsibility se hodí pro sekvence kontrol a validací – middleware pipeline ve webovém frameworku (auth → logging → rate limiting → handler), zpracování eventů v GUI (propagace kliknutí přes komponenty), validace formulářů, nebo filtrování spamu v e-mailu.
public abstract class Handler
{
private Handler? _next;
public Handler SetNext(Handler next) { _next = next; return next; }
public virtual string? Handle(string request)
{
return _next?.Handle(request);
}
}
public class AuthHandler : Handler
{
public override string? Handle(string request)
{
if (request == "neautorizovaný")
return "AuthHandler: přístup zamítnut";
return base.Handle(request);
}
}
public class LogHandler : Handler
{
public override string? Handle(string request)
{
Console.WriteLine($"LogHandler: loguji '{request}'");
return base.Handle(request);
}
}
public class FinalHandler : Handler
{
public override string? Handle(string request) => $"Zpracováno: {request}";
}
Handler chain = new AuthHandler();
chain.SetNext(new LogHandler()).SetNext(new FinalHandler());
Console.WriteLine(chain.Handle("data"));
Console.WriteLine(chain.Handle("neautorizovaný"));
Command se hodí, když potřebuješ undo/redo (textový editor, grafický editor), frontu úkolů (job queue, task scheduler), transakce (databázové operace s rollbackem), nebo když chceš stejnou akci vyvolat z více míst (tlačítko, klávesová zkratka, menu).
public interface ICommand
{
void Execute();
void Undo();
}
public class Editor
{
public string Text { get; set; } = "";
}
public class AddTextCommand(Editor editor, string text) : ICommand
{
public void Execute() => editor.Text += text;
public void Undo() => editor.Text = editor.Text[..^text.Length];
}
Editor editor = new();
Stack<ICommand> history = new();
ICommand cmd1 = new AddTextCommand(editor, "Hello ");
cmd1.Execute();
history.Push(cmd1);
ICommand cmd2 = new AddTextCommand(editor, "World");
cmd2.Execute();
history.Push(cmd2);
Console.WriteLine(editor.Text); // "Hello World"
history.Pop().Undo();
Console.WriteLine(editor.Text); // "Hello "
Iterator se v C# používá implicitně přes IEnumerable<T> / IEnumerator<T> a foreach. Explicitně se hodí pro vlastní datové struktury (stromy, grafy), stránkování výsledků, nebo lazy loading dat.
public class NumberRange(int start, int end) : IEnumerable<int>
{
public IEnumerator<int> GetEnumerator()
{
for (int i = start; i <= end; i++)
yield return i;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
}
NumberRange range = new(1, 5);
foreach (int number in range)
Console.Write($"{number} "); // 1 2 3 4 5
Mediator se hodí, když máš skupinu objektů, které na sebe vzájemně reagují – formuláře v UI (checkbox ovlivňuje viditelnost textového pole), chatovací místnosti (zprávy jdou přes server, ne přímo mezi klienty), řízení letového provozu, nebo event bus v aplikaci.
public interface IMediator
{
void Notify(object sender, string eventName);
}
public class Button(IMediator mediator)
{
public void Click() => mediator.Notify(this, "click");
}
public class TextBox
{
public bool IsVisible { get; set; } = false;
}
public class DialogMediator : IMediator
{
public Button Button { get; }
public TextBox TextBox { get; } = new();
public DialogMediator() => Button = new Button(this);
public void Notify(object sender, string eventName)
{
if (sender == Button && eventName == "click")
TextBox.IsVisible = !TextBox.IsVisible;
}
}
DialogMediator dialog = new();
dialog.Button.Click();
Console.WriteLine(dialog.TextBox.IsVisible); // True
dialog.Button.Click();
Console.WriteLine(dialog.TextBox.IsVisible); // False
Memento se hodí pro undo/redo v editorech (text, grafika), ukládání stavu hry (save/load), transakce s rollbackem, nebo snapshotování konfigurace před změnou.
public record EditorMemento(string Text, int CursorPosition);
public class TextEditor
{
public string Text { get; set; } = "";
public int CursorPosition { get; set; }
public EditorMemento Save() => new(Text, CursorPosition);
public void Restore(EditorMemento memento)
{
Text = memento.Text;
CursorPosition = memento.CursorPosition;
}
}
TextEditor editor = new() { Text = "Hello", CursorPosition = 5 };
Stack<EditorMemento> history = new();
history.Push(editor.Save());
editor.Text = "Hello World";
editor.CursorPosition = 11;
history.Push(editor.Save());
editor.Restore(history.Pop());
editor.Restore(history.Pop());
Console.WriteLine(editor.Text); // "Hello"
Observer se hodí, když změna jednoho objektu má vyvolat reakci v jiných – event systémy v UI, notifikace v aplikaci (nový e-mail, nová zpráva), data binding (model → view), systém pluginů, nebo reaktivní programování. V C# je přímo zabudovaný přes event a delegáty.
public interface ISubscriber
{
void Update(string message);
}
public class Publisher
{
private readonly List<ISubscriber> _subscribers = [];
public void Subscribe(ISubscriber subscriber) => _subscribers.Add(subscriber);
public void Unsubscribe(ISubscriber subscriber) => _subscribers.Remove(subscriber);
public void Notify(string message)
{
foreach (ISubscriber subscriber in _subscribers)
subscriber.Update(message);
}
}
public class EmailSubscriber(string email) : ISubscriber
{
public void Update(string message) => Console.WriteLine($"Email [{email}]: {message}");
}
Publisher publisher = new();
EmailSubscriber sub1 = new("a@b.cz");
EmailSubscriber sub2 = new("x@y.cz");
publisher.Subscribe(sub1);
publisher.Subscribe(sub2);
publisher.Notify("Nový článek!");
State se hodí pro stavové automaty – objednávka (nová → zaplacená → odeslaná → doručená), přehrávač médií (playing/paused/stopped), konečný automat ve hře, workflow engine, nebo TCP spojení (listening/established/closed).
public interface IState
{
string Handle(OrderContext context);
}
public class OrderContext
{
public IState State { get; set; }
public OrderContext() => State = new NewOrderState();
public string Proceed() => State.Handle(this);
}
public class NewOrderState : IState
{
public string Handle(OrderContext context)
{
context.State = new PaidState();
return "Objednávka vytvořena → zaplacena";
}
}
public class PaidState : IState
{
public string Handle(OrderContext context)
{
context.State = new ShippedState();
return "Objednávka zaplacena → odeslána";
}
}
public class ShippedState : IState
{
public string Handle(OrderContext context) => "Objednávka již odeslána";
}
OrderContext order = new();
Console.WriteLine(order.Proceed()); // vytvořena → zaplacena
Console.WriteLine(order.Proceed()); // zaplacena → odeslána
Console.WriteLine(order.Proceed()); // již odeslána
Strategy se hodí, když máš více způsobů, jak provést totéž – řazení (quicksort/mergesort/bubblesort), výpočet slevy (procentuální/pevná/žádná), komprese (zip/gzip/brotli), routování v navigaci (auto/pěšky/MHD), nebo validace (strict/lenient).
public interface IDiscountStrategy
{
decimal Calculate(decimal price);
}
public class NoDiscount : IDiscountStrategy
{
public decimal Calculate(decimal price) => price;
}
public class PercentageDiscount(int percent) : IDiscountStrategy
{
public decimal Calculate(decimal price) => price * (1 - percent / 100m);
}
public class FixedDiscount(decimal amount) : IDiscountStrategy
{
public decimal Calculate(decimal price) => Math.Max(0, price - amount);
}
public class ShoppingCart(IDiscountStrategy strategy)
{
public decimal Checkout(decimal total) => strategy.Calculate(total);
}
ShoppingCart cart = new(new PercentageDiscount(20));
Console.WriteLine(cart.Checkout(1000)); // 800
cart = new(new FixedDiscount(150));
Console.WriteLine(cart.Checkout(1000)); // 850
Template Method se hodí, když máš několik tříd s téměř identickým algoritmem, kde se liší jen pár kroků – parsování různých formátů (PDF/DOC/CSV se stejným pipeline), testovací frameworky (setup → test → teardown), generování reportů, nebo ETL procesy (extract → transform → load).
public abstract class DataParser
{
public string Parse(string source)
{
string raw = ReadData(source);
string processed = ProcessData(raw);
return FormatOutput(processed);
}
protected abstract string ReadData(string source);
protected abstract string ProcessData(string data);
protected virtual string FormatOutput(string data) => $"[{data}]";
}
public class CsvParser : DataParser
{
protected override string ReadData(string source) => $"CSV z {source}";
protected override string ProcessData(string data) => data.ToUpper();
}
public class JsonParser : DataParser
{
protected override string ReadData(string source) => $"JSON z {source}";
protected override string ProcessData(string data) => data.Trim();
}
DataParser parser = new CsvParser();
Console.WriteLine(parser.Parse("data.csv")); // [CSV Z DATA.CSV]
Accept(), visitor má metodu pro každý typ elementu (double dispatch)Visitor se hodí, když potřebuješ provádět různé operace nad heterogenní kolekcí objektů bez jejich úprav – export do různých formátů (XML, JSON, HTML), analýza AST kompilátoru, výpočet statistik nad stromovou strukturou, nebo serializace objektového grafu.
public interface IShapeVisitor
{
string Visit(CircleElement circle);
string Visit(RectangleElement rectangle);
}
public interface IShape
{
string Accept(IShapeVisitor visitor);
}
public class CircleElement(double radius) : IShape
{
public double Radius => radius;
public string Accept(IShapeVisitor visitor) => visitor.Visit(this);
}
public class RectangleElement(double width, double height) : IShape
{
public double Width => width;
public double Height => height;
public string Accept(IShapeVisitor visitor) => visitor.Visit(this);
}
public class AreaCalculator : IShapeVisitor
{
public string Visit(CircleElement c) => $"Kruh: {Math.PI * c.Radius * c.Radius:F2}";
public string Visit(RectangleElement r) => $"Obdélník: {r.Width * r.Height:F2}";
}
List<IShape> shapes = [new CircleElement(5), new RectangleElement(4, 6)];
AreaCalculator calc = new();
foreach (IShape shape in shapes)
Console.WriteLine(shape.Accept(calc));

