├── src ├── DotnetDesignPatterns │ ├── Creational │ │ ├── README.md │ │ ├── Singleton │ │ │ ├── README.md │ │ │ ├── LazySingleton.cs │ │ │ └── LockSingleton.cs │ │ ├── AbstractFactory │ │ │ ├── README.md │ │ │ ├── IOperatingSystem.cs │ │ │ ├── IOperatingSystemFactory.cs │ │ │ ├── LinuxOSFactory.cs │ │ │ ├── WindowsOSFactory.cs │ │ │ ├── LinuxOS.cs │ │ │ └── WindowsOS.cs │ │ ├── Prototype │ │ │ ├── IPrototype.cs │ │ │ ├── OperatingSystemSettings.cs │ │ │ └── README.md │ │ ├── Factory │ │ │ ├── IOperatingSystem.cs │ │ │ ├── LinuxOS.cs │ │ │ ├── WindowsOS.cs │ │ │ ├── OperatingSystemFactory.cs │ │ │ └── README.md │ │ └── Builder │ │ │ ├── IOperatingSystemConfigBuilder.cs │ │ │ ├── OperatingSystemConfig.cs │ │ │ ├── OperatingSystemConfigBuilder.cs │ │ │ └── README.md │ ├── Structural │ │ ├── README.md │ │ ├── Decorator │ │ │ ├── README.md │ │ │ ├── Notification.cs │ │ │ ├── BasicNotification.cs │ │ │ ├── NotificationDecorator.cs │ │ │ ├── LoggingDecorator.cs │ │ │ ├── EncryptionDecorator.cs │ │ │ └── PrioritizationDecorator.cs │ │ ├── Adapter │ │ │ ├── ISystemInfo.cs │ │ │ ├── LinuxOS.cs │ │ │ ├── WindowsOS.cs │ │ │ ├── LinuxAdapter.cs │ │ │ ├── WindowsAdapter.cs │ │ │ └── README.md │ │ ├── Proxy │ │ │ ├── IResource.cs │ │ │ ├── Resource.cs │ │ │ ├── ResourceProxy.cs │ │ │ └── README.md │ │ ├── Flyweight │ │ │ ├── IFileMetadata.cs │ │ │ ├── FileMetadata.cs │ │ │ ├── FileMetadataFactory.cs │ │ │ └── README.md │ │ ├── Bridge │ │ │ ├── IFileSystem.cs │ │ │ ├── FileManager.cs │ │ │ ├── TextFileManager.cs │ │ │ ├── LinuxFileSystem.cs │ │ │ ├── WindowsFileSystem.cs │ │ │ └── README.md │ │ ├── Facade │ │ │ ├── FileWriter.cs │ │ │ ├── FileReader.cs │ │ │ ├── FileValidator.cs │ │ │ ├── FileManagerFacade.cs │ │ │ └── README.md │ │ └── Composite │ │ │ ├── FileSystemComponent.cs │ │ │ ├── File.cs │ │ │ ├── Directory.cs │ │ │ └── README.md │ ├── Behavioral │ │ ├── Command │ │ │ ├── ICommand.cs │ │ │ ├── FileInvoker.cs │ │ │ ├── FileSystemReceiver.cs │ │ │ ├── CreateFileCommand.cs │ │ │ ├── DeleteFileCommand.cs │ │ │ ├── WriteFileCommand.cs │ │ │ └── README.md │ │ ├── Interpreter │ │ │ ├── IExpression.cs │ │ │ ├── File.cs │ │ │ ├── ExtensionFilter.cs │ │ │ ├── FilenameFilter.cs │ │ │ └── README.md │ │ ├── Iterator │ │ │ ├── IIterator.cs │ │ │ ├── IFileSystemCollection.cs │ │ │ ├── IFileSystemElement.cs │ │ │ ├── File.cs │ │ │ ├── Directory.cs │ │ │ └── README.md │ │ ├── Strategy │ │ │ ├── ICompressionStrategy.cs │ │ │ ├── FileCompressor.cs │ │ │ ├── ZipCompressionStrategy.cs │ │ │ ├── GZipCompressionStrategy.cs │ │ │ └── README.md │ │ ├── Observer │ │ │ ├── IFileObserver.cs │ │ │ ├── IFileSubject.cs │ │ │ ├── ConsoleLogger.cs │ │ │ ├── EmailNotifier.cs │ │ │ ├── FileWatcher.cs │ │ │ └── README.md │ │ ├── Visitor │ │ │ ├── IFileSystemVisitor.cs │ │ │ ├── IFileSystemElement.cs │ │ │ ├── FileListingVisitor.cs │ │ │ ├── File.cs │ │ │ ├── SizeCalculationVisitor.cs │ │ │ ├── Directory.cs │ │ │ └── README.md │ │ ├── State │ │ │ ├── IFileState.cs │ │ │ ├── FileContext.cs │ │ │ ├── OpenedState.cs │ │ │ ├── ClosedState.cs │ │ │ ├── CreatedState.cs │ │ │ └── README.md │ │ ├── Memento │ │ │ ├── FileMemento.cs │ │ │ ├── FileEditor.cs │ │ │ ├── FileHistory.cs │ │ │ └── README.md │ │ ├── Mediator │ │ │ ├── IFileManager.cs │ │ │ ├── Logger.cs │ │ │ ├── FileOperationHandler.cs │ │ │ ├── FileExplorer.cs │ │ │ ├── FileManager.cs │ │ │ └── README.md │ │ ├── ChainOfResponsibility │ │ │ ├── FileOperationHandler.cs │ │ │ ├── LoggingHandler.cs │ │ │ ├── ValidationHandler.cs │ │ │ ├── AuthorizationHandler.cs │ │ │ └── README.md │ │ ├── TemplateMethod │ │ │ ├── FileProcessor.cs │ │ │ ├── TextFileProcessor.cs │ │ │ ├── CsvFileProcessor.cs │ │ │ └── README.md │ │ └── README.md │ └── DotnetDesignPatterns.csproj ├── DotnetDesignPatterns.Tests │ ├── Creational │ │ ├── Factory │ │ │ └── FactoryTests.cs │ │ ├── Singleton │ │ │ ├── LazySingletonTests.cs │ │ │ └── LockSingletonTests.cs │ │ ├── Builder │ │ │ └── BuilderTests.cs │ │ └── Prototype │ │ │ └── PrototypeTests.cs │ └── DotnetDesignPatterns.Tests.csproj └── DotnetDesignPatterns.sln ├── LICENSE ├── .gitignore └── README.md /src/DotnetDesignPatterns/Creational/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/engineering87/dotnet-design-patterns/HEAD/src/DotnetDesignPatterns/Creational/README.md -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/engineering87/dotnet-design-patterns/HEAD/src/DotnetDesignPatterns/Structural/README.md -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Singleton/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/engineering87/dotnet-design-patterns/HEAD/src/DotnetDesignPatterns/Creational/Singleton/README.md -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Decorator/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/engineering87/dotnet-design-patterns/HEAD/src/DotnetDesignPatterns/Structural/Decorator/README.md -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/AbstractFactory/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/engineering87/dotnet-design-patterns/HEAD/src/DotnetDesignPatterns/Creational/AbstractFactory/README.md -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Prototype/IPrototype.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.Prototype 4 | { 5 | public interface IPrototype 6 | { 7 | T Clone(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Adapter/ISystemInfo.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Adapter 4 | { 5 | public interface ISystemInfo 6 | { 7 | string GetSystemDetails(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Proxy/IResource.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Proxy 4 | { 5 | // Subject Interface 6 | public interface IResource 7 | { 8 | void Access(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Factory/IOperatingSystem.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.Factory 4 | { 5 | public interface IOperatingSystem 6 | { 7 | void Configure(); 8 | void DisplayInfo(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Flyweight/IFileMetadata.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Flyweight 4 | { 5 | // Flyweight Interface 6 | public interface IFileMetadata 7 | { 8 | void DisplayFileInfo(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Command/ICommand.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Command 4 | { 5 | // Command Interface 6 | public interface ICommand 7 | { 8 | void Execute(); 9 | void Undo(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Interpreter/IExpression.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Interpreter 4 | { 5 | // Abstract Expression 6 | public interface IExpression 7 | { 8 | bool Interpret(File file); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Iterator/IIterator.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Iterator 4 | { 5 | // Iterator Interface 6 | public interface IIterator 7 | { 8 | bool HasNext(); 9 | T Next(); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/AbstractFactory/IOperatingSystem.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.AbstractFactory 4 | { 5 | public interface IOperatingSystem 6 | { 7 | void Configure(); 8 | void DisplayInfo(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Decorator/Notification.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Decorator 4 | { 5 | // Component 6 | public abstract class Notification 7 | { 8 | public abstract void Send(string message); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Strategy/ICompressionStrategy.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Strategy 4 | { 5 | // Strategy Interface 6 | public interface ICompressionStrategy 7 | { 8 | void Compress(string filePath); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/AbstractFactory/IOperatingSystemFactory.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.AbstractFactory 4 | { 5 | public interface IOperatingSystemFactory 6 | { 7 | IOperatingSystem CreateOperatingSystem(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Observer/IFileObserver.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Observer 4 | { 5 | // Observer Interface 6 | public interface IFileObserver 7 | { 8 | void Update(string fileName, string changeType); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Adapter/LinuxOS.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Adapter 4 | { 5 | public class LinuxOS 6 | { 7 | public string FetchLinuxInfo() 8 | { 9 | return "Ubuntu 20.04 LTS"; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Iterator/IFileSystemCollection.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Iterator 4 | { 5 | // Aggregate Interface 6 | public interface IFileSystemCollection 7 | { 8 | IIterator CreateIterator(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Iterator/IFileSystemElement.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Iterator 4 | { 5 | // Element Interface 6 | public interface IFileSystemElement 7 | { 8 | string Name { get; } 9 | void PrintDetails(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Bridge/IFileSystem.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Bridge 4 | { 5 | public interface IFileSystem 6 | { 7 | void WriteToFile(string fileName, string content); 8 | string ReadFromFile(string fileName); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Visitor/IFileSystemVisitor.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Visitor 4 | { 5 | // Visitor Interface 6 | public interface IFileSystemVisitor 7 | { 8 | void Visit(File file); 9 | void Visit(Directory directory); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Adapter/WindowsOS.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Adapter 4 | { 5 | public class WindowsOS 6 | { 7 | public string RetrieveWindowsInfo() 8 | { 9 | return "Windows 10, Version 21H1"; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Visitor/IFileSystemElement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | // (c) 2024 Francesco Del Re 4 | // This code is licensed under MIT license (see LICENSE.txt for details) 5 | namespace DotnetDesignPatterns.Behavioral.Visitor 6 | { 7 | // Element Interface 8 | public interface IFileSystemElement 9 | { 10 | void Accept(IFileSystemVisitor visitor); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/State/IFileState.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.State 4 | { 5 | // State Interface 6 | public interface IFileState 7 | { 8 | void Open(FileContext context); 9 | void Close(FileContext context); 10 | void Edit(FileContext context); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Decorator/BasicNotification.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Decorator 4 | { 5 | public class BasicNotification : Notification 6 | { 7 | public override void Send(string message) 8 | { 9 | Console.WriteLine($"Sending notification: {message}"); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Proxy/Resource.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Proxy 4 | { 5 | // Real Subject 6 | public class Resource : IResource 7 | { 8 | public void Access() 9 | { 10 | // Simulate accessing a resource 11 | Console.WriteLine("Accessing the real resource."); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Memento/FileMemento.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Memento 4 | { 5 | // Memento: Stores the state of the File 6 | public class FileMemento 7 | { 8 | public string Content { get; } 9 | 10 | public FileMemento(string content) 11 | { 12 | Content = content; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/AbstractFactory/LinuxOSFactory.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.AbstractFactory 4 | { 5 | // Concrete Factory per Linux OS 6 | public class LinuxOSFactory : IOperatingSystemFactory 7 | { 8 | public IOperatingSystem CreateOperatingSystem() 9 | { 10 | return new LinuxOS(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Observer/IFileSubject.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Observer 4 | { 5 | // Subject Interface 6 | public interface IFileSubject 7 | { 8 | void RegisterObserver(IFileObserver observer); 9 | void UnregisterObserver(IFileObserver observer); 10 | void NotifyObservers(string fileName, string changeType); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/AbstractFactory/WindowsOSFactory.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.AbstractFactory 4 | { 5 | // Concrete Factory per Windows OS 6 | public class WindowsOSFactory : IOperatingSystemFactory 7 | { 8 | public IOperatingSystem CreateOperatingSystem() 9 | { 10 | return new WindowsOS(); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Mediator/IFileManager.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Mediator 4 | { 5 | // Mediator Interface 6 | public interface IFileManager 7 | { 8 | void CreateFile(string filename); 9 | void OpenFile(string filename); 10 | void DeleteFile(string filename); 11 | void Notify(object sender, string eventCode); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Facade/FileWriter.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Facade 4 | { 5 | // Subsystem 2: File Writer 6 | public class FileWriter 7 | { 8 | public void WriteFile(string filePath, string content) 9 | { 10 | // Simulate writing to a file 11 | Console.WriteLine($"Writing to file at {filePath}"); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Interpreter/File.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Interpreter 4 | { 5 | // Context 6 | public class File 7 | { 8 | public string Name { get; } 9 | public string Extension { get; } 10 | 11 | public File(string name, string extension) 12 | { 13 | Name = name; 14 | Extension = extension; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Observer/ConsoleLogger.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Observer 4 | { 5 | // Concrete Observer 1: Console Logger 6 | public class ConsoleLogger : IFileObserver 7 | { 8 | public void Update(string fileName, string changeType) 9 | { 10 | Console.WriteLine($"[Console Logger] File {fileName} has been {changeType}."); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Facade/FileReader.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Facade 4 | { 5 | // Subsystem 1: File Reader 6 | public class FileReader 7 | { 8 | public string ReadFile(string filePath) 9 | { 10 | // Simulate reading a file 11 | Console.WriteLine($"Reading file from {filePath}"); 12 | return "File content"; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Facade/FileValidator.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Facade 4 | { 5 | // Subsystem 3: File Validator 6 | public class FileValidator 7 | { 8 | public bool Validate(string filePath) 9 | { 10 | // Simulate file validation 11 | Console.WriteLine($"Validating file at {filePath}"); 12 | return true; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Decorator/NotificationDecorator.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Decorator 4 | { 5 | // Decorator 6 | public abstract class NotificationDecorator : Notification 7 | { 8 | protected Notification _notification; 9 | 10 | protected NotificationDecorator(Notification notification) 11 | { 12 | _notification = notification; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Observer/EmailNotifier.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Observer 4 | { 5 | // Concrete Observer 2: Email Notifier 6 | public class EmailNotifier : IFileObserver 7 | { 8 | public void Update(string fileName, string changeType) 9 | { 10 | Console.WriteLine($"[Email Notifier] Sending email: File {fileName} has been {changeType}."); 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Iterator/File.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Iterator 4 | { 5 | // Concrete Element: File 6 | public class File : IFileSystemElement 7 | { 8 | public string Name { get; } 9 | 10 | public File(string name) 11 | { 12 | Name = name; 13 | } 14 | 15 | public void PrintDetails() 16 | { 17 | Console.WriteLine($"File: {Name}"); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Composite/FileSystemComponent.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Composite 4 | { 5 | public abstract class FileSystemComponent 6 | { 7 | public string Name { get; protected set; } 8 | 9 | protected FileSystemComponent(string name) 10 | { 11 | Name = name; 12 | } 13 | 14 | public abstract void Display(int depth); 15 | public abstract long CalculateSize(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Factory/LinuxOS.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | 4 | namespace DotnetDesignPatterns.Creational.Factory 5 | { 6 | public class LinuxOS : IOperatingSystem 7 | { 8 | public void Configure() 9 | { 10 | Console.WriteLine("Configuring Linux OS with ext4 file system and firewall enabled."); 11 | } 12 | 13 | public void DisplayInfo() 14 | { 15 | Console.WriteLine("Operating System: Linux"); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/AbstractFactory/LinuxOS.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.AbstractFactory 4 | { 5 | public class LinuxOS : IOperatingSystem 6 | { 7 | public void Configure() 8 | { 9 | Console.WriteLine("Configuring Linux OS with ext4 file system and iptables enabled."); 10 | } 11 | 12 | public void DisplayInfo() 13 | { 14 | Console.WriteLine("Operating System: Linux"); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Factory/WindowsOS.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | 4 | namespace DotnetDesignPatterns.Creational.Factory 5 | { 6 | public class WindowsOS : IOperatingSystem 7 | { 8 | public void Configure() 9 | { 10 | Console.WriteLine("Configuring Windows OS with NTFS file system and firewall enabled."); 11 | } 12 | 13 | public void DisplayInfo() 14 | { 15 | Console.WriteLine("Operating System: Windows"); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Mediator/Logger.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Mediator 4 | { 5 | // Colleague: Logger 6 | public class Logger 7 | { 8 | private IFileManager _mediator; 9 | 10 | public void SetMediator(IFileManager mediator) 11 | { 12 | _mediator = mediator; 13 | } 14 | 15 | public void Log(string message) 16 | { 17 | Console.WriteLine($"[LOG]: {message}"); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Bridge/FileManager.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Bridge 4 | { 5 | public abstract class FileManager 6 | { 7 | protected IFileSystem _fileSystem; 8 | 9 | protected FileManager(IFileSystem fileSystem) 10 | { 11 | _fileSystem = fileSystem; 12 | } 13 | 14 | public abstract void SaveFile(string fileName, string content); 15 | public abstract string ReadFile(string fileName); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/AbstractFactory/WindowsOS.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.AbstractFactory 4 | { 5 | public class WindowsOS : IOperatingSystem 6 | { 7 | public void Configure() 8 | { 9 | Console.WriteLine("Configuring Windows OS with NTFS file system and firewall enabled."); 10 | } 11 | 12 | public void DisplayInfo() 13 | { 14 | Console.WriteLine("Operating System: Windows"); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/ChainOfResponsibility/FileOperationHandler.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.ChainOfResponsibility 4 | { 5 | // Abstract Handler 6 | public abstract class FileOperationHandler 7 | { 8 | protected FileOperationHandler _nextHandler; 9 | 10 | public void SetNext(FileOperationHandler nextHandler) 11 | { 12 | _nextHandler = nextHandler; 13 | } 14 | 15 | public abstract void HandleRequest(string operationType, string fileName); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Visitor/FileListingVisitor.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Visitor 4 | { 5 | // Concrete Visitor: File Listing 6 | public class FileListingVisitor : IFileSystemVisitor 7 | { 8 | public void Visit(File file) 9 | { 10 | Console.WriteLine($"File: {file.Name} - Size: {file.Size} bytes"); 11 | } 12 | 13 | public void Visit(Directory directory) 14 | { 15 | Console.WriteLine($"Directory: {directory.Name}"); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Visitor/File.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Visitor 4 | { 5 | // Concrete Element: File 6 | public class File : IFileSystemElement 7 | { 8 | public string Name { get; } 9 | public long Size { get; } 10 | 11 | public File(string name, long size) 12 | { 13 | Name = name; 14 | Size = size; 15 | } 16 | 17 | public void Accept(IFileSystemVisitor visitor) 18 | { 19 | visitor.Visit(this); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Adapter/LinuxAdapter.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Adapter 4 | { 5 | public class LinuxAdapter : ISystemInfo 6 | { 7 | private readonly LinuxOS _linuxOS; 8 | 9 | public LinuxAdapter(LinuxOS linuxOS) 10 | { 11 | _linuxOS = linuxOS; 12 | } 13 | 14 | public string GetSystemDetails() 15 | { 16 | // Adapt the LinuxOS interface to the ISystemInfo interface 17 | return _linuxOS.FetchLinuxInfo(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Factory/OperatingSystemFactory.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | 4 | namespace DotnetDesignPatterns.Creational.Factory 5 | { 6 | public static class OperatingSystemFactory 7 | { 8 | public static IOperatingSystem CreateOperatingSystem(string osType) 9 | { 10 | return osType.ToLower() switch 11 | { 12 | "linux" => new LinuxOS(), 13 | "windows" => new WindowsOS(), 14 | _ => throw new ArgumentException("Invalid OS Type"), 15 | }; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Command/FileInvoker.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Command 4 | { 5 | // Invoker Class 6 | public class FileInvoker 7 | { 8 | private readonly ICommand _command; 9 | 10 | public FileInvoker(ICommand command) 11 | { 12 | _command = command; 13 | } 14 | 15 | public void Execute() 16 | { 17 | _command.Execute(); 18 | } 19 | 20 | public void Undo() 21 | { 22 | _command.Undo(); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Visitor/SizeCalculationVisitor.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Visitor 4 | { 5 | // Concrete Visitor: Size Calculation 6 | public class SizeCalculationVisitor : IFileSystemVisitor 7 | { 8 | public long TotalSize { get; private set; } 9 | 10 | public void Visit(File file) 11 | { 12 | TotalSize += file.Size; 13 | } 14 | 15 | public void Visit(Directory directory) 16 | { 17 | // Optionally, do something with the directory 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Adapter/WindowsAdapter.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Adapter 4 | { 5 | public class WindowsAdapter : ISystemInfo 6 | { 7 | private readonly WindowsOS _windowsOS; 8 | 9 | public WindowsAdapter(WindowsOS windowsOS) 10 | { 11 | _windowsOS = windowsOS; 12 | } 13 | 14 | public string GetSystemDetails() 15 | { 16 | // Adapt the WindowsOS interface to the ISystemInfo interface 17 | return _windowsOS.RetrieveWindowsInfo(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Interpreter/ExtensionFilter.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Interpreter 4 | { 5 | // Terminal Expression: ExtensionFilter 6 | public class ExtensionFilter : IExpression 7 | { 8 | private readonly string _extension; 9 | 10 | public ExtensionFilter(string extension) 11 | { 12 | _extension = extension; 13 | } 14 | 15 | public bool Interpret(File file) 16 | { 17 | return file.Extension.Equals(_extension, StringComparison.OrdinalIgnoreCase); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Builder/IOperatingSystemConfigBuilder.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.Builder 4 | { 5 | public interface IOperatingSystemConfigBuilder 6 | { 7 | IOperatingSystemConfigBuilder SetOSName(string osName); 8 | IOperatingSystemConfigBuilder SetVersion(string version); 9 | IOperatingSystemConfigBuilder SetFileSystem(string fileSystem); 10 | IOperatingSystemConfigBuilder EnableFirewall(bool enable); 11 | IOperatingSystemConfigBuilder SetNetworkSettings(string networkSettings); 12 | OperatingSystemConfig Build(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Bridge/TextFileManager.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Bridge 4 | { 5 | public class TextFileManager : FileManager 6 | { 7 | public TextFileManager(IFileSystem fileSystem) : base(fileSystem) 8 | { 9 | } 10 | 11 | public override void SaveFile(string fileName, string content) 12 | { 13 | _fileSystem.WriteToFile(fileName, content); 14 | } 15 | 16 | public override string ReadFile(string fileName) 17 | { 18 | return _fileSystem.ReadFromFile(fileName); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Flyweight/FileMetadata.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Flyweight 4 | { 5 | // Concrete Flyweight 6 | public class FileMetadata : IFileMetadata 7 | { 8 | private string _fileType; 9 | private string _owner; 10 | 11 | public FileMetadata(string fileType, string owner) 12 | { 13 | _fileType = fileType; 14 | _owner = owner; 15 | } 16 | 17 | public void DisplayFileInfo() 18 | { 19 | Console.WriteLine($"File Type: {_fileType}, Owner: {_owner}"); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/ChainOfResponsibility/LoggingHandler.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.ChainOfResponsibility 4 | { 5 | // Concrete Handler: Logging 6 | public class LoggingHandler : FileOperationHandler 7 | { 8 | public override void HandleRequest(string operationType, string fileName) 9 | { 10 | Console.WriteLine($"[LOG] Operation '{operationType}' on file '{fileName}'"); 11 | 12 | if (_nextHandler != null) 13 | { 14 | _nextHandler.HandleRequest(operationType, fileName); 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Interpreter/FilenameFilter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | // (c) 2024 Francesco Del Re 4 | // This code is licensed under MIT license (see LICENSE.txt for details) 5 | namespace DotnetDesignPatterns.Behavioral.Interpreter 6 | { 7 | // Terminal Expression: FilenameFilter 8 | public class FilenameFilter : IExpression 9 | { 10 | private readonly string _filename; 11 | 12 | public FilenameFilter(string filename) 13 | { 14 | _filename = filename; 15 | } 16 | 17 | public bool Interpret(File file) 18 | { 19 | return file.Name.Contains(_filename, StringComparison.OrdinalIgnoreCase); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/ChainOfResponsibility/ValidationHandler.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.ChainOfResponsibility 4 | { 5 | // Concrete Handler: Validation 6 | public class ValidationHandler : FileOperationHandler 7 | { 8 | public override void HandleRequest(string operationType, string fileName) 9 | { 10 | Console.WriteLine($"[VALIDATION] Validating operation '{operationType}' on file '{fileName}'"); 11 | 12 | if (_nextHandler != null) 13 | { 14 | _nextHandler.HandleRequest(operationType, fileName); 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/State/FileContext.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.State 4 | { 5 | // Context 6 | public class FileContext 7 | { 8 | public IFileState State { get; set; } 9 | 10 | public FileContext() 11 | { 12 | State = new CreatedState(); 13 | } 14 | 15 | public void Open() 16 | { 17 | State.Open(this); 18 | } 19 | 20 | public void Close() 21 | { 22 | State.Close(this); 23 | } 24 | 25 | public void Edit() 26 | { 27 | State.Edit(this); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Composite/File.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Composite 4 | { 5 | // Leaf 6 | public class File : FileSystemComponent 7 | { 8 | private long _size; // Size of the file in bytes 9 | 10 | public File(string name, long size) : base(name) 11 | { 12 | _size = size; 13 | } 14 | 15 | public override void Display(int depth) 16 | { 17 | Console.WriteLine(new string('-', depth) + Name); 18 | } 19 | 20 | public override long CalculateSize() 21 | { 22 | return _size; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Decorator/LoggingDecorator.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Decorator 4 | { 5 | // Concrete Decorator for Logging 6 | public class LoggingDecorator : NotificationDecorator 7 | { 8 | public LoggingDecorator(Notification notification) : base(notification) 9 | { 10 | } 11 | 12 | public override void Send(string message) 13 | { 14 | Log(message); 15 | _notification.Send(message); 16 | } 17 | 18 | private void Log(string message) 19 | { 20 | Console.WriteLine($"Logging notification: {message}"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Bridge/LinuxFileSystem.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Bridge 4 | { 5 | public class LinuxFileSystem : IFileSystem 6 | { 7 | public void WriteToFile(string fileName, string content) 8 | { 9 | Console.WriteLine($"Writing to Linux file: {fileName}"); 10 | // Linux-specific file writing logic 11 | } 12 | 13 | public string ReadFromFile(string fileName) 14 | { 15 | Console.WriteLine($"Reading from Linux file: {fileName}"); 16 | // Linux-specific file reading logic 17 | return "File content from Linux"; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/State/OpenedState.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.State 4 | { 5 | // Concrete State: Opened 6 | public class OpenedState : IFileState 7 | { 8 | public void Open(FileContext context) 9 | { 10 | Console.WriteLine("File is already opened."); 11 | } 12 | 13 | public void Close(FileContext context) 14 | { 15 | Console.WriteLine("File closed."); 16 | context.State = new ClosedState(); 17 | } 18 | 19 | public void Edit(FileContext context) 20 | { 21 | Console.WriteLine("File is being edited."); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/DotnetDesignPatterns.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | https://github.com/engineering87/dotnet-design-patterns 8 | https://github.com/engineering87/dotnet-design-patterns 9 | README.md 10 | GoF Design Patterns implemented in .NET C# 11 | Francesco Del Re 12 | 13 | 14 | 15 | 16 | True 17 | \ 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Bridge/WindowsFileSystem.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Bridge 4 | { 5 | public class WindowsFileSystem : IFileSystem 6 | { 7 | public void WriteToFile(string fileName, string content) 8 | { 9 | Console.WriteLine($"Writing to Windows file: {fileName}"); 10 | // Windows-specific file writing logic 11 | } 12 | 13 | public string ReadFromFile(string fileName) 14 | { 15 | Console.WriteLine($"Reading from Windows file: {fileName}"); 16 | // Windows-specific file reading logic 17 | return "File content from Windows"; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/State/ClosedState.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.State 4 | { 5 | // Concrete State: Closed 6 | public class ClosedState : IFileState 7 | { 8 | public void Open(FileContext context) 9 | { 10 | Console.WriteLine("File opened."); 11 | context.State = new OpenedState(); 12 | } 13 | 14 | public void Close(FileContext context) 15 | { 16 | Console.WriteLine("File is already closed."); 17 | } 18 | 19 | public void Edit(FileContext context) 20 | { 21 | Console.WriteLine("Cannot edit the file. It is closed."); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Decorator/EncryptionDecorator.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Decorator 4 | { 5 | // Concrete Decorator for Encryption 6 | public class EncryptionDecorator : NotificationDecorator 7 | { 8 | public EncryptionDecorator(Notification notification) : base(notification) 9 | { 10 | } 11 | 12 | public override void Send(string message) 13 | { 14 | string encryptedMessage = Encrypt(message); 15 | _notification.Send(encryptedMessage); 16 | } 17 | 18 | private string Encrypt(string message) 19 | { 20 | return $"[Encrypted]{message}"; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/State/CreatedState.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.State 4 | { 5 | // Concrete State: Created 6 | public class CreatedState : IFileState 7 | { 8 | public void Open(FileContext context) 9 | { 10 | Console.WriteLine("File opened."); 11 | context.State = new OpenedState(); 12 | } 13 | 14 | public void Close(FileContext context) 15 | { 16 | Console.WriteLine("Cannot close the file. It is not opened."); 17 | } 18 | 19 | public void Edit(FileContext context) 20 | { 21 | Console.WriteLine("Cannot edit the file. It is not opened."); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Decorator/PrioritizationDecorator.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Decorator 4 | { 5 | // Concrete Decorator for Prioritization 6 | public class PrioritizationDecorator : NotificationDecorator 7 | { 8 | public PrioritizationDecorator(Notification notification) : base(notification) 9 | { 10 | } 11 | 12 | public override void Send(string message) 13 | { 14 | string prioritizedMessage = Prioritize(message); 15 | _notification.Send(prioritizedMessage); 16 | } 17 | 18 | private string Prioritize(string message) 19 | { 20 | return $"[Priority]{message}"; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Command/FileSystemReceiver.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Command 4 | { 5 | // Receiver Class: Represents the file system 6 | public class FileSystemReceiver 7 | { 8 | public void CreateFile(string filename) 9 | { 10 | Console.WriteLine($"Creating file: {filename}"); 11 | } 12 | 13 | public void WriteFile(string filename, string content) 14 | { 15 | Console.WriteLine($"Writing to file: {filename}"); 16 | Console.WriteLine($"Content: {content}"); 17 | } 18 | 19 | public void DeleteFile(string filename) 20 | { 21 | Console.WriteLine($"Deleting file: {filename}"); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Command/CreateFileCommand.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Command 4 | { 5 | // Concrete Command Classes 6 | public class CreateFileCommand : ICommand 7 | { 8 | private readonly FileSystemReceiver _fileSystem; 9 | private readonly string _filename; 10 | 11 | public CreateFileCommand(FileSystemReceiver fileSystem, string filename) 12 | { 13 | _fileSystem = fileSystem; 14 | _filename = filename; 15 | } 16 | 17 | public void Execute() 18 | { 19 | _fileSystem.CreateFile(_filename); 20 | } 21 | 22 | public void Undo() 23 | { 24 | _fileSystem.DeleteFile(_filename); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Strategy/FileCompressor.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Strategy 4 | { 5 | // Context: File Compressor 6 | public class FileCompressor 7 | { 8 | private ICompressionStrategy _compressionStrategy; 9 | 10 | public void SetCompressionStrategy(ICompressionStrategy compressionStrategy) 11 | { 12 | _compressionStrategy = compressionStrategy; 13 | } 14 | 15 | public void CompressFile(string filePath) 16 | { 17 | if (_compressionStrategy == null) 18 | { 19 | throw new InvalidOperationException("Compression strategy is not set."); 20 | } 21 | _compressionStrategy.Compress(filePath); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Memento/FileEditor.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Memento 4 | { 5 | // Originator: The File being edited 6 | public class FileEditor 7 | { 8 | public string Content { get; private set; } 9 | 10 | public void Write(string content) 11 | { 12 | Content = content; 13 | Console.WriteLine($"File content updated to: {Content}"); 14 | } 15 | 16 | public FileMemento Save() 17 | { 18 | Console.WriteLine("Saving current file state."); 19 | return new FileMemento(Content); 20 | } 21 | 22 | public void Restore(FileMemento memento) 23 | { 24 | Content = memento.Content; 25 | Console.WriteLine($"Restored file content to: {Content}"); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Command/DeleteFileCommand.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Command 4 | { 5 | public class DeleteFileCommand : ICommand 6 | { 7 | private readonly FileSystemReceiver _fileSystem; 8 | private readonly string _filename; 9 | 10 | public DeleteFileCommand(FileSystemReceiver fileSystem, string filename) 11 | { 12 | _fileSystem = fileSystem; 13 | _filename = filename; 14 | } 15 | 16 | public void Execute() 17 | { 18 | _fileSystem.DeleteFile(_filename); 19 | } 20 | 21 | public void Undo() 22 | { 23 | Console.WriteLine($"Undoing delete: Recreating file {_filename}"); 24 | _fileSystem.CreateFile(_filename); // Re-create the file (simple undo example) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Mediator/FileOperationHandler.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Mediator 4 | { 5 | // Colleague: File Operation Handler 6 | public class FileOperationHandler 7 | { 8 | private IFileManager _mediator; 9 | 10 | public void SetMediator(IFileManager mediator) 11 | { 12 | _mediator = mediator; 13 | } 14 | 15 | public void CreateFile(string filename) 16 | { 17 | Console.WriteLine($"Creating file: {filename}"); 18 | } 19 | 20 | public void OpenFile(string filename) 21 | { 22 | Console.WriteLine($"Opening file: {filename}"); 23 | } 24 | 25 | public void DeleteFile(string filename) 26 | { 27 | Console.WriteLine($"Deleting file: {filename}"); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Strategy/ZipCompressionStrategy.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | using System.IO.Compression; 4 | 5 | namespace DotnetDesignPatterns.Behavioral.Strategy 6 | { 7 | // Concrete Strategy 1: ZIP Compression 8 | public class ZipCompressionStrategy : ICompressionStrategy 9 | { 10 | public void Compress(string filePath) 11 | { 12 | var outputFilePath = filePath + ".zip"; 13 | using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) 14 | using (var zipArchive = new FileStream(outputFilePath, FileMode.Create)) 15 | using (var zipStream = new GZipStream(zipArchive, CompressionMode.Compress)) 16 | { 17 | fileStream.CopyTo(zipStream); 18 | } 19 | Console.WriteLine($"File compressed to ZIP: {outputFilePath}"); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Visitor/Directory.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Visitor 4 | { 5 | // Concrete Element: Directory 6 | public class Directory : IFileSystemElement 7 | { 8 | public string Name { get; } 9 | public List Elements { get; } 10 | 11 | public Directory(string name) 12 | { 13 | Name = name; 14 | Elements = new List(); 15 | } 16 | 17 | public void AddElement(IFileSystemElement element) 18 | { 19 | Elements.Add(element); 20 | } 21 | 22 | public void Accept(IFileSystemVisitor visitor) 23 | { 24 | visitor.Visit(this); 25 | foreach (var element in Elements) 26 | { 27 | element.Accept(visitor); 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Strategy/GZipCompressionStrategy.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | using System.IO.Compression; 4 | 5 | namespace DotnetDesignPatterns.Behavioral.Strategy 6 | { 7 | // Concrete Strategy 2: GZip Compression 8 | public class GZipCompressionStrategy : ICompressionStrategy 9 | { 10 | public void Compress(string filePath) 11 | { 12 | var outputFilePath = filePath + ".gz"; 13 | using (var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) 14 | using (var gzipStream = new FileStream(outputFilePath, FileMode.Create)) 15 | using (var compressionStream = new GZipStream(gzipStream, CompressionMode.Compress)) 16 | { 17 | fileStream.CopyTo(compressionStream); 18 | } 19 | Console.WriteLine($"File compressed to GZIP: {outputFilePath}"); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Builder/OperatingSystemConfig.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.Builder 4 | { 5 | public class OperatingSystemConfig 6 | { 7 | public string OSName { get; set; } 8 | public string Version { get; set; } 9 | public string FileSystem { get; set; } 10 | public bool IsFirewallEnabled { get; set; } 11 | public string NetworkSettings { get; set; } 12 | 13 | public void DisplayConfig() 14 | { 15 | Console.WriteLine($"Operating System: {OSName}"); 16 | Console.WriteLine($"Version: {Version}"); 17 | Console.WriteLine($"File System: {FileSystem}"); 18 | Console.WriteLine($"Firewall Enabled: {IsFirewallEnabled}"); 19 | Console.WriteLine($"Network Settings: {NetworkSettings}"); 20 | Console.WriteLine(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Flyweight/FileMetadataFactory.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Flyweight 4 | { 5 | // Flyweight Factory 6 | public class FileMetadataFactory 7 | { 8 | private Dictionary _metadataCache = new Dictionary(); 9 | 10 | public IFileMetadata GetFileMetadata(string fileType, string owner) 11 | { 12 | string key = $"{fileType}:{owner}"; 13 | 14 | if (!_metadataCache.ContainsKey(key)) 15 | { 16 | Console.WriteLine("Creating new file metadata."); 17 | _metadataCache[key] = new FileMetadata(fileType, owner); 18 | } 19 | else 20 | { 21 | Console.WriteLine("Reusing existing file metadata."); 22 | } 23 | 24 | return _metadataCache[key]; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Command/WriteFileCommand.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Command 4 | { 5 | public class WriteFileCommand : ICommand 6 | { 7 | private readonly FileSystemReceiver _fileSystem; 8 | private readonly string _filename; 9 | private readonly string _content; 10 | 11 | public WriteFileCommand(FileSystemReceiver fileSystem, string filename, string content) 12 | { 13 | _fileSystem = fileSystem; 14 | _filename = filename; 15 | _content = content; 16 | } 17 | 18 | public void Execute() 19 | { 20 | _fileSystem.WriteFile(_filename, _content); 21 | } 22 | 23 | public void Undo() 24 | { 25 | Console.WriteLine($"Undoing write to file: {_filename}"); 26 | _fileSystem.WriteFile(_filename, ""); // Clear the content (simple undo example) 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Singleton/LazySingleton.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.Singleton 4 | { 5 | public sealed class LazySingleton 6 | { 7 | // Lazy is thread-safe by definition and ensures that the instance is created only once. 8 | private static readonly Lazy _instance = new(() => new LazySingleton()); 9 | 10 | // Private constructor to prevent instantiation from outside 11 | private LazySingleton() 12 | { 13 | // Initialize the singleton instance 14 | } 15 | 16 | // Public static method to get the singleton instance 17 | public static LazySingleton Instance 18 | { 19 | get 20 | { 21 | return _instance.Value; 22 | } 23 | } 24 | 25 | // Example method 26 | public void DoSomething() 27 | { 28 | // Do something 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/ChainOfResponsibility/AuthorizationHandler.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.ChainOfResponsibility 4 | { 5 | // Concrete Handler: Authorization 6 | public class AuthorizationHandler : FileOperationHandler 7 | { 8 | public override void HandleRequest(string operationType, string fileName) 9 | { 10 | Console.WriteLine($"[AUTHORIZATION] Checking permissions for '{operationType}' on file '{fileName}'"); 11 | 12 | if (operationType != "delete") // Simulate authorization check 13 | { 14 | if (_nextHandler != null) 15 | { 16 | _nextHandler.HandleRequest(operationType, fileName); 17 | } 18 | } 19 | else 20 | { 21 | Console.WriteLine($"[AUTHORIZATION] Permission denied for '{operationType}' operation on file '{fileName}'"); 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Francesco Del Re 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/TemplateMethod/FileProcessor.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.TemplateMethod 4 | { 5 | // Abstract class defining the Template Method 6 | abstract class FileProcessor 7 | { 8 | // Template Method 9 | public void ProcessFile(string filePath) 10 | { 11 | OpenFile(filePath); 12 | var content = ReadFileContent(); 13 | ProcessContent(content); 14 | CloseFile(); 15 | } 16 | 17 | // Steps of the algorithm, some of which must be overridden by subclasses 18 | protected virtual void OpenFile(string filePath) 19 | { 20 | Console.WriteLine($"Opening file: {filePath}"); 21 | } 22 | 23 | protected abstract string ReadFileContent(); 24 | 25 | protected abstract void ProcessContent(string content); 26 | 27 | protected virtual void CloseFile() 28 | { 29 | Console.WriteLine("Closing file."); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Prototype/OperatingSystemSettings.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.Prototype 4 | { 5 | public class OperatingSystemSettings : IPrototype 6 | { 7 | public string OSName { get; set; } 8 | public string Version { get; set; } 9 | 10 | public OperatingSystemSettings(string osName, string version) 11 | { 12 | OSName = osName; 13 | Version = version; 14 | } 15 | 16 | // Implementazione del metodo Clone 17 | public OperatingSystemSettings Clone() 18 | { 19 | // Clonazione profonda per evitare riferimenti condivisi tra l'originale e il clone 20 | return new OperatingSystemSettings(OSName, Version); 21 | } 22 | 23 | // Metodo per visualizzare i dettagli delle impostazioni del sistema operativo 24 | public void DisplaySettings() 25 | { 26 | Console.WriteLine($"OS Name: {OSName}"); 27 | Console.WriteLine($"Version: {Version}"); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns.Tests/Creational/Factory/FactoryTests.cs: -------------------------------------------------------------------------------- 1 | using DotnetDesignPatterns.Creational.Factory; 2 | 3 | namespace DotnetDesignPatterns.Tests.Creational.Factory 4 | { 5 | public class FactoryTests 6 | { 7 | [Fact] 8 | public void CreateOperatingSystem_ShouldReturnLinuxOS_WhenLinuxIsRequested() 9 | { 10 | // Act 11 | var os = OperatingSystemFactory.CreateOperatingSystem("linux"); 12 | 13 | // Assert 14 | Assert.NotNull(os); 15 | Assert.IsType(os); 16 | } 17 | 18 | [Fact] 19 | public void CreateOperatingSystem_ShouldReturnWindowsOS_WhenWindowsIsRequested() 20 | { 21 | // Act 22 | var os = OperatingSystemFactory.CreateOperatingSystem("windows"); 23 | 24 | // Assert 25 | Assert.NotNull(os); 26 | Assert.IsType(os); 27 | } 28 | 29 | [Fact] 30 | public void CreateOperatingSystem_ShouldThrowArgumentException_WhenInvalidOSTypeIsRequested() 31 | { 32 | // Act & Assert 33 | Assert.Throws(() => OperatingSystemFactory.CreateOperatingSystem("macos")); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Proxy/ResourceProxy.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Proxy 4 | { 5 | // Proxy 6 | public class ResourceProxy : IResource 7 | { 8 | private Resource _realResource; 9 | private readonly string _userRole; 10 | 11 | public ResourceProxy(string userRole) 12 | { 13 | _userRole = userRole; 14 | } 15 | 16 | public void Access() 17 | { 18 | if (HasAccess()) 19 | { 20 | if (_realResource == null) 21 | { 22 | _realResource = new Resource(); // Lazy initialization 23 | } 24 | Console.WriteLine("Proxy forwarding the request to the real resource."); 25 | _realResource.Access(); 26 | } 27 | else 28 | { 29 | Console.WriteLine("Access denied."); 30 | } 31 | } 32 | 33 | private bool HasAccess() 34 | { 35 | // Simple access control based on user role 36 | return _userRole == "Admin"; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Facade/FileManagerFacade.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | 4 | namespace DotnetDesignPatterns.Structural.Facade 5 | { 6 | // Facade 7 | public class FileManagerFacade 8 | { 9 | private FileReader _fileReader; 10 | private FileWriter _fileWriter; 11 | private FileValidator _fileValidator; 12 | 13 | public FileManagerFacade() 14 | { 15 | _fileReader = new FileReader(); 16 | _fileWriter = new FileWriter(); 17 | _fileValidator = new FileValidator(); 18 | } 19 | 20 | public void ProcessFile(string filePath, string newContent) 21 | { 22 | if (_fileValidator.Validate(filePath)) 23 | { 24 | string content = _fileReader.ReadFile(filePath); 25 | Console.WriteLine($"Current content: {content}"); 26 | _fileWriter.WriteFile(filePath, newContent); 27 | Console.WriteLine("File processed successfully."); 28 | } 29 | else 30 | { 31 | Console.WriteLine("File validation failed."); 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns.Tests/DotnetDesignPatterns.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0 5 | enable 6 | enable 7 | false 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers; buildtransitive 14 | 15 | 16 | 17 | 18 | all 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/TemplateMethod/TextFileProcessor.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.TemplateMethod 4 | { 5 | // Concrete class for processing text files 6 | class TextFileProcessor : FileProcessor 7 | { 8 | private StreamReader _reader; 9 | 10 | protected override void OpenFile(string filePath) 11 | { 12 | base.OpenFile(filePath); 13 | _reader = new StreamReader(filePath); 14 | } 15 | 16 | protected override string ReadFileContent() 17 | { 18 | Console.WriteLine("Reading text file content..."); 19 | return _reader.ReadToEnd(); 20 | } 21 | 22 | protected override void ProcessContent(string content) 23 | { 24 | Console.WriteLine("Processing text file content..."); 25 | // Simple example of content processing 26 | var processedContent = content.ToUpper(); 27 | Console.WriteLine($"Processed content: {processedContent}"); 28 | } 29 | 30 | protected override void CloseFile() 31 | { 32 | _reader.Close(); 33 | base.CloseFile(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Composite/Directory.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Structural.Composite 4 | { 5 | // Composite 6 | public class Directory : FileSystemComponent 7 | { 8 | private List _children = []; 9 | 10 | public Directory(string name) : base(name) 11 | { 12 | } 13 | 14 | public void Add(FileSystemComponent component) 15 | { 16 | _children.Add(component); 17 | } 18 | 19 | public void Remove(FileSystemComponent component) 20 | { 21 | _children.Remove(component); 22 | } 23 | 24 | public override void Display(int depth) 25 | { 26 | Console.WriteLine(new string('-', depth) + Name); 27 | foreach (var component in _children) 28 | { 29 | component.Display(depth + 2); 30 | } 31 | } 32 | 33 | public override long CalculateSize() 34 | { 35 | long totalSize = 0; 36 | foreach (var component in _children) 37 | { 38 | totalSize += component.CalculateSize(); 39 | } 40 | return totalSize; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/TemplateMethod/CsvFileProcessor.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.TemplateMethod 4 | { 5 | class CsvFileProcessor : FileProcessor 6 | { 7 | private StreamReader _reader; 8 | 9 | protected override void OpenFile(string filePath) 10 | { 11 | base.OpenFile(filePath); 12 | _reader = new StreamReader(filePath); 13 | } 14 | 15 | protected override string ReadFileContent() 16 | { 17 | Console.WriteLine("Reading CSV file content..."); 18 | return _reader.ReadToEnd(); 19 | } 20 | 21 | protected override void ProcessContent(string content) 22 | { 23 | Console.WriteLine("Processing CSV file content..."); 24 | // Example of CSV processing: split content by lines 25 | var lines = content.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); 26 | foreach (var line in lines) 27 | { 28 | var columns = line.Split(','); 29 | Console.WriteLine($"Processed CSV line: {string.Join(" | ", columns)}"); 30 | } 31 | } 32 | 33 | protected override void CloseFile() 34 | { 35 | _reader.Close(); 36 | base.CloseFile(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Mediator/FileExplorer.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Mediator 4 | { 5 | // Colleague: File Explorer 6 | public class FileExplorer 7 | { 8 | private IFileManager _mediator; 9 | public string CurrentFile { get; private set; } 10 | 11 | public void SetMediator(IFileManager mediator) 12 | { 13 | _mediator = mediator; 14 | } 15 | 16 | public void SelectFile(string filename) 17 | { 18 | CurrentFile = filename; 19 | Console.WriteLine($"File selected: {filename}"); 20 | } 21 | 22 | public void CreateFile() 23 | { 24 | if (!string.IsNullOrEmpty(CurrentFile)) 25 | { 26 | _mediator.CreateFile(CurrentFile); 27 | _mediator.Notify(this, "FileCreated"); 28 | } 29 | } 30 | 31 | public void OpenFile() 32 | { 33 | if (!string.IsNullOrEmpty(CurrentFile)) 34 | { 35 | _mediator.OpenFile(CurrentFile); 36 | _mediator.Notify(this, "FileOpened"); 37 | } 38 | } 39 | 40 | public void DeleteFile() 41 | { 42 | if (!string.IsNullOrEmpty(CurrentFile)) 43 | { 44 | _mediator.DeleteFile(CurrentFile); 45 | _mediator.Notify(this, "FileDeleted"); 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Builder/OperatingSystemConfigBuilder.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.Builder 4 | { 5 | public class OperatingSystemConfigBuilder : IOperatingSystemConfigBuilder 6 | { 7 | private readonly OperatingSystemConfig _config; 8 | 9 | public OperatingSystemConfigBuilder() 10 | { 11 | _config = new OperatingSystemConfig(); 12 | } 13 | 14 | public IOperatingSystemConfigBuilder SetOSName(string osName) 15 | { 16 | _config.OSName = osName; 17 | return this; 18 | } 19 | 20 | public IOperatingSystemConfigBuilder SetVersion(string version) 21 | { 22 | _config.Version = version; 23 | return this; 24 | } 25 | 26 | public IOperatingSystemConfigBuilder SetFileSystem(string fileSystem) 27 | { 28 | _config.FileSystem = fileSystem; 29 | return this; 30 | } 31 | 32 | public IOperatingSystemConfigBuilder EnableFirewall(bool enable) 33 | { 34 | _config.IsFirewallEnabled = enable; 35 | return this; 36 | } 37 | 38 | public IOperatingSystemConfigBuilder SetNetworkSettings(string networkSettings) 39 | { 40 | _config.NetworkSettings = networkSettings; 41 | return this; 42 | } 43 | 44 | public OperatingSystemConfig Build() 45 | { 46 | return _config; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Singleton/LockSingleton.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Creational.Singleton 4 | { 5 | public sealed class LockSingleton 6 | { 7 | // Private static instance of the Singleton class 8 | private static LockSingleton? _instance = null; 9 | // Object used for locking 10 | private static readonly object _lock = new(); 11 | 12 | // Private constructor to prevent instantiation from outside 13 | private LockSingleton() 14 | { 15 | // Initialize the singleton instance 16 | } 17 | 18 | // Public static method to get the singleton instance 19 | public static LockSingleton Instance 20 | { 21 | get 22 | { 23 | // Check if the instance is null 24 | if (_instance == null) 25 | { 26 | // Lock to ensure that only one thread can enter this block at a time 27 | lock (_lock) 28 | { 29 | // Double-check if the instance is still null 30 | // Create the singleton instance 31 | _instance ??= new LockSingleton(); 32 | } 33 | } 34 | // Return the singleton instance 35 | return _instance; 36 | } 37 | } 38 | 39 | // Example method 40 | public void DoSomething() 41 | { 42 | // Do something 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Memento/FileHistory.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Memento 4 | { 5 | // Caretaker: Manages mementos 6 | public class FileHistory 7 | { 8 | private readonly Stack _undoStack = new Stack(); 9 | private readonly Stack _redoStack = new Stack(); 10 | private readonly FileEditor _fileEditor; 11 | 12 | public FileHistory(FileEditor fileEditor) 13 | { 14 | _fileEditor = fileEditor; 15 | } 16 | 17 | public void Save() 18 | { 19 | _undoStack.Push(_fileEditor.Save()); 20 | _redoStack.Clear(); // Clear redo history after a new save 21 | } 22 | 23 | public void Undo() 24 | { 25 | if (_undoStack.Count > 0) 26 | { 27 | _redoStack.Push(_fileEditor.Save()); // Save the current state for redo 28 | _fileEditor.Restore(_undoStack.Pop()); 29 | } 30 | else 31 | { 32 | Console.WriteLine("No states to undo."); 33 | } 34 | } 35 | 36 | public void Redo() 37 | { 38 | if (_redoStack.Count > 0) 39 | { 40 | _undoStack.Push(_fileEditor.Save()); // Save the current state for undo 41 | _fileEditor.Restore(_redoStack.Pop()); 42 | } 43 | else 44 | { 45 | Console.WriteLine("No states to redo."); 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Observer/FileWatcher.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Observer 4 | { 5 | // Concrete Subject: File Watcher 6 | public class FileWatcher : IFileSubject 7 | { 8 | private readonly List _observers = new List(); 9 | 10 | public void RegisterObserver(IFileObserver observer) 11 | { 12 | _observers.Add(observer); 13 | } 14 | 15 | public void UnregisterObserver(IFileObserver observer) 16 | { 17 | _observers.Remove(observer); 18 | } 19 | 20 | public void NotifyObservers(string fileName, string changeType) 21 | { 22 | foreach (var observer in _observers) 23 | { 24 | observer.Update(fileName, changeType); 25 | } 26 | } 27 | 28 | public void StartWatching(string path) 29 | { 30 | var fileSystemWatcher = new FileSystemWatcher(path) 31 | { 32 | NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName 33 | }; 34 | 35 | fileSystemWatcher.Created += (sender, args) => NotifyObservers(args.FullPath, "created"); 36 | fileSystemWatcher.Changed += (sender, args) => NotifyObservers(args.FullPath, "modified"); 37 | fileSystemWatcher.Deleted += (sender, args) => NotifyObservers(args.FullPath, "deleted"); 38 | 39 | fileSystemWatcher.EnableRaisingEvents = true; 40 | 41 | Console.WriteLine($"Started watching directory: {path}"); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.10.35122.118 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDesignPatterns", "DotnetDesignPatterns\DotnetDesignPatterns.csproj", "{24653D04-8436-43E7-A6E3-B300EAFD43C0}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotnetDesignPatterns.Tests", "DotnetDesignPatterns.Tests\DotnetDesignPatterns.Tests.csproj", "{6276D3BE-8C30-4C6E-A4A2-DDBF64C23140}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {24653D04-8436-43E7-A6E3-B300EAFD43C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {24653D04-8436-43E7-A6E3-B300EAFD43C0}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {24653D04-8436-43E7-A6E3-B300EAFD43C0}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {24653D04-8436-43E7-A6E3-B300EAFD43C0}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {6276D3BE-8C30-4C6E-A4A2-DDBF64C23140}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {6276D3BE-8C30-4C6E-A4A2-DDBF64C23140}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {6276D3BE-8C30-4C6E-A4A2-DDBF64C23140}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {6276D3BE-8C30-4C6E-A4A2-DDBF64C23140}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {754B08E9-BCD6-47D0-B7B8-E65C5BC8B1D5} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns.Tests/Creational/Singleton/LazySingletonTests.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | using DotnetDesignPatterns.Creational.Singleton; 4 | 5 | namespace DotnetDesignPatterns.Tests.Creational.Singleton 6 | { 7 | public class LazySingletonTests 8 | { 9 | [Fact] 10 | public void Instance_ShouldReturnSameInstance() 11 | { 12 | // Arrange & Act 13 | var instance1 = LazySingleton.Instance; 14 | var instance2 = LazySingleton.Instance; 15 | 16 | // Assert 17 | Assert.Same(instance1, instance2); 18 | } 19 | 20 | [Fact] 21 | public void DoSomething_ShouldExecuteWithoutErrors() 22 | { 23 | // Arrange 24 | var instance = LazySingleton.Instance; 25 | 26 | // Act & Assert 27 | var exception = Record.Exception(() => instance.DoSomething()); 28 | 29 | Assert.Null(exception); 30 | } 31 | 32 | [Fact] 33 | public void Instance_ShouldBeThreadSafe() 34 | { 35 | // Arrange 36 | LazySingleton instance1 = null; 37 | LazySingleton instance2 = null; 38 | 39 | // Act 40 | var thread1 = new Thread(() => instance1 = LazySingleton.Instance); 41 | var thread2 = new Thread(() => instance2 = LazySingleton.Instance); 42 | 43 | thread1.Start(); 44 | thread2.Start(); 45 | 46 | thread1.Join(); 47 | thread2.Join(); 48 | 49 | // Assert 50 | Assert.NotNull(instance1); 51 | Assert.NotNull(instance2); 52 | Assert.Same(instance1, instance2); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns.Tests/Creational/Singleton/LockSingletonTests.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | using DotnetDesignPatterns.Creational.Singleton; 4 | 5 | namespace DotnetDesignPatterns.Tests.Creational.Singleton 6 | { 7 | public class LockSingletonTests 8 | { 9 | [Fact] 10 | public void Instance_ShouldReturnSameInstance() 11 | { 12 | // Arrange & Act 13 | var instance1 = LockSingleton.Instance; 14 | var instance2 = LockSingleton.Instance; 15 | 16 | // Assert 17 | Assert.Same(instance1, instance2); 18 | } 19 | 20 | [Fact] 21 | public void DoSomething_ShouldExecuteWithoutErrors() 22 | { 23 | // Arrange 24 | var instance = LockSingleton.Instance; 25 | 26 | // Act & Assert 27 | var exception = Record.Exception(() => instance.DoSomething()); 28 | 29 | Assert.Null(exception); 30 | } 31 | 32 | [Fact] 33 | public void Instance_ShouldBeThreadSafe() 34 | { 35 | // Arrange 36 | LockSingleton instance1 = null; 37 | LockSingleton instance2 = null; 38 | 39 | // Act 40 | var thread1 = new Thread(() => instance1 = LockSingleton.Instance); 41 | var thread2 = new Thread(() => instance2 = LockSingleton.Instance); 42 | 43 | thread1.Start(); 44 | thread2.Start(); 45 | 46 | thread1.Join(); 47 | thread2.Join(); 48 | 49 | // Assert 50 | Assert.NotNull(instance1); 51 | Assert.NotNull(instance2); 52 | Assert.Same(instance1, instance2); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Iterator/Directory.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Iterator 4 | { 5 | // Concrete Element: Directory 6 | public class Directory : IFileSystemElement, IFileSystemCollection 7 | { 8 | public string Name { get; } 9 | private readonly List _elements; 10 | 11 | public Directory(string name) 12 | { 13 | Name = name; 14 | _elements = new List(); 15 | } 16 | 17 | public void AddElement(IFileSystemElement element) 18 | { 19 | _elements.Add(element); 20 | } 21 | 22 | public IIterator CreateIterator() 23 | { 24 | return new FileSystemIterator(_elements); 25 | } 26 | 27 | public void PrintDetails() 28 | { 29 | Console.WriteLine($"Directory: {Name}"); 30 | } 31 | 32 | private class FileSystemIterator : IIterator 33 | { 34 | private readonly List _elements; 35 | private int _currentIndex; 36 | 37 | public FileSystemIterator(List elements) 38 | { 39 | _elements = elements; 40 | _currentIndex = 0; 41 | } 42 | 43 | public bool HasNext() 44 | { 45 | return _currentIndex < _elements.Count; 46 | } 47 | 48 | public IFileSystemElement Next() 49 | { 50 | if (!HasNext()) 51 | throw new InvalidOperationException("No more elements."); 52 | 53 | return _elements[_currentIndex++]; 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Mediator/FileManager.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | namespace DotnetDesignPatterns.Behavioral.Mediator 4 | { 5 | // Concrete Mediator 6 | public class FileManager : IFileManager 7 | { 8 | private readonly FileExplorer _fileExplorer; 9 | private readonly FileOperationHandler _fileOperationHandler; 10 | private readonly Logger _logger; 11 | 12 | public FileManager(FileExplorer fileExplorer, FileOperationHandler fileOperationHandler, Logger logger) 13 | { 14 | _fileExplorer = fileExplorer; 15 | _fileOperationHandler = fileOperationHandler; 16 | _logger = logger; 17 | 18 | _fileExplorer.SetMediator(this); 19 | _fileOperationHandler.SetMediator(this); 20 | _logger.SetMediator(this); 21 | } 22 | 23 | public void CreateFile(string filename) 24 | { 25 | _fileOperationHandler.CreateFile(filename); 26 | } 27 | 28 | public void OpenFile(string filename) 29 | { 30 | _fileOperationHandler.OpenFile(filename); 31 | } 32 | 33 | public void DeleteFile(string filename) 34 | { 35 | _fileOperationHandler.DeleteFile(filename); 36 | } 37 | 38 | public void Notify(object sender, string eventCode) 39 | { 40 | switch (eventCode) 41 | { 42 | case "FileCreated": 43 | _logger.Log($"File created: {((FileExplorer)sender).CurrentFile}"); 44 | break; 45 | case "FileOpened": 46 | _logger.Log($"File opened: {((FileExplorer)sender).CurrentFile}"); 47 | break; 48 | case "FileDeleted": 49 | _logger.Log($"File deleted: {((FileExplorer)sender).CurrentFile}"); 50 | break; 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns.Tests/Creational/Builder/BuilderTests.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | using DotnetDesignPatterns.Creational.Builder; 4 | 5 | namespace DotnetDesignPatterns.Tests.Creational.Builder 6 | { 7 | public class BuilderTests 8 | { 9 | [Fact] 10 | public void Build_ShouldReturnConfiguredOperatingSystemConfig() 11 | { 12 | // Arrange 13 | var builder = new OperatingSystemConfigBuilder(); 14 | string osName = "Linux"; 15 | string version = "Ubuntu 22.04"; 16 | string fileSystem = "ext4"; 17 | bool firewallEnabled = true; 18 | string networkSettings = "DHCP"; 19 | 20 | // Act 21 | var config = builder 22 | .SetOSName(osName) 23 | .SetVersion(version) 24 | .SetFileSystem(fileSystem) 25 | .EnableFirewall(firewallEnabled) 26 | .SetNetworkSettings(networkSettings) 27 | .Build(); 28 | 29 | // Assert 30 | Assert.NotNull(config); 31 | Assert.Equal(osName, config.OSName); 32 | Assert.Equal(version, config.Version); 33 | Assert.Equal(fileSystem, config.FileSystem); 34 | Assert.Equal(firewallEnabled, config.IsFirewallEnabled); 35 | Assert.Equal(networkSettings, config.NetworkSettings); 36 | } 37 | 38 | [Fact] 39 | public void DefaultBuild_ShouldReturnEmptyOperatingSystemConfig() 40 | { 41 | // Arrange 42 | var builder = new OperatingSystemConfigBuilder(); 43 | 44 | // Act 45 | var config = builder.Build(); 46 | 47 | // Assert 48 | Assert.NotNull(config); 49 | Assert.Null(config.OSName); 50 | Assert.Null(config.Version); 51 | Assert.Null(config.FileSystem); 52 | Assert.False(config.IsFirewallEnabled); 53 | Assert.Null(config.NetworkSettings); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Facade/README.md: -------------------------------------------------------------------------------- 1 | # Facade Design Pattern 2 | 3 | The Facade Design Pattern is a structural pattern that provides a simplified interface to a complex subsystem. It aims to make a system easier to use by hiding its complexities behind a unified interface. 4 | 5 | ## Key Concepts of the Facade Pattern 6 | 7 | 1. Facade: 8 | Provides a simplified interface to a complex subsystem. It acts as a wrapper that hides the complexities of the subsystem by exposing a high-level interface for clients. 9 | Implements a unified interface that delegates client requests to the appropriate subsystem components. The facade encapsulates the interactions between multiple components and simplifies the client's interaction with the subsystem. 10 | 11 | 2. Subsystems: 12 | Represent the complex components or classes within the subsystem that the facade interacts with. These components perform the actual work but may have complex interfaces and interactions. 13 | Consists of multiple classes or modules that handle specific functionalities. The facade coordinates these components to provide a higher-level operation to the client. 14 | 15 | ## Code Explanation 16 | 17 | * **Subsystems**: 18 | `FileReader`: Handles the reading of files. Contains methods to simulate reading from a file. 19 | `FileWriter`: Handles writing to files. Contains methods to simulate writing to a file. 20 | `FileValidator`: Validates files before operations. Contains methods to simulate file validation. 21 | 22 | * **Facade**: 23 | Class `FileManagerFacade` provides a simplified interface for interacting with the file management subsystem. It encapsulates the complex interactions between `FileReader`, `FileWriter`, and `FileValidator`. 24 | Contains a method `ProcessFile` that performs file validation, reads the file, and writes new content, all using the subsystem components. 25 | 26 | ## Usage 27 | 28 | ```csharp 29 | class Program 30 | { 31 | static void Main(string[] args) 32 | { 33 | // Create a facade instance 34 | var fileManager = new FileManagerFacade(); 35 | 36 | // Use the facade to process a file 37 | fileManager.ProcessFile("path/to/file.txt", "New content"); 38 | } 39 | } 40 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns.Tests/Creational/Prototype/PrototypeTests.cs: -------------------------------------------------------------------------------- 1 | // (c) 2024 Francesco Del Re 2 | // This code is licensed under MIT license (see LICENSE.txt for details) 3 | using DotnetDesignPatterns.Creational.Prototype; 4 | 5 | namespace DotnetDesignPatterns.Tests.Creational.Prototype 6 | { 7 | public class PrototypeTests 8 | { 9 | [Fact] 10 | public void Clone_ShouldCreateDeepCopy() 11 | { 12 | // Arrange 13 | var original = new OperatingSystemSettings("Windows", "10.0"); 14 | 15 | // Act 16 | var clone = original.Clone(); 17 | 18 | // Assert 19 | Assert.NotNull(clone); 20 | Assert.NotSame(original, clone); 21 | Assert.Equal(original.OSName, clone.OSName); 22 | Assert.Equal(original.Version, clone.Version); 23 | } 24 | 25 | [Fact] 26 | public void Clone_ModifyingCloneShouldNotAffectOriginal() 27 | { 28 | // Arrange 29 | var original = new OperatingSystemSettings("Linux", "5.0"); 30 | var clone = original.Clone(); 31 | 32 | // Act 33 | clone.OSName = "Ubuntu"; 34 | clone.Version = "20.04"; 35 | 36 | // Assert 37 | Assert.NotEqual(original.OSName, clone.OSName); 38 | Assert.NotEqual(original.Version, clone.Version); 39 | Assert.Equal("Linux", original.OSName); 40 | Assert.Equal("5.0", original.Version); 41 | } 42 | 43 | [Fact] 44 | public void DisplaySettings_ShouldOutputCorrectDetails() 45 | { 46 | // Arrange 47 | var settings = new OperatingSystemSettings("MacOS", "12.5"); 48 | 49 | // Act 50 | var consoleOutput = CaptureConsoleOutput(() => settings.DisplaySettings()); 51 | 52 | // Assert 53 | Assert.Contains("OS Name: MacOS", consoleOutput); 54 | Assert.Contains("Version: 12.5", consoleOutput); 55 | } 56 | 57 | // Helper method to capture console output 58 | private string CaptureConsoleOutput(Action action) 59 | { 60 | using (var stringWriter = new StringWriter()) 61 | { 62 | Console.SetOut(stringWriter); 63 | action.Invoke(); 64 | return stringWriter.ToString(); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/README.md: -------------------------------------------------------------------------------- 1 | # Behavioral Design Patterns 2 | Behavioral design patterns focus on the interaction between objects and the way responsibilities are distributed among them. These patterns are concerned with algorithms and the assignment of responsibilities between objects. They help in designing systems that are flexible, maintainable, and scalable by defining how objects communicate and collaborate to achieve specific behaviors. 3 | 4 | ## Key Concepts of Behavioral Design Patterns 5 | 1. Encapsulation of Behavior: 6 | - **Purpose**: Encapsulates complex behavior within objects to simplify the interface and manage how operations are executed. This separation of concerns allows for more modular and maintainable code. 7 | - **Implementation**: Encapsulates operations or behavior in classes, providing a clear interface for interacting with the behavior while hiding the implementation details. 8 | 9 | 2. Responsibility Delegation: 10 | - **Purpose**: Distributes responsibilities among objects to ensure that no single object becomes overly complex or handles too many tasks. This delegation supports the Single Responsibility Principle and enhances code readability. 11 | - **Implementation**: Uses patterns that define how objects should collaborate and pass responsibilities to other objects. This allows for dynamic changes in behavior and promotes flexibility. 12 | 13 | 3. Behavioral Patterns: 14 | - **Purpose**: Defines common communication patterns between objects and how objects interact to accomplish specific tasks. Behavioral patterns focus on how objects collaborate and the sequence of interactions. 15 | - **Implementation**: Provides solutions to common problems in object communication, such as how to execute operations, handle events, or manage state changes. 16 | 17 | 4. Flexible Object Interaction: 18 | - **Purpose**: Allows objects to interact with each other in a flexible and extensible manner. This flexibility makes it easier to adapt to changing requirements and extend functionality. 19 | - **Implementation**: Uses patterns that enable objects to communicate and collaborate without being tightly coupled, facilitating easier changes and extensions. 20 | 21 | ## When to Use Behavioral Patterns 22 | - When the interaction between objects needs to be flexible and decoupled. 23 | - When you need to define a communication protocol between objects in a systematic way. 24 | - When the logic is complex and you want to distribute responsibilities across different classes. 25 | - When you want to encapsulate varying behavior to make it easily interchangeable or extendable. -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Composite/README.md: -------------------------------------------------------------------------------- 1 | # Composite Design Pattern 2 | The Composite Design Pattern is a structural pattern that allows you to compose objects into tree structures to represent part-whole hierarchies. This pattern is useful when you want to treat individual objects and compositions of objects uniformly. 3 | 4 | ## Key Concepts of the Composite Pattern 5 | 1. Component: 6 | Defines the common interface or abstract class for all objects in the hierarchy, both leaf and composite. It declares the operations that can be performed on the objects, such as rendering or calculating size. 7 | This base class or interface provides a common contract for both leaf and composite nodes, allowing clients to interact with them in a uniform way. 8 | 9 | 2. Leaf: 10 | Represents the end objects in the hierarchy that do not have any children. Leaf nodes implement the Component interface and provide concrete behavior for the operations defined by the Component. 11 | These are the objects that do not have any further sub-objects. For example, in a file system hierarchy, individual files would be leaf nodes. 12 | 13 | 3. Composite: 14 | Represents nodes that can contain other Component objects, either leaves or other composites. Composite nodes implement the Component interface and manage a collection of child components. 15 | This class provides methods to add, remove, and access child components. It aggregates the behavior of its children and delegates operations to them. 16 | 17 | ## Code Explanation 18 | * **Component**: 19 | `FileSystemComponent` is an abstract class that defines the common interface for both leaf and composite objects. It declares methods for displaying the component and calculating its size. 20 | 21 | * **Leaf**: 22 | Class `File` represents the end objects in the hierarchy (files). It implements the `Display` and `CalculateSize` methods for files. 23 | 24 | * **Composite**: 25 | Class `Directory` represents nodes that can contain other components (directories or files). It manages child components and implements the `Display` and `CalculateSize` methods to aggregate their behavior. 26 | 27 | ## Usage 28 | ```csharp 29 | class Program 30 | { 31 | static void Main(string[] args) 32 | { 33 | // Create files 34 | var file1 = new File("File1.txt", 100); 35 | var file2 = new File("File2.jpg", 500); 36 | 37 | // Create directories 38 | var directory1 = new Directory("Directory1"); 39 | var directory2 = new Directory("Directory2"); 40 | 41 | // Build hierarchy 42 | directory1.Add(file1); 43 | directory1.Add(file2); 44 | directory2.Add(directory1); 45 | 46 | // Display hierarchy 47 | directory2.Display(1); 48 | 49 | // Calculate size 50 | Console.WriteLine($"Total size of {directory2.Name}: {directory2.CalculateSize()} bytes"); 51 | } 52 | } 53 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Adapter/README.md: -------------------------------------------------------------------------------- 1 | # Adapter Design Pattern 2 | 3 | The Adapter Design Pattern is a structural pattern that allows objects with incompatible interfaces to work together. It acts as a bridge between two incompatible interfaces, enabling them to communicate. This pattern is especially useful when integrating new components with existing systems where the interfaces do not match. 4 | 5 | ## Key Concepts of the Adapter Pattern 6 | 7 | 1. Adapter: 8 | The adapter is the core component that implements the target interface and holds an instance of the adaptee. It translates the requests from the target interface to the methods of the adaptee. 9 | It implements or inherits from the target interface and translates method calls to the adaptee’s methods. The adapter often uses composition to hold a reference to the adaptee object. 10 | 11 | 2. Target Interface: 12 | Defines the interface that the client code expects to use. The target interface specifies the methods and properties that the client interacts with. 13 | This is a common interface that the client code uses, and the adapter will implement this interface to provide a unified way to interact with different adaptees. 14 | 15 | 3. Adaptee: 16 | Represents the existing class or component with an incompatible interface that needs to be adapted. The adaptee provides functionality that the client code needs but does not conform to the target interface. 17 | This is the class with the methods or properties that the adapter will translate into the target interface format. 18 | 19 | ## Code Explanation 20 | 21 | * **Target Interface**: 22 | Interface `ISystemInfo` defines the common interface (`GetSystemDetails()`) that the client code expects to interact with. 23 | 24 | * **Adaptee Classes**: 25 | Classes `WindowsOS` and `LinuxOS` represent existing system components with methods that do not match the `ISystemInfo` interface. 26 | 27 | * **Adapter Classes**: 28 | Classes `WindowsAdapter` and `LinuxAdapter` implement the `ISystemInfo` interface and adapt the interfaces of the `WindowsOS` and `LinuxOS` classes to this common interface. They translate calls from the target interface to the methods of the adaptee classes. 29 | 30 | ## Usage 31 | 32 | ```csharp 33 | class Program 34 | { 35 | static void Main(string[] args) 36 | { 37 | // Instantiate the Adaptees 38 | WindowsOS windowsOS = new WindowsOS(); 39 | LinuxOS linuxOS = new LinuxOS(); 40 | 41 | // Create adapters for the Adaptees 42 | ISystemInfo windowsAdapter = new WindowsAdapter(windowsOS); 43 | ISystemInfo linuxAdapter = new LinuxAdapter(linuxOS); 44 | 45 | // Use the adapters through the target interface 46 | Console.WriteLine($"Windows System Details: {windowsAdapter.GetSystemDetails()}"); 47 | Console.WriteLine($"Linux System Details: {linuxAdapter.GetSystemDetails()}"); 48 | } 49 | } 50 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Proxy/README.md: -------------------------------------------------------------------------------- 1 | # Proxy Design Pattern 2 | 3 | The Proxy Design Pattern is a structural pattern that provides a surrogate or placeholder for another object to control access to it. Proxies can be used for various purposes, including access control, lazy initialization, logging, and more. The proxy pattern involves creating an interface or abstract class that both the real subject and proxy class implement, allowing the proxy to act as an intermediary. 4 | 5 | ## Key Concepts of the Proxy Pattern 6 | 7 | 1. Subject Interface: 8 | Defines the common interface that both the real subject and proxy will implement. This ensures that both the proxy and the real object can be used interchangeably by the client. 9 | Specifies the methods and properties that the real subject and proxy must implement. This interface provides a consistent way for clients to interact with both the proxy and the real subject. 10 | 11 | 2. Real Subject: 12 | Represents the actual object that performs the core functionality. It contains the real implementation of the operations defined by the subject interface. 13 | Provides the concrete implementation of the subject interface. This is where the main functionality resides and is used directly by the proxy to perform actions. 14 | 15 | 3. Proxy: 16 | Acts as an intermediary between the client and the real subject. The proxy controls access to the real subject and can add additional functionality such as access control, logging, or lazy initialization. 17 | Implements the subject interface and holds a reference to the real subject. The proxy forwards client requests to the real subject and can perform additional tasks before or after delegating the request. 18 | 19 | ## Code Explanation 20 | 21 | * **Subject Interface**: 22 | `IResource` defines the common interface that both the real subject (Resource) and the proxy (ResourceProxy) implement. This ensures that both can be used interchangeably. 23 | 24 | * **Real Subject**: 25 | Class `Resource` implements the actual resource management functionality. This is where the core operations are performed. 26 | 27 | * **Proxy**: 28 | Class `ResourceProxy` controls access to the real subject. It performs additional tasks such as access control, logging, or lazy initialization. In this example, it checks user permissions and initializes the real resource only when needed (lazy initialization). 29 | 30 | ## Usage 31 | 32 | ```csharp 33 | class Program 34 | { 35 | static void Main(string[] args) 36 | { 37 | // Create a proxy with restricted access 38 | IResource proxyWithRestrictedAccess = new ResourceProxy("Guest"); 39 | proxyWithRestrictedAccess.Access(); // Should deny access 40 | 41 | // Create a proxy with admin access 42 | IResource proxyWithAdminAccess = new ResourceProxy("Admin"); 43 | proxyWithAdminAccess.Access(); // Should grant access 44 | } 45 | } 46 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Builder/README.md: -------------------------------------------------------------------------------- 1 | # Builder Design Pattern 2 | 3 | The Builder Design Pattern is a creational design pattern that provides a flexible solution to constructing complex objects. It allows an object to be constructed step-by-step, separating the construction process from the representation. This pattern is particularly useful when an object can be created in multiple ways or when the creation process involves many optional parameters or complex configurations. 4 | 5 | ## Key Concepts of the Builder Pattern 6 | 7 | 1. Separation of Construction and Representation: 8 | The Builder Pattern separates the construction of an object from its final representation, allowing the same construction process to create different representations. 9 | 10 | 2. Step-by-Step Construction: 11 | he object is constructed step-by-step through a series of method calls. This makes the creation process more flexible and easier to manage, especially when dealing with complex objects with many fields or configurations. 12 | 13 | 3. Immutability: 14 | In many implementations, once the object is built, it is immutable, meaning its state cannot be changed. This ensures that the object is fully configured when it is constructed and remains consistent throughout its lifetime. 15 | 16 | ## Code Explanation 17 | 18 | * **Product Class OperatingSystemConfig**: 19 | The `OperatingSystemConfig` class represents the final product, which is a configuration of an operating system. It has properties like OSName, Version, FileSystem, IsFirewallEnabled, and NetworkSettings. 20 | The `DisplayConfig()` method is used to print out the configuration details. 21 | 22 | * **Builder Interface IOperatingSystemConfigBuilder**: 23 | The `Build()` method returns the final `OperatingSystemConfig` object. 24 | 25 | * **Concrete Builder OperatingSystemConfigBuilder**: 26 | The `OperatingSystemConfigBuilder` class implements the `IOperatingSystemConfigBuilder` interface. It maintains an instance of `OperatingSystemConfig` and provides concrete implementations of the methods to set each configuration property. 27 | The builder methods return this to allow for method chaining, which is a common practice in builder pattern implementations. 28 | 29 | ## Usage 30 | 31 | ```csharp 32 | class Program 33 | { 34 | static void Main(string[] args) 35 | { 36 | // Building a Linux OS configuration using the builder 37 | OperatingSystemConfig linuxConfig = new OperatingSystemConfigBuilder() 38 | .SetOSName("Linux") 39 | .SetVersion("5.15") 40 | .SetFileSystem("ext4") 41 | .EnableFirewall(true) 42 | .SetNetworkSettings("DHCP") 43 | .Build(); 44 | linuxConfig.DisplayConfig(); 45 | 46 | // Building a Windows OS configuration using the builder 47 | OperatingSystemConfig windowsConfig = new OperatingSystemConfigBuilder() 48 | .SetOSName("Windows") 49 | .SetVersion("11") 50 | .SetFileSystem("NTFS") 51 | .EnableFirewall(true) 52 | .SetNetworkSettings("Static IP") 53 | .Build(); 54 | windowsConfig.DisplayConfig(); 55 | } 56 | } 57 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Prototype/README.md: -------------------------------------------------------------------------------- 1 | # Prototype Design Pattern 2 | 3 | The Prototype Design Pattern is a creational design pattern that allows objects to be copied rather than created from scratch. It is particularly useful when the creation of an object is complex or expensive and when you need to create multiple instances of an object with the same structure but different data. The Prototype Pattern helps in cloning existing objects, making it easier to create new objects based on prototypes. 4 | 5 | ## Key Concepts of the Prototype Pattern 6 | 7 | 1. Prototype Interface: 8 | Defines a common interface for cloning itself. This interface typically includes a `Clone()` method that returns a copy of the object. 9 | This can be an interface or an abstract class that declares the `Clone()` method. Concrete classes implement this method to perform the cloning. 10 | 11 | 2. Concrete Prototype: 12 | Implements the Prototype interface and provides the actual cloning logic. Each concrete prototype class defines how an object is copied, often using a shallow or deep copy approach. 13 | Concrete classes that inherit from the prototype interface and override the `Clone()` method to create a copy of themselves. 14 | 15 | 3. Shallow Copy vs. Deep Copy: 16 | Shallow Copy: Copies the immediate values of the object, including references to other objects, but does not copy the referenced objects themselves. Changes to the referenced objects will affect the original and cloned objects. 17 | Deep Copy: Copies the object and all objects it references, creating a completely independent copy. Changes to the cloned object or its references do not affect the original object. 18 | 19 | ## Code Explanation 20 | 21 | * **Interface IPrototype**: 22 | The `IPrototype` interface defines a `Clone()` method that allows for cloning the operating system settings object. Any class implementing this interface must provide an implementation of the `Clone()` method. 23 | 24 | * **Class OperatingSystemSettings**: 25 | The `OperatingSystemSettings` class represents the configuration settings of an operating system. It contains properties like OSName, Version to store system settings. 26 | The class constructor initializes these properties with the provided values. 27 | The `Clone()` method creates and returns a new instance of `OperatingSystemSettings` with the same properties as the current object, enabling the cloning of configurations. 28 | 29 | * **Method DisplaySettings**: 30 | This method prints the operating system settings to the console, allowing you to verify that the clone has correctly inherited the properties from the original object. 31 | 32 | ## Usage 33 | 34 | ```csharp 35 | class Program 36 | { 37 | static void Main(string[] args) 38 | { 39 | // Create an original configuration for an operating system 40 | OperatingSystemSettings originalSettings = new OperatingSystemSettings("Linux", "5.15"); 41 | originalSettings.DisplaySettings(); 42 | 43 | // Clone the original configuration and modify it to create a new configuration 44 | OperatingSystemSettings clonedSettings = (OperatingSystemSettings)originalSettings.Clone(); 45 | clonedSettings.OSName = "Ubuntu"; 46 | clonedSettings.Version = "22.04"; 47 | clonedSettings.DisplaySettings(); 48 | 49 | // Another clone with further modifications 50 | OperatingSystemSettings anotherClonedSettings = (OperatingSystemSettings)originalSettings.Clone(); 51 | anotherClonedSettings.OSName = "Windows"; 52 | anotherClonedSettings.Version = "11"; 53 | anotherClonedSettings.DisplaySettings(); 54 | } 55 | } 56 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Bridge/README.md: -------------------------------------------------------------------------------- 1 | # Bridge Design Pattern 2 | 3 | The Bridge Design Pattern is a structural pattern that decouples an abstraction from its implementation so that the two can vary independently. This pattern is useful when you need to separate a complex abstraction from its implementation to allow both to evolve independently. 4 | 5 | ## Key Concepts of the Bridge Pattern 6 | 7 | 1. Abstraction: 8 | Defines the high-level control logic or interface that the client code interacts with. It provides a way to manage or manipulate complex objects. 9 | The abstraction holds a reference to an implementor object and delegates the actual work to it. This allows the abstraction to remain independent of the specifics of how the tasks are performed. 10 | 11 | 2. Implementor Interface: 12 | Defines the interface for the implementation classes. This interface specifies the operations that the concrete implementors must provide. 13 | This interface is designed to be independent of the abstraction. It provides the methods or operations that are implemented by concrete classes. 14 | 15 | 3. Concrete Implementors: 16 | Provide specific implementations of the operations defined in the implementor interface. These classes contain the details of how tasks are performed. 17 | Each concrete implementor provides its own version of the methods declared in the implementor interface, allowing different ways to perform the same operations. 18 | 19 | 4. Refined Abstraction: 20 | Extends the abstraction to provide more specific behavior or functionality. It uses the implementor to perform tasks but may add additional functionality. 21 | The refined abstraction provides specific implementations of the operations defined in the abstraction and uses the implementor to execute the underlying tasks. 22 | 23 | ## Code Explanation 24 | 25 | * **Abstraction**: 26 | Class `FileManager` provides the high-level file management operations. It holds a reference to the `IFileSystem` implementor, allowing it to delegate file operations. 27 | 28 | * **Implementor Interface**: 29 | Interface `IFileSystem` defines the operations that need to be implemented by different file systems. It separates the abstraction from its concrete implementation. 30 | 31 | * **Concrete Implementors**: 32 | Classes `LinuxFileSystem` and `WindowsFileSystem` provide specific implementations for file operations on different operating systems. Each concrete implementor handles file operations according to the OS-specific requirements. 33 | 34 | * **Refined Abstraction**: 35 | Class `TextFileManager` extends the `FileManager` abstract class and uses the `IFileSystem` interface to perform file operations. This allows for different types of file managers to be created based on the abstraction. 36 | 37 | ## Usage 38 | 39 | ```csharp 40 | class Program 41 | { 42 | static void Main(string[] args) 43 | { 44 | // Create file system implementations 45 | IFileSystem windowsFileSystem = new WindowsFileSystem(); 46 | IFileSystem linuxFileSystem = new LinuxFileSystem(); 47 | 48 | // Create file managers for text files 49 | FileManager windowsTextFileManager = new TextFileManager(windowsFileSystem); 50 | FileManager linuxTextFileManager = new TextFileManager(linuxFileSystem); 51 | 52 | // Use the file managers 53 | windowsTextFileManager.SaveFile("example.txt", "Hello, Windows!"); 54 | Console.WriteLine(windowsTextFileManager.ReadFile("example.txt")); 55 | 56 | linuxTextFileManager.SaveFile("example.txt", "Hello, Linux!"); 57 | Console.WriteLine(linuxTextFileManager.ReadFile("example.txt")); 58 | } 59 | } 60 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Structural/Flyweight/README.md: -------------------------------------------------------------------------------- 1 | # Flyweight Design Pattern 2 | 3 | The Flyweight Design Pattern is a structural pattern that reduces the memory usage by sharing common parts of objects. It is particularly useful when dealing with a large number of objects that share a common state. The Flyweight Pattern helps to optimize memory usage by avoiding the creation of duplicate objects that share similar data. 4 | 5 | ## Key Concepts of the Flyweight Pattern 6 | 7 | 1. Flyweight Interface: 8 | Defines the common interface for all flyweight objects. This interface provides methods that the flyweight objects must implement, ensuring that they can be used interchangeably. 9 | The interface specifies the operations that can be performed on the flyweight objects. This ensures that both concrete flyweights and the client code can interact with the objects in a uniform manner. 10 | 11 | 2. Concrete Flyweight: 12 | Implements the flyweight interface and contains the intrinsic state (shared state) that is common across multiple instances. Intrinsic state is immutable and shared among flyweight instances. 13 | Provides the actual implementation of the flyweight operations and stores the data that is shared among multiple objects. The concrete flyweight does not manage any unique state specific to individual instances. 14 | 15 | 3. Intrinsic State: 16 | Represents the part of the object's state that is shared and can be shared among multiple objects. Intrinsic state is stored in the concrete flyweight and is consistent across all instances of the flyweight. 17 | This state is stored within the flyweight objects and is reused across different contexts to save memory. 18 | 19 | 4. Extrinsic State: 20 | Represents the part of the object's state that varies and is not shared. This state is managed by the client code and is provided to the flyweight when needed. Extrinsic state is not stored in the flyweight objects but is passed as parameters or provided externally. 21 | Managed outside the flyweight and is provided to the flyweight objects during operations. This allows the flyweight to work with varying data without having to store it internally. 22 | 23 | 5. Flyweight Factory: 24 | Manages the creation and sharing of flyweight objects. It maintains a cache or pool of existing flyweight instances to ensure that duplicate objects are not created unnecessarily. 25 | Responsible for checking if a flyweight instance already exists in the cache. If it does, the factory returns the existing instance; otherwise, it creates a new one and adds it to the cache. 26 | 27 | ## Code Explanation 28 | 29 | * **Flyweight Interface**: 30 | IFileMetadata defines the common interface that all flyweight objects will implement. It ensures that all concrete flyweights adhere to a uniform interface for displaying file information. 31 | 32 | * **Concrete Flyweight**: 33 | FileMetadata implements the flyweight interface and contains the shared state (metadata) for files, such as file type and owner. This class does not store any unique state specific to individual file instances. 34 | 35 | * **Flyweight Factory**: 36 | FileMetadataFactory manages the creation and sharing of flyweight instances. It maintains a cache of existing flyweight objects to avoid creating duplicates. If the required flyweight object is already in the cache, it reuses the existing instance; otherwise, it creates a new one. 37 | 38 | ## Usage 39 | 40 | ```csharp 41 | class Program 42 | { 43 | static void Main(string[] args) 44 | { 45 | // Create a proxy with restricted access 46 | IResource proxyWithRestrictedAccess = new ResourceProxy("Guest"); 47 | proxyWithRestrictedAccess.Access(); // Should deny access 48 | 49 | // Create a proxy with admin access 50 | IResource proxyWithAdminAccess = new ResourceProxy("Admin"); 51 | proxyWithAdminAccess.Access(); // Should grant access 52 | } 53 | } 54 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Creational/Factory/README.md: -------------------------------------------------------------------------------- 1 | # Factory Design Pattern 2 | The Factory Design Pattern is a creational design pattern that provides an interface for creating objects in a super class but allows subclasses to alter the type of objects that will be created. Essentially, the Factory Pattern defines an interface or abstract class for creating an object, but it lets the subclasses decide which class to instantiate. This pattern promotes loose coupling by eliminating the need to bind application-specific classes into the code. 3 | 4 | ## Key Concepts of the Factory Pattern 5 | 1. Factory Method: 6 | The Factory Method defines an interface for creating objects but allows subclasses to alter the type of objects that will be created. It encapsulates the object creation logic in a method, which can be overridden in subclasses. 7 | Typically implemented as a method in a factory class or interface that returns instances of a product interface or abstract class. 8 | 9 | 2. Product Interface: 10 | Defines the common interface for all products that the factory method will produce. This allows the client code to interact with different types of products through a uniform interface. 11 | Can be an interface or an abstract class that specifies the methods that concrete products must implement. 12 | 13 | 3. Concrete Products: 14 | These are the specific implementations of the product interface. Each concrete product class implements or inherits from the product interface, providing its own version of the functionality. 15 | Classes that implement the product interface, defining the specific behaviors and attributes of the product. 16 | 17 | 4. Factory Class: 18 | Contains the factory method that creates and returns instances of concrete products. It may also contain logic to decide which concrete product to instantiate based on input parameters or other criteria. 19 | A class that implements the factory method, often with methods for creating different types of products based on the input or configuration. 20 | 21 | ## Code Explanation 22 | * **Interface IOperatingSystem**: 23 | This interface defines the common behavior for different operating systems. It includes methods `Configure()` and `DisplayInfo()` that each concrete operating system class must implement. 24 | 25 | * **Concrete Classes LinuxOS, WindowsOS**: 26 | These classes implement the `IOperatingSystem` interface and provide specific implementations for the `Configure()` and `DisplayInfo()` methods. Each class represents a different operating system with its unique configuration logic. 27 | 28 | * **Factory Class OperatingSystemFactory**: 29 | The `OperatingSystemFactory` is a static class that provides a method `CreateOperatingSystem` to create instances of `IOperatingSystem` based on the provided operating system type (osType). The factory method uses a switch statement to return the correct instance based on the input string. 30 | If an invalid osType is provided, the factory throws an ArgumentException to handle the error. 31 | 32 | ## Usage 33 | ```csharp 34 | class Program 35 | { 36 | static void Main(string[] args) 37 | { 38 | // Creating Linux OS configuration using the factory 39 | IOperatingSystem linux = OperatingSystemFactory.CreateOperatingSystem("linux"); 40 | linux.Configure(); 41 | linux.DisplayInfo(); 42 | 43 | // Creating Windows OS configuration using the factory 44 | IOperatingSystem windows = OperatingSystemFactory.CreateOperatingSystem("windows"); 45 | windows.Configure(); 46 | windows.DisplayInfo(); 47 | } 48 | } 49 | ``` 50 | 51 | ## Key Differences between Abstract Factory and Factory 52 | | Aspect | Abstract Factory Pattern | Factory Pattern | 53 | | --- | --- | --- | 54 | | Purpose | Creates individual objects based on input | Creates families of related objects | 55 | | Complexity | Simpler, lower level | More complex, higher level | 56 | | Use Cases | Single object creation with flexibility | Cross-platform or themed systems needing cohesive components | 57 | | Flexibility | Limited to single object creation | Scalable to families of objects | 58 | | Structure | Often uses a single factory class | Typically uses a factory interface with multiple implementations for families | -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Strategy/README.md: -------------------------------------------------------------------------------- 1 | # Strategy Design Pattern 2 | The Strategy design pattern is a behavioral pattern that defines a family of algorithms, encapsulates each algorithm, and makes them interchangeable. This pattern allows a client to choose an algorithm from a family of algorithms at runtime. It's particularly useful when you need to select a specific behavior or strategy dynamically. 3 | 4 | ## Key Concepts of the Strategy Pattern 5 | 1. Strategy Interface: 6 | Definition: An interface or abstract class that defines a common method for a family of algorithms or strategies. 7 | Purpose: Provides a way to encapsulate a family of related algorithms or behaviors, allowing them to be interchangeable. 8 | 9 | 2. Concrete Strategies: 10 | Definition: Classes that implement the Strategy interface, providing specific implementations of the algorithm or behavior. 11 | Purpose: Each concrete strategy implements a different algorithm or variation of the algorithm defined by the Strategy interface. 12 | 13 | 3. Context: 14 | Definition: The class that uses a Strategy object to perform a particular operation. It maintains a reference to a Strategy object and delegates the algorithm execution to this strategy. 15 | Purpose: Acts as a client of the Strategy interface, providing a way to change the strategy at runtime and execute the algorithm defined by the strategy. 16 | 17 | 4. Encapsulation of Algorithms: 18 | Definition: Algorithms or behaviors are encapsulated within their own strategy classes, ensuring that each strategy is responsible for its own implementation. 19 | Purpose: Promotes clean code organization by separating different algorithms and keeping them encapsulated within their respective classes. 20 | 21 | 5. Interchangeability: 22 | Definition: Strategies can be swapped or replaced dynamically at runtime, allowing the context to use different algorithms as needed. 23 | Purpose: Provides flexibility and adaptability, allowing the behavior of an object to be changed without modifying its code. 24 | 25 | 6. Decoupling: 26 | Definition: The context class is decoupled from the specific implementations of the strategies. It interacts with the Strategy interface rather than concrete strategy classes. 27 | Purpose: Reduces dependencies between the context and specific algorithms, making the system more modular and easier to maintain. 28 | 29 | 7. Dynamic Behavior Change: 30 | Definition: The ability to change the behavior of the context at runtime by switching the strategy object. 31 | Purpose: Allows the behavior of the system to be modified dynamically based on the current needs or conditions. 32 | 33 | 8. Open/Closed Principle: 34 | Definition: The Strategy pattern adheres to the Open/Closed Principle, which states that a class should be open for extension but closed for modification. 35 | Purpose: New strategies can be added without modifying the context class or existing strategy classes, promoting extensibility and reducing the risk of introducing bugs. 36 | 37 | ## Code Explanation 38 | 1. Strategy Interface: 39 | `ICompressionStrategy` defines the common interface for all compression strategies. In this case, it has a Compress method that takes a file path as a parameter. 40 | 41 | 2. Concrete Strategies: 42 | `ZipCompressionStrategy`: Implements the `ICompressionStrategy` interface to compress files using ZIP format. It uses GZipStream for compression but in a ZIP format. 43 | `GZipCompressionStrategy`: Implements the `ICompressionStrategy` interface to compress files using GZIP format. It uses GZipStream directly to compress the file. 44 | Each strategy provides its own implementation of the `Compress` method to handle file compression. 45 | 46 | 3. Context: 47 | `FileCompressor` maintains a reference to an `ICompressionStrategy` object and delegates the compression task to this strategy. 48 | Provides the `SetCompressionStrategy` method to allow changing the compression strategy at runtime. 49 | Uses the `CompressFile` method to perform the compression by invoking the strategy's `Compress` method. 50 | 51 | ## Usage 52 | ```csharp 53 | class Program 54 | { 55 | static void Main(string[] args) 56 | { 57 | var fileCompressor = new FileCompressor(); 58 | 59 | // Set ZIP Compression Strategy and compress the file 60 | fileCompressor.SetCompressionStrategy(new ZipCompressionStrategy()); 61 | fileCompressor.CompressFile(@"C:\Temp\example.txt"); 62 | 63 | // Set GZIP Compression Strategy and compress the file 64 | fileCompressor.SetCompressionStrategy(new GZipCompressionStrategy()); 65 | fileCompressor.CompressFile(@"C:\Temp\example.txt"); 66 | } 67 | } 68 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/TemplateMethod/README.md: -------------------------------------------------------------------------------- 1 | # Template Method Design Pattern 2 | The Template Method design pattern defines the skeleton of an algorithm in a base class, allowing subclasses to override specific steps of the algorithm without changing its structure. It's a behavioral pattern often used to encapsulate the invariant parts of an algorithm, while allowing the variable parts to be redefined by subclasses. 3 | 4 | ## Key Concepts of the Template Method 5 | 1. Template Method: 6 | The Template Method is a method in an abstract class that defines the overall structure of an algorithm. It consists of a series of method calls, some of which may be abstract or have default implementations. This method controls the algorithm's sequence of execution. 7 | 8 | 2. Abstract Methods: 9 | Within the Template Method, certain steps are defined as abstract methods. These methods are declared in the abstract class but lack an implementation. Subclasses are required to provide their own implementations for these methods. The purpose is to allow subclasses to define the specific behavior of these steps while preserving the overall algorithm structure. 10 | 11 | 3. Concrete Methods: 12 | The abstract class may also define concrete methods, which provide default implementations for certain steps of the algorithm. These methods can be used as-is by subclasses or can be overridden to provide different behavior. This allows flexibility and reuse of common code. 13 | 14 | 4. Hooks: 15 | A hook is a method in the abstract class that does nothing or provides a default implementation, and subclasses can optionally override it. Hooks provide a way to extend or customize parts of the algorithm without being forced to override every method. 16 | 17 | 5. Invariance vs. Variance: 18 | The Template Method pattern separates the invariant parts of an algorithm (those that remain constant) from the variant parts (those that may change). The invariant parts are implemented in the abstract class, while the variant parts are left to subclasses to implement. 19 | 20 | 6. Subclassing: 21 | Subclasses inherit the Template Method and can customize the behavior of the algorithm by overriding the abstract methods and hooks. This allows for different implementations of the algorithm's steps while maintaining the overall structure. 22 | 23 | 7. Encapsulation of Algorithm: 24 | The pattern encapsulates the algorithm's structure within the abstract class. The subclasses are not concerned with the overall flow but only with implementing or modifying specific steps. This encapsulation makes the code more organized and easier to maintain. 25 | 26 | 8. Non-Overridable Template Method: 27 | The Template Method itself is often marked as final or sealed (depending on the programming language) to prevent subclasses from overriding it. This ensures that the algorithm's structure remains consistent and intact. 28 | 29 | 9. Reusability and Maintainability: 30 | By defining the core algorithm in the abstract class, the Template Method pattern promotes code reuse and reduces duplication. When the algorithm changes, modifications are made in the abstract class, which automatically applies to all subclasses. This enhances maintainability. 31 | 32 | ## Code Explanation 33 | * **Abstract Class FileProcessor**: 34 | This class defines the `ProcessFile` method, which is the Template Method. It outlines the steps of the algorithm: opening the file, reading its content, processing the content, and closing the file. 35 | Some steps, such as `OpenFile` and `CloseFile`, are implemented with a default behavior but can be overridden if needed. 36 | Other steps, `ReadFileContent` and `ProcessContent`, are abstract and must be implemented by subclasses because they depend on the specific file type. 37 | 38 | * **Concrete Class TextFileProcessor**: 39 | Implements file processing for text files. 40 | Overrides `OpenFile`, `ReadFileContent`, `ProcessContent`, and `CloseFile` to handle the specifics of text files. 41 | 42 | * **Concrete Class CsvFileProcessor**: 43 | Implements file processing for CSV files. 44 | Similar to `TextFileProcessor`, but the `ProcessContent` method is designed to handle CSV data, splitting lines by newline characters and columns by commas. 45 | 46 | ## Usage 47 | ```csharp 48 | class Program 49 | { 50 | static void Main(string[] args) 51 | { 52 | // Example usage 53 | FileProcessor textProcessor = new TextFileProcessor(); 54 | textProcessor.ProcessFile("example.txt"); 55 | 56 | Console.WriteLine(); 57 | 58 | FileProcessor csvProcessor = new CsvFileProcessor(); 59 | csvProcessor.ProcessFile("example.csv"); 60 | } 61 | } 62 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Observer/README.md: -------------------------------------------------------------------------------- 1 | # Observer Design Pattern 2 | The Observer design pattern is a behavioral pattern that defines a one-to-many dependency between objects. When one object changes its state, all its dependents (observers) are notified and updated automatically. This pattern is particularly useful for implementing distributed event-handling systems. 3 | 4 | ## Key Concepts of the Observer Pattern 5 | 1. Subject: 6 | Definition: The Subject is the object whose state changes and needs to notify its observers about these changes. 7 | Responsibilities: It maintains a list of observers and provides methods for attaching, detaching, and notifying them. 8 | Interface: The Subject typically defines methods like `Attach()`, `Detach()`, and `Notify()` for managing observers. 9 | 10 | 2. Observer: 11 | Definition: The Observer is an object that depends on the Subject and gets notified of any state changes in the Subject. 12 | Responsibilities: It defines the `Update()` method that gets called by the Subject when there is a change. 13 | Interface: Observers implement a common interface that the Subject can use to notify them of changes. 14 | 15 | 3. Concrete Subject: 16 | Definition: A Concrete Subject is a specific implementation of the Subject interface. 17 | Responsibilities: It maintains the state and notifies all registered observers about state changes. 18 | 19 | 4. Concrete Observer: 20 | Definition: A Concrete Observer is a specific implementation of the Observer interface. 21 | Responsibilities: It performs the necessary actions when notified of a state change by the Subject. 22 | 23 | 5. Dependents Notification: 24 | Notification: The Subject automatically informs all registered Observers when its state changes. This is done through the Notify() method, which iterates over the list of observers and calls their Update() method. 25 | 26 | 6. Decoupling: 27 | Loose Coupling: The Observer pattern promotes loose coupling between the Subject and its Observers. The Subject does not need to know details about the Observers, only that they implement the Observer interface. 28 | Flexibility: New Observers can be added or removed without modifying the Subject, and the Subject does not need to know about specific implementations of Observers. 29 | 30 | 7. Dynamic Updates: 31 | Real-Time Notification: Observers are updated in real time as soon as the Subject’s state changes, making it suitable for scenarios where timely updates are crucial. 32 | Consistency: Ensures that all registered Observers have the most recent state information from the Subject. 33 | 34 | 8. Multiple Observers: 35 | One-to-Many Relationship: The pattern supports having multiple Observers for a single Subject. All Observers are notified of any change, ensuring that all dependent objects are kept in sync with the Subject's state. 36 | 37 | 9. State Management: 38 | Centralized Updates: The Subject is responsible for managing its state and notifying Observers, which simplifies state management and keeps the update mechanism centralized. 39 | 40 | ## Code Explanation 41 | * **Observer Interface**: 42 | `IFileObserver` defines the Update method that will be called when the observed object (subject) changes its state. 43 | Implemented by concrete observers to handle file change notifications. 44 | 45 | * **Concrete Observers**: 46 | `ConsoleLogger` logs file changes to the console. 47 | `EmailNotifier` simulates sending an email notification about file changes. 48 | Both observers implement the Update method from the `IFileObserver` interface. 49 | 50 | * **Subject Interface**: 51 | `IFileSubject` defines methods to register, unregister, and notify observers. 52 | Concrete subjects will implement this interface to manage the observer list and send notifications. 53 | 54 | * **Concrete Subject**: 55 | `FileWatcher` implements the `IFileSubject` interface. 56 | Uses a `FileSystemWatcher` to monitor changes in a specified directory. 57 | Notifies all registered observers about file creation, modification, or deletion events. 58 | 59 | ## Usage 60 | ```csharp 61 | class Program 62 | { 63 | static void Main(string[] args) 64 | { 65 | // Create FileWatcher (Subject) 66 | var fileWatcher = new FileWatcher(); 67 | 68 | // Create Observers 69 | var consoleLogger = new ConsoleLogger(); 70 | var emailNotifier = new EmailNotifier(); 71 | 72 | // Register Observers 73 | fileWatcher.RegisterObserver(consoleLogger); 74 | fileWatcher.RegisterObserver(emailNotifier); 75 | 76 | // Start watching a directory 77 | fileWatcher.StartWatching(@"C:\Temp"); 78 | 79 | // Keep the application running to monitor file changes 80 | Console.WriteLine("Press 'q' to quit."); 81 | while (Console.Read() != 'q') ; 82 | } 83 | } 84 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Interpreter/README.md: -------------------------------------------------------------------------------- 1 | # Interpreter Design Pattern 2 | The Interpreter design pattern is a behavioral pattern that provides a way to evaluate sentences in a language. It is often used to interpret expressions or commands, where you define a grammar and create an interpreter that can parse and execute these expressions. 3 | 4 | ## Key Concepts of the Interpreter Pattern 5 | 1. Abstract Expression: 6 | Definition: An interface or abstract class that defines an Interpret method for interpreting expressions or commands. 7 | Purpose: Provides a common interface for all concrete expressions, allowing them to be used interchangeably. 8 | 9 | 2. Terminal Expression: 10 | Definition: Concrete implementations of the Abstract Expression that interpret specific elements of the language or commands. These expressions typically implement the actual interpretation logic. 11 | Purpose: Represents the fundamental elements or tokens of the language, such as literals or operators. 12 | 13 | 3. Non-terminal Expression: 14 | Definition: Concrete classes that represent composite expressions or constructs. These expressions combine or build on terminal expressions to form more complex expressions. 15 | Purpose: Allows for the composition of multiple expressions to create complex queries or commands. 16 | 17 | 4. Context: 18 | Definition: The object or data structure that contains the information needed for the expressions to interpret. It represents the environment or data being interpreted. 19 | Purpose: Provides the data or state on which the expressions operate. 20 | 21 | 5. Interpreter: 22 | Definition: The process or mechanism that uses the expressions to interpret or evaluate commands. This often involves parsing input, applying the expressions, and returning results. 23 | Purpose: Executes the interpretation logic defined by the expressions to achieve the desired outcome. 24 | 25 | 6. Grammar Definition: 26 | Definition: The set of rules or structure for the language or command syntax being interpreted. It defines how expressions are formed and combined. 27 | Purpose: Provides a structured way to represent and process commands or expressions. 28 | 29 | 7. Flexibility and Extensibility: 30 | Definition: The pattern allows for the addition of new expressions or commands without altering existing code. 31 | Purpose: Supports the Open/Closed Principle by enabling extensions through new expressions rather than modifying existing ones. 32 | 33 | 8. Separation of Concerns: 34 | Definition: The pattern separates the logic for interpreting commands from the data being interpreted. 35 | Purpose: Enhances modularity and maintainability by keeping the interpretation logic distinct from the data structure or context. 36 | 37 | ## Code Explanation 38 | * **Abstract Expression**: 39 | `IExpression` interface that declares a method `Interpret(File file)` for interpreting a file based on some criteria. 40 | Provides a common interface for all concrete expressions. 41 | 42 | * **Terminal Expressions**: 43 | `FilenameFilter`: A terminal expression that checks if a file name contains a specific substring. 44 | - Constructor: Takes the filename substring to search for. 45 | - Interpret Method: Checks if the file name contains the substring. 46 | 47 | * **ExtensionFilter**: 48 | `ExtensionFilter`: A terminal expression that checks if a file has a specific extension. 49 | - Constructor: Takes the file extension to search for. 50 | - Interpret Method: Checks if the file extension matches the given extension. 51 | 52 | * **Context**: 53 | `File` represents a file with a name and extension. 54 | The object that is interpreted by the expressions. It holds the data that the expressions operate on. 55 | 56 | ## Usage 57 | ```csharp 58 | class Program 59 | { 60 | static void Main(string[] args) 61 | { 62 | // Create a list of files 63 | var files = new List 64 | { 65 | new File("document1.txt", "txt"), 66 | new File("presentation.pptx", "pptx"), 67 | new File("notes.docx", "docx"), 68 | new File("image.png", "png") 69 | }; 70 | 71 | // Define expressions to filter files 72 | IExpression filenameFilter = new FilenameFilter("doc"); 73 | IExpression extensionFilter = new ExtensionFilter("png"); 74 | 75 | // Apply filters to the list of files 76 | Console.WriteLine("Files containing 'doc' in their name:"); 77 | foreach (var file in files.Where(f => filenameFilter.Interpret(f))) 78 | { 79 | Console.WriteLine($"- {file.Name}"); 80 | } 81 | 82 | Console.WriteLine("\nFiles with '.png' extension:"); 83 | foreach (var file in files.Where(f => extensionFilter.Interpret(f))) 84 | { 85 | Console.WriteLine($"- {file.Name}"); 86 | } 87 | } 88 | } 89 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/ChainOfResponsibility/README.md: -------------------------------------------------------------------------------- 1 | # Chain of Responsibility Design Pattern 2 | The Chain of Responsibility design pattern is a behavioral pattern that allows an object to pass a request along a chain of handlers. Each handler in the chain either processes the request or passes it to the next handler in the chain. This pattern is useful for scenarios where multiple objects might handle a request, but the specific handler isn't known beforehand. 3 | 4 | ## Key Concepts of the Chain of Responsibility Pattern 5 | 1. Handler: 6 | Definition: An abstract class or interface that declares a method for handling requests and a reference to the next handler in the chain. 7 | Purpose: Defines a common interface for all concrete handlers and establishes the link to the next handler in the chain. 8 | 9 | 2. Concrete Handler: 10 | Definition: Implements the Handler interface and provides the actual processing logic for the request. Each concrete handler handles specific types of requests or parts of the request. 11 | Purpose: Contains the logic to handle a request if applicable; otherwise, it passes the request to the next handler in the chain. 12 | 13 | 3. Context: 14 | Definition: The data or information that is passed through the chain of handlers. This is often represented as a request object that contains details necessary for processing. 15 | Purpose: Provides the data that handlers use to process the request and make decisions. 16 | 17 | 4. Chain: 18 | Definition: The sequence of handlers connected in a specific order. Each handler processes the request and either handles it or passes it to the next handler in the chain. 19 | Purpose: Provides a structured flow through which requests are passed and processed. 20 | 21 | 5. Decoupling: 22 | Definition: The pattern decouples the sender of a request from its receivers, allowing for flexible and dynamic request handling. 23 | Purpose: Reduces dependencies between the client and the concrete handlers, allowing for changes in the chain structure without affecting client code. 24 | 25 | 6. Flexibility: 26 | Definition: The pattern allows for the dynamic configuration of the chain of handlers at runtime. 27 | Purpose: Enables the modification of the chain (e.g., adding, removing, or reordering handlers) without altering existing code. 28 | 29 | 7. Single Responsibility: 30 | Definition: Each handler in the chain is responsible for a specific type of processing or decision-making. 31 | Purpose: Ensures that each handler focuses on a single responsibility, adhering to the Single Responsibility Principle. 32 | 33 | 8. Responsibility Delegation: 34 | Definition: The pattern allows for the delegation of request handling to appropriate handlers based on the request type or conditions. 35 | Purpose: Distributes the handling of requests among multiple handlers, ensuring that each request is processed in a manner suited to its needs. 36 | 37 | ## Code Explanation 38 | * **Abstract Handler**: 39 | Definition: `FileOperationHandler` defines an interface for handling requests and maintaining a reference to the next handler in the chain. 40 | Purpose: Provides the base class for concrete handlers and sets up the chain of responsibility. 41 | 42 | * **Concrete Handlers**: 43 | - LoggingHandler: 44 | - Purpose: Logs file operations. 45 | - `HandleRequest` Method: Logs the operation and then passes the request to the next handler. 46 | - AuthorizationHandler: 47 | - Purpose: Checks if the operation is authorized. 48 | - `HandleRequest` Method: Checks if authorization is granted; if not, it denies the operation or passes it to the next handler. 49 | - ValidationHandler: 50 | - Purpose: Validates the file operation. 51 | - `HandleRequest` Method: Validates the operation and then passes the request to the next handler. 52 | 53 | * **Setting Up the Chain**: 54 | `SetNext` Method: Used to link handlers in the desired order. For instance, the logging handler is followed by the authorization handler, which is then followed by the validation handler. 55 | 56 | ## Usage 57 | ```csharp 58 | class Program 59 | { 60 | static void Main(string[] args) 61 | { 62 | // Create handlers 63 | var loggingHandler = new LoggingHandler(); 64 | var authorizationHandler = new AuthorizationHandler(); 65 | var validationHandler = new ValidationHandler(); 66 | 67 | // Set up the chain of responsibility 68 | loggingHandler.SetNext(authorizationHandler); 69 | authorizationHandler.SetNext(validationHandler); 70 | 71 | // Client requests 72 | Console.WriteLine("Processing 'read' operation:"); 73 | loggingHandler.HandleRequest("read", "document.txt"); 74 | 75 | Console.WriteLine("\nProcessing 'delete' operation:"); 76 | loggingHandler.HandleRequest("delete", "document.txt"); 77 | } 78 | } 79 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Memento/README.md: -------------------------------------------------------------------------------- 1 | # Memento Design Pattern 2 | The Memento design pattern is a behavioral pattern that allows capturing and externalizing an object's internal state without violating its encapsulation. The object can be restored to this state later. This pattern is particularly useful in scenarios where you need to implement undo/redo functionality. 3 | 4 | ## Key Concepts of the Memento Pattern 5 | 1. Memento: 6 | Definition: The Memento is an object that stores the internal state of another object (the Originator) without exposing its internal structure. 7 | Purpose: It acts as a snapshot of the state of the Originator at a specific point in time, allowing the state to be restored later. 8 | Immutability: Typically, the Memento is immutable to ensure that the state cannot be altered after it has been saved. 9 | 10 | 2. Originator: 11 | Definition: The Originator is the object whose state needs to be saved and restored. 12 | Responsibilities: It is responsible for creating a Memento that captures its current state and for restoring its state from a Memento. 13 | State Management: The Originator manages its internal state and provides methods for saving and restoring it. 14 | 15 | 2. Caretaker: 16 | Definition: The Caretaker is responsible for managing and storing Mementos. 17 | Responsibilities: It keeps track of multiple Mementos, often using a stack or other data structure, to facilitate undo/redo functionality. 18 | Limitation: The Caretaker does not modify or directly interact with the contents of the Memento; it only stores and retrieves them. 19 | 20 | 3. Encapsulation: 21 | State Preservation: The Memento pattern allows the internal state of the Originator to be preserved without exposing its internal details. 22 | Decoupling: It decouples the internal state management of the Originator from the operations that modify or restore the state. 23 | 24 | 4. Undo/Redo Functionality: 25 | State History: The pattern enables tracking of state changes over time, making it possible to revert to previous states or reapply undone states. 26 | Command History: Often used in conjunction with a history or command stack to manage multiple state changes and transitions. 27 | 28 | 5. Snapshot Management: 29 | State Capture: The Memento pattern captures the state of the Originator at a specific moment, allowing for precise control over state transitions. 30 | State Restoration: The pattern supports restoring the state to any previously saved snapshot, facilitating state recovery or rollback. 31 | 32 | 6. Complex State Handling: 33 | Complex Objects: The pattern is useful for managing complex objects with intricate states that need to be saved and restored independently of their internal structure. 34 | State Integrity: It ensures that the integrity of the state is maintained and not exposed to other parts of the system. 35 | 36 | ## Code Explanation 37 | * **Memento**: 38 | `FileMemento` class stores the internal state of the `FileEditor`. In this case, it stores the content of the file. 39 | The memento is immutable once created, ensuring that the saved state cannot be altered after creation. 40 | 41 | * **Originator**: 42 | `FileEditor` is the object whose state we want to save and restore. It contains a method Write to change the content of the file. 43 | It has a `Save` method that creates a new `FileMemento` containing the current state and a `Restore` method that restores the state from a memento. 44 | 45 | * **Caretaker**: 46 | `FileHistory` class manages the mementos. It keeps a stack of mementos for undo and redo operations. 47 | `Save` method saves the current state of the file by pushing a new memento onto the undo stack. 48 | `Undo` method pops the latest memento from the undo stack and uses it to restore the file's state. It also pushes the current state onto the redo stack. 49 | `Redo` method restores the state from the redo stack if an undo has been performed. 50 | 51 | ## Usage 52 | ```csharp 53 | class Program 54 | { 55 | static void Main(string[] args) 56 | { 57 | // Create an instance of the FileEditor 58 | var fileEditor = new FileEditor(); 59 | 60 | // Create an instance of FileHistory (the Caretaker) 61 | var fileHistory = new FileHistory(fileEditor); 62 | 63 | // Perform some operations 64 | fileEditor.Write("Version 1"); 65 | fileHistory.Save(); 66 | 67 | fileEditor.Write("Version 2"); 68 | fileHistory.Save(); 69 | 70 | fileEditor.Write("Version 3"); 71 | fileHistory.Save(); 72 | 73 | // Undo operations 74 | fileHistory.Undo(); // Output: Restored file content to: Version 2 75 | fileHistory.Undo(); // Output: Restored file content to: Version 1 76 | 77 | // Redo operation 78 | fileHistory.Redo(); // Output: Restored file content to: Version 2 79 | } 80 | } 81 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/State/README.md: -------------------------------------------------------------------------------- 1 | # State Design Pattern 2 | The State design pattern is a behavioral pattern that allows an object to alter its behavior when its internal state changes. It appears as if the object changed its class. This pattern is useful when an object needs to change its behavior based on its state, and it can help in managing state-specific behavior in a cleaner and more organized way. 3 | 4 | ## Key Concepts of the State Pattern 5 | 1. Context: 6 | Definition: The class that maintains a reference to an instance of a State subclass. It is responsible for managing the current state and delegating requests to the current state object. 7 | Purpose: Provides a way to interact with the state and allows state transitions. 8 | 9 | 2. State Interface (or Abstract State): 10 | Definition: An interface or abstract class that declares methods for handling state-specific behavior. These methods will be implemented by concrete state classes. 11 | Purpose: Defines a common interface for all concrete states and ensures that each state can handle requests in a way that is appropriate for that state. 12 | 13 | 3. Concrete States: 14 | Definition: Classes that implement the State interface and define the behavior specific to each state. Each concrete state represents a particular state of the context and contains the logic for handling requests in that state. 15 | Purpose: Encapsulates state-specific behavior and manages transitions between states. 16 | 17 | 4. State Transition: 18 | Definition: The mechanism for changing the state of the context from one state to another. This typically involves updating the context’s state reference to a new instance of a state class. 19 | Purpose: Allows the context to change its behavior dynamically based on its current state. 20 | 21 | 5. Encapsulation of State-Specific Behavior: 22 | Definition: Each state encapsulates the behavior associated with that state, avoiding the need for large conditional statements in the context class. 23 | Purpose: Enhances code organization and maintainability by separating state-specific logic into distinct classes. 24 | 25 | 6. Dynamic Behavior Change: 26 | Definition: The pattern allows an object to change its behavior at runtime by switching between states. 27 | Purpose: Enables the object to adapt its behavior based on its current state without requiring modifications to the core logic. 28 | 29 | 7. Simplified Context Class: 30 | Definition: The context class is simplified as it delegates state-specific behavior to the state objects, thus reducing the complexity of handling multiple states within the context itself. 31 | Purpose: Keeps the context class clean and focused on managing state transitions rather than implementing all state-specific logic. 32 | 33 | 8. State-Specific Logic: 34 | Definition: Each state class implements behavior relevant to its particular state, leading to a clear and modular design. 35 | Purpose: Ensures that behavior changes in a controlled manner, and new states can be added with minimal impact on existing code. 36 | 37 | ## Code Explanation 38 | * **State Interface**: 39 | Definition: `IFileState` interface define the methods that concrete states will implement. 40 | Purpose: Declares the state-specific behaviors for opening, closing, and editing a file. 41 | 42 | * **Concrete States**: 43 | - CreatedState: 44 | - Purpose: Represents the initial state when the file is created but not yet opened. 45 | - Behavior: Can transition to the OpenedState when the file is opened. Cannot close or edit. 46 | - OpenedState: 47 | - Purpose: Represents the state when the file is open and can be edited. 48 | - Behavior: Allows the file to be edited and closed. Can transition to ClosedState when closed. 49 | - ClosedState: 50 | - Purpose: Represents the state when the file is closed. 51 | - Behavior: Allows the file to be reopened. Cannot be edited while closed. 52 | 53 | * **Context**: 54 | Definition: `FileContext` maintains a reference to the current state and delegates state-specific behavior to the current state object. 55 | Purpose: Manages the current state and provides methods to interact with the file, delegating behavior to the state object. 56 | 57 | * **Client Code**: 58 | Creates: An instance of `FileContext` and invokes methods that transition between states and perform actions based on the current state. 59 | 60 | ## Usage 61 | ```csharp 62 | class Program 63 | { 64 | static void Main(string[] args) 65 | { 66 | var file = new FileContext(); 67 | 68 | // File is in Created state 69 | file.Open(); // Transitions to Opened state 70 | file.Edit(); // Operates in Opened state 71 | file.Close(); // Transitions to Closed state 72 | 73 | // File is in Closed state 74 | file.Open(); // Transitions back to Opened state 75 | file.Edit(); // Operates in Opened state 76 | } 77 | } 78 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Mediator/README.md: -------------------------------------------------------------------------------- 1 | # Mediator Design Pattern 2 | The Mediator design pattern is a behavioral pattern that helps reduce the direct dependencies between objects by introducing a mediator that facilitates communication between them. In the context of file operations within an operating system, a mediator could be used to manage interactions between different components, such as a file manager, file operations, and the user interface. 3 | 4 | ## Key Concepts of the Mediator Pattern 5 | 1. Mediator Interface: 6 | The mediator interface defines the contract for communication between the different components (colleagues) that interact with each other. 7 | It usually contains methods that facilitate the communication and coordination between the colleagues. 8 | 9 | 2. Concrete Mediator: 10 | The concrete mediator implements the mediator interface and coordinates communication among colleagues. 11 | It contains references to all the colleague objects and handles the communication logic, so the colleagues don’t interact with each other directly. 12 | It centralizes the control logic, simplifying the system by reducing the direct dependencies between colleagues. 13 | 14 | 3. Colleague Objects: 15 | These are the components or objects that communicate with each other through the mediator. 16 | Each colleague is aware of the mediator but does not need to know about the other colleagues directly. 17 | They communicate by calling methods on the mediator, which then forwards the requests to the appropriate colleague. 18 | 19 | 4. Decoupling: 20 | The primary purpose of the mediator pattern is to reduce the tight coupling between colleague objects by abstracting their communication through a mediator. 21 | Colleagues no longer need to know about each other's existence, which makes the system easier to maintain and extend. 22 | 23 | 5. Centralized Control: 24 | The mediator pattern centralizes the control of communication between objects into a single mediator class, which can lead to more manageable and understandable interactions in complex systems. 25 | However, it may also lead to the mediator becoming too complex, as it might need to handle many different types of interactions. 26 | 27 | 6. Flexibility and Extensibility: 28 | Since the communication logic is encapsulated in the mediator, it’s easier to modify or extend the system. You can add new colleagues or modify existing ones without altering the code for other colleagues. 29 | This flexibility makes the mediator pattern suitable for systems where the interaction between components might change over time. 30 | 31 | 6. Reduced Direct Dependencies: 32 | By reducing the direct dependencies between colleague objects, the mediator pattern helps in creating more modular and testable code. 33 | Each colleague object can be developed, tested, and maintained independently, with the mediator coordinating their interactions. 34 | 35 | ## Code Explanation 36 | * **Mediator Interface**: 37 | `IFileManager` interface defines the methods for interacting with different components: creating, opening, deleting files, and notifying about events. 38 | 39 | * **Concrete Mediator**: 40 | `FileManager` coordinates the communication between the `FileExplorer`, `FileOperationHandler`, and `Logger`. It ensures that these components do not need to reference each other directly. 41 | It has methods like `CreateFile`, `OpenFile`, and `DeleteFile`, which delegate the work to the `FileOperationHandler`. 42 | 43 | * **Colleagues**: 44 | `FileExplorer`: Represents the user interface or the component that interacts with the user. It selects files and invokes operations like creating, opening, or deleting them. 45 | `FileOperationHandler`: Performs the actual file operations such as creating, opening, and deleting files. 46 | `Logger`: Logs actions performed in the system, like file creation or deletion. 47 | 48 | ## Usage 49 | 50 | ```csharp 51 | class Program 52 | { 53 | static void Main(string[] args) 54 | { 55 | // Create Colleagues 56 | var fileExplorer = new FileExplorer(); 57 | var fileOperationHandler = new FileOperationHandler(); 58 | var logger = new Logger(); 59 | 60 | // Create Mediator 61 | var fileManager = new FileManager(fileExplorer, fileOperationHandler, logger); 62 | 63 | // Client interacts with FileExplorer 64 | fileExplorer.SelectFile("example.txt"); 65 | fileExplorer.CreateFile(); // Output: Creating file: example.txt 66 | // Output: [LOG]: File created: example.txt 67 | 68 | fileExplorer.OpenFile(); // Output: Opening file: example.txt 69 | // Output: [LOG]: File opened: example.txt 70 | 71 | fileExplorer.DeleteFile(); // Output: Deleting file: example.txt 72 | // Output: [LOG]: File deleted: example.txt 73 | } 74 | } 75 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Iterator/README.md: -------------------------------------------------------------------------------- 1 | # Iterator Design Pattern 2 | The Iterator design pattern is a behavioral pattern that provides a way to access the elements of a collection sequentially without exposing the underlying representation of the collection. It allows for traversal of complex data structures, like lists or trees, in a uniform way. 3 | 4 | ## Key Concepts of the Iterator Pattern 5 | 1. Iterator Interface: 6 | Definition: An interface that defines methods for accessing elements of a collection sequentially. Common methods include HasNext() to check if there are more elements, and Next() to retrieve the next element. 7 | Purpose: Provides a standard way to traverse the elements of a collection without needing to understand the internal structure of the collection. 8 | 9 | 2. Concrete Iterator: 10 | Definition: A class that implements the Iterator interface and maintains the current position within the collection. 11 | Purpose: Implements the traversal logic for the collection, keeping track of the current state and ensuring correct sequential access. 12 | 13 | 3. Aggregate Interface: 14 | Definition: An interface or abstract class that declares a method for creating an iterator object. This is often named CreateIterator(). 15 | Purpose: Provides a way to obtain an iterator for the collection, allowing clients to traverse the collection through the iterator. 16 | 17 | 4. Concrete Aggregate: 18 | Definition: A class that implements the Aggregate interface and contains the collection of elements. It also provides the implementation of the method to create an iterator. 19 | Purpose: Represents the collection of elements and supports creation of an iterator that can traverse its elements. 20 | 21 | 5. Element: 22 | Definition: The objects that are contained within the collection and are accessed by the iterator. 23 | Purpose: Represents the items that are iterated over. In the context of the Iterator pattern, these objects are accessed sequentially. 24 | 25 | 6. Encapsulation of Traversal Logic: 26 | Definition: The Iterator pattern encapsulates the traversal logic inside the iterator object, separating it from the collection. 27 | Purpose: Ensures that the collection can focus on managing its elements, while the iterator handles the traversal details. 28 | 29 | 7. Uniform Access: 30 | Definition: Provides a consistent way to access elements regardless of the underlying data structure. 31 | Purpose: Allows different types of collections (like lists, trees, or graphs) to be traversed using the same iterator interface, promoting code reuse and consistency. 32 | 33 | 8. Separation of Concerns: 34 | Definition: Separates the responsibility of iterating over the elements from the collection itself. 35 | Purpose: Makes it easier to modify or extend the collection or iteration logic independently. For example, you can add new types of collections or iterators without changing the existing code. 36 | 37 | 9. Flexibility and Extensibility: 38 | Definition: Allows for the easy addition of new types of collections or traversal strategies by creating new iterator implementations. 39 | Purpose: Supports the Open/Closed Principle, making the system easier to extend with new functionality without modifying existing code. 40 | 41 | ## Code Explanation 42 | * **Iterator Interface**: 43 | Definition: `IIterator` defines the methods `HasNext()` and `Next()` for iterating over a collection. 44 | Purpose: Provides a standard way to traverse elements in the collection. 45 | 46 | * **Aggregate Interface**: 47 | Definition: `IFileSystemCollection` declares a method `CreateIterator()` that returns an iterator for the collection. 48 | Purpose: Allows the creation of an iterator for traversing the elements. 49 | 50 | * **Element Interface**: 51 | Definition: `IFileSystemElement` defines the properties and methods common to all elements in the file system. 52 | Purpose: Ensures that all elements (files and directories) can be treated uniformly. 53 | 54 | * **Concrete Elements**: 55 | `File`: Represents a file with a name and implements the `IFileSystemElement` interface. 56 | `Directory`: Represents a directory that can contain files and subdirectories. It implements both `IFileSystemElement` and `IFileSystemCollection` interfaces. 57 | `AddElement` Method: Adds elements (files or subdirectories) to the directory. 58 | `CreateIterator` Method: Returns an iterator for traversing the directory’s elements. 59 | 60 | * **Concrete Iterator**: 61 | `FileSystemIterator` implements the `IIterator` interface and provides methods to traverse the collection. 62 | Purpose: Handles the actual iteration logic for a list of file system elements. 63 | 64 | ## Usage 65 | ```csharp 66 | class Program 67 | { 68 | static void Main(string[] args) 69 | { 70 | // Create file system structure 71 | var file1 = new File("file1.txt"); 72 | var file2 = new File("file2.txt"); 73 | var subdir = new Directory("subdir"); 74 | subdir.AddElement(file2); 75 | 76 | var rootDir = new Directory("root"); 77 | rootDir.AddElement(file1); 78 | rootDir.AddElement(subdir); 79 | 80 | // Use iterator to traverse the file system 81 | var iterator = rootDir.CreateIterator(); 82 | while (iterator.HasNext()) 83 | { 84 | var element = iterator.Next(); 85 | element.PrintDetails(); 86 | } 87 | } 88 | } 89 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Command/README.md: -------------------------------------------------------------------------------- 1 | # Command Design Pattern 2 | The Command design pattern is a behavioral design pattern in which an object is used to encapsulate all the information needed to perform an action or trigger an event at a later time. This pattern allows for the separation of concerns, making it easier to handle, queue, and log operations. 3 | 4 | ## Key Concepts of the Command Pattern 5 | 1. Command Interface: 6 | The command interface declares a method for executing the command. Typically, this is named `Execute()` or similar. 7 | This interface might also include an `Undo()` method to allow reversing the operation if needed. 8 | 9 | 2. Concrete Command: 10 | A concrete command class implements the command interface and defines the binding between an action and a receiver. 11 | It holds a reference to the receiver object, which performs the action when the command’s `Execute()` method is called. 12 | This class can also implement an `Undo()` method to reverse the operation. 13 | 14 | 3. Receiver: 15 | The receiver is the object that performs the actual work when the command is executed. 16 | It contains the business logic necessary to carry out the request. 17 | The receiver doesn’t know anything about the command interface, only how to perform the requested action. 18 | 19 | 4. Invoker: 20 | The invoker is responsible for initiating requests or commands. It holds a reference to the command object and triggers its `Execute()` method. 21 | The invoker doesn’t know the details of how the request will be handled, only that it will be executed when needed. 22 | 23 | 5. Client: 24 | The client is responsible for creating command objects and configuring them with the appropriate receiver. 25 | The client decides which command to execute and passes it to the invoker. 26 | 27 | 6. Decoupling of Sender and Receiver: 28 | The Command pattern decouples the object that invokes the operation (invoker) from the one that knows how to perform it (receiver). 29 | This allows for greater flexibility, as commands can be passed around, queued, or stored without needing to know anything about the implementation details. 30 | 31 | 7. Support for Undo/Redo: 32 | By encapsulating operations in objects, the Command pattern naturally supports undo/redo functionality. 33 | Each command can store state information that allows it to reverse the operation if needed, which is useful in scenarios like text editors or transaction systems. 34 | 35 | 8. Command History and Queuing: 36 | Commands can be stored in a history list or queue, allowing for deferred execution, batch processing, or replaying a sequence of commands. 37 | This is particularly useful in scenarios where you need to maintain a log of operations or execute commands later. 38 | 39 | 9. Extensibility: 40 | The Command pattern makes it easy to add new commands without altering existing classes. 41 | New commands can be created by simply implementing the command interface and defining the `Execute()` method, without needing to modify the invoker or receiver. 42 | 43 | 10. Macro Commands: 44 | The Command pattern supports macro commands, which are commands that execute a sequence of other commands. 45 | This allows grouping multiple operations into a single command, which can then be executed or undone as a single unit. 46 | 47 | ## Code Explanation 48 | * **Command Interface**: 49 | `ICommand` interface defines the Execute and Undo methods, which concrete command classes will implement. 50 | 51 | * **Receiver**: 52 | `FileSystemReceiver` class simulates the file system in an operating system. It provides methods like `CreateFile`, `WriteFile`, and `DeleteFile` to perform actual operations. 53 | 54 | * **Concrete Command Classes**: 55 | - `CreateFileCommand`: Encapsulates the action of creating a file. 56 | - `WriteFileCommand`: Encapsulates the action of writing content to a file. 57 | - `DeleteFileCommand`: Encapsulates the action of deleting a file. 58 | 59 | Each of these classes contains a reference to the `FileSystemReceiver` and uses it to perform the specific operation when Execute is called. They also implement Undo to reverse the operation. 60 | 61 | * **Invoker**: 62 | `FileInvoker` class is responsible for executing the command. It holds a reference to a `ICommand` object and calls its Execute and Undo methods. 63 | 64 | ## Usage 65 | ```csharp 66 | class Program 67 | { 68 | static void Main(string[] args) 69 | { 70 | // Receiver 71 | var fileSystem = new FileSystemReceiver(); 72 | 73 | // Commands 74 | var createCommand = new CreateFileCommand(fileSystem, "example.txt"); 75 | var writeCommand = new WriteFileCommand(fileSystem, "example.txt", "Hello, World!"); 76 | var deleteCommand = new DeleteFileCommand(fileSystem, "example.txt"); 77 | 78 | // Invoker 79 | var fileInvoker = new FileInvoker(createCommand); 80 | fileInvoker.Execute(); // Output: Creating file: example.txt 81 | fileInvoker.Undo(); // Output: Deleting file: example.txt 82 | 83 | fileInvoker = new FileInvoker(writeCommand); 84 | fileInvoker.Execute(); // Output: Writing to file: example.txt 85 | // Content: Hello, World! 86 | fileInvoker.Undo(); // Output: Undoing write to file: example.txt 87 | 88 | fileInvoker = new FileInvoker(deleteCommand); 89 | fileInvoker.Execute(); // Output: Deleting file: example.txt 90 | fileInvoker.Undo(); // Output: Undoing delete: Recreating file example.txt 91 | } 92 | } 93 | ``` -------------------------------------------------------------------------------- /src/DotnetDesignPatterns/Behavioral/Visitor/README.md: -------------------------------------------------------------------------------- 1 | # Visitor Design Pattern 2 | The Visitor design pattern is a behavioral pattern that allows you to add further operations to objects without modifying their classes. It separates the algorithm from the object structure it operates on, making it easy to add new operations without altering the object structures. 3 | 4 | ## Key Concepts of the Visitor Pattern 5 | 1. Visitor Interface: 6 | Definition: The Visitor interface declares a set of visiting methods, one for each type of element in the object structure. 7 | Purpose: Allows the implementation of operations that can be applied to elements of different types in the object structure. Each method in the interface corresponds to a particular type of element. 8 | Example: In a file system, `IFileSystemVisitor` might define methods like `Visit(File file)` and `Visit(Directory directory)`. 9 | 10 | 2. Concrete Visitor: 11 | Definition: A class that implements the Visitor interface and provides concrete implementations of the visiting methods. 12 | Purpose: Encapsulates the behavior or operation that you want to apply to elements of the object structure. Each visitor class represents a different operation. 13 | Example: `SizeCalculationVisitor` and `FileListingVisitor` can be concrete visitors that implement operations like calculating the total size of files or listing files in a directory. 14 | 15 | 3. Element Interface: 16 | Definition: An interface or abstract class that defines an Accept method. This method takes a visitor as an argument. 17 | Purpose: Allows the element to "accept" a visitor, which means that the element will delegate the operation to the visitor. 18 | Example: `IFileSystemElement` with an `Accept(IFileSystemVisitor visitor)` method. 19 | 20 | 4. Concrete Elements: 21 | Definition: Classes that implement the `Element` interface and represent the objects in the structure on which operations will be performed. 22 | Purpose: These are the objects that can be visited by visitors. They implement the Accept method to delegate the operation to the appropriate visitor method. 23 | Example: `File` and `Directory` are concrete elements in a file system. 24 | 25 | 5. Double Dispatch: 26 | Definition: A key feature of the Visitor pattern that allows a method call to be dispatched to different methods based on both the type of the visitor and the type of the element being visited. 27 | Purpose: Enables the correct operation to be applied depending on both the element and the visitor, without needing to use if or switch statements. 28 | Example: When a `File` object calls `visitor.Visit(this)`, the call is dispatched to the `Visit(File file)` method on the visitor, ensuring the correct operation is performed. 29 | 30 | 6. Separation of Algorithms and Object Structure: 31 | Definition: The Visitor pattern separates the algorithms from the object structure on which they operate, making the object structure easier to maintain and extend. 32 | Purpose: Enhances modularity by allowing new operations to be added without modifying the objects themselves. 33 | Example: You can add new operations to the file system by creating new visitors without changing the `File` or `Directory` classes. 34 | 35 | 7. Extensibility: 36 | Definition: New operations can be added easily by creating new visitor classes, without altering the existing element classes. 37 | Purpose: Supports the Open/Closed Principle, allowing the system to be extended with new behaviors without modifying the existing code. 38 | Example: Adding a `FileSearchVisitor` to search for files by name or extension in the file system. 39 | 40 | 8. Element Structure Complexity: 41 | Definition: The Visitor pattern is well-suited for complex object structures, particularly when the structure is relatively stable and the operations on the structure may change or need to be extended. 42 | Purpose: Simplifies the addition of operations in complex structures by avoiding the need to modify element classes whenever a new operation is required. 43 | 44 | 9. Visitor Encapsulation: 45 | Definition: Visitors encapsulate the logic that operates on the elements, which keeps the element classes lightweight and focused on their core responsibilities. 46 | Purpose: Reduces the burden on element classes and promotes a cleaner, more maintainable design. 47 | Example: The `File` and `Directory` classes do not need to know how to calculate sizes or list files; these behaviors are handled by the visitors. 48 | 49 | ## Code Explanation 50 | * **Visitor Interface**: 51 | Interface `IFileSystemVisitor` defines the operations that can be performed on different elements of the file system. 52 | Methods `Visit(File file)` and `Visit(Directory directory)` are implemented by concrete visitors to perform operations specific to files and directories. 53 | 54 | * **Concrete Visitors**: 55 | `SizeCalculationVisitor`: Calculates the total size of all files in the file system. 56 | `FileListingVisitor`: Lists all files and directories in the file system. 57 | 58 | * **Element Interface**: 59 | Interface `IFileSystemElement` defines an Accept method that takes a visitor as an argument. 60 | This method allows an element (file or directory) to accept a visitor and lets the visitor perform its operation on the element. 61 | 62 | * **Concrete Elements**: 63 | `File`: Represents a file in the file system, storing its name and size. Implements the Accept method to allow visitors to operate on it. 64 | `Directory`: Represents a directory, which can contain multiple files and subdirectories. It also implements the Accept method and iterates through its elements to apply the visitor operation. 65 | 66 | ## Usage 67 | ```csharp 68 | class Program 69 | { 70 | static void Main(string[] args) 71 | { 72 | // Create file system structure 73 | var file1 = new File("file1.txt", 1200); 74 | var file2 = new File("file2.txt", 2500); 75 | var subdir = new Directory("subdir"); 76 | subdir.AddElement(file2); 77 | 78 | var rootDir = new Directory("root"); 79 | rootDir.AddElement(file1); 80 | rootDir.AddElement(subdir); 81 | 82 | // Calculate total size using Visitor 83 | var sizeVisitor = new SizeCalculationVisitor(); 84 | rootDir.Accept(sizeVisitor); 85 | Console.WriteLine($"Total size: {sizeVisitor.TotalSize} bytes"); 86 | 87 | // List all files and directories using Visitor 88 | var listingVisitor = new FileListingVisitor(); 89 | rootDir.Accept(listingVisitor); 90 | } 91 | } 92 | ``` -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.tlog 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 298 | *.vbp 299 | 300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 301 | *.dsw 302 | *.dsp 303 | 304 | # Visual Studio 6 technical files 305 | *.ncb 306 | *.aps 307 | 308 | # Visual Studio LightSwitch build output 309 | **/*.HTMLClient/GeneratedArtifacts 310 | **/*.DesktopClient/GeneratedArtifacts 311 | **/*.DesktopClient/ModelManifest.xml 312 | **/*.Server/GeneratedArtifacts 313 | **/*.Server/ModelManifest.xml 314 | _Pvt_Extensions 315 | 316 | # Paket dependency manager 317 | .paket/paket.exe 318 | paket-files/ 319 | 320 | # FAKE - F# Make 321 | .fake/ 322 | 323 | # CodeRush personal settings 324 | .cr/personal 325 | 326 | # Python Tools for Visual Studio (PTVS) 327 | __pycache__/ 328 | *.pyc 329 | 330 | # Cake - Uncomment if you are using it 331 | # tools/** 332 | # !tools/packages.config 333 | 334 | # Tabs Studio 335 | *.tss 336 | 337 | # Telerik's JustMock configuration file 338 | *.jmconfig 339 | 340 | # BizTalk build output 341 | *.btp.cs 342 | *.btm.cs 343 | *.odx.cs 344 | *.xsd.cs 345 | 346 | # OpenCover UI analysis results 347 | OpenCover/ 348 | 349 | # Azure Stream Analytics local run output 350 | ASALocalRun/ 351 | 352 | # MSBuild Binary and Structured Log 353 | *.binlog 354 | 355 | # NVidia Nsight GPU debugger configuration file 356 | *.nvuser 357 | 358 | # MFractors (Xamarin productivity tool) working folder 359 | .mfractor/ 360 | 361 | # Local History for Visual Studio 362 | .localhistory/ 363 | 364 | # Visual Studio History (VSHistory) files 365 | .vshistory/ 366 | 367 | # BeatPulse healthcheck temp database 368 | healthchecksdb 369 | 370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 371 | MigrationBackup/ 372 | 373 | # Ionide (cross platform F# VS Code tools) working folder 374 | .ionide/ 375 | 376 | # Fody - auto-generated XML schema 377 | FodyWeavers.xsd 378 | 379 | # VS Code files for those working on multiple tools 380 | .vscode/* 381 | !.vscode/settings.json 382 | !.vscode/tasks.json 383 | !.vscode/launch.json 384 | !.vscode/extensions.json 385 | *.code-workspace 386 | 387 | # Local History for Visual Studio Code 388 | .history/ 389 | 390 | # Windows Installer files from build outputs 391 | *.cab 392 | *.msi 393 | *.msix 394 | *.msm 395 | *.msp 396 | 397 | # JetBrains Rider 398 | *.sln.iml 399 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Design Patterns Implemented in .NET C# 2 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 3 | [![issues - dotnet-design-patterns](https://img.shields.io/github/issues/engineering87/dotnet-design-patterns)](https://github.com/engineering87/dotnet-design-patterns/issues) 4 | [![Language - C#](https://img.shields.io/static/v1?label=Language&message=C%23&color=blueviolet)](https://dotnet.microsoft.com/it-it/languages/csharp) 5 | [![stars - dotnet-design-patterns](https://img.shields.io/github/stars/engineering87/dotnet-design-patterns?style=social)](https://github.com/engineering87/dotnet-design-patterns) 6 | 7 | This repository showcases .NET C# Design Patterns. The patterns can be browsed by their high-level descriptions or by looking at their source code. Each design pattern category has its own formal description and each pattern is represented with concrete examples in order to prove the effectiveness of their use. 8 | 9 | ## Contents 10 | - [What Are Design Patterns?](#what-are-design-patterns) 11 | - [GoF Design Patterns](#gof-design-patterns) 12 | - [Quickstart](#quickstart) 13 | - [Categories of Design Patterns](#categories-of-design-patterns) 14 | - [Creational Patterns](#creational-patterns) 15 | - [Structural Patterns](#structural-patterns) 16 | - [Behavioral Patterns](#behavioral-patterns) 17 | - [Importance of Design Patterns](#importance-of-design-patterns) 18 | - [Why Use Design Patterns?](#why-use-design-patterns) 19 | - [Overview Table of GoF Patterns](#overview-table-of-gof-patterns) 20 | - [Patterns vs. Anti-patterns](#patterns-vs-anti-patterns) 21 | - [When to Use or Avoid Each Pattern](#when-to-use-or-avoid-each-pattern) 22 | - [.NET and Design Patterns](#net-and-design-patterns) 23 | - [.NET Mapping Cheatsheet](#net-mapping-cheatsheet) 24 | - [Repository Layout](#repository-layout) 25 | - [Examples and Use Cases](#examples-and-use-cases) 26 | - [How to Contribute](#how-to-contribute) 27 | - [Further Reading](#further-reading) 28 | - [License](#license) 29 | - [Contact](#contact) 30 | 31 | ## What Are Design Patterns? 32 | Design patterns are **standardized solutions** to common problems encountered in Software Design. They provide reusable templates for solving recurring design issues in a way that promotes best practices and improves the overall architecture of a Software System. Design patterns are not code snippets but rather general concepts that can be adapted to specific needs. They help in creating systems that are **modular**, **maintainable**, and **scalable** by defining best practices for structuring code and handling various aspects of software design. 33 | 34 | ## GoF Design Patterns 35 | The **GoF (Gang of Four)** design patterns refer to a collection of 23 design patterns that were introduced in the book **"Design Patterns: Elements of Reusable Object-Oriented Software"** published in 1994 by four authors: *Erich Gamma*, *Richard Helm*, *Ralph Johnson*, and *John Vlissides*. This book became a cornerstone in the field of software engineering and introduced the concept of design patterns as a systematic approach to solving common design problems. 36 | 37 | 👉 [Design Patterns: Elements of Reusable Object-Oriented Software](https://en.wikipedia.org/wiki/Design_Patterns) 38 | 39 | ## Quickstart 40 | Clone the repository and build the project: 41 | 42 | ```bash 43 | git clone https://github.com/engineering87/dotnet-design-patterns.git 44 | cd dotnet-design-patterns 45 | dotnet build 46 | ``` 47 | 48 | ## Categories of Design Patterns 49 | Design patterns are typically categorized into three main types based on their role and purpose: 50 | 51 | 1. **Creational Patterns** 52 | 2. **Structural Patterns** 53 | 3. **Behavioral Patterns** 54 | 55 | ### Creational Patterns 56 | Creational patterns focus on the process of object creation. They deal with how objects are instantiated, which can be a complex process depending on the requirements. These patterns abstract the instantiation process, allowing for more flexible and reusable code. 57 | 58 | ### Structural Patterns 59 | Structural patterns focus on the composition of classes and objects to form larger structures. They help in defining how objects and classes are composed to form larger structures while ensuring flexibility and efficiency. 60 | 61 | ### Behavioral Patterns 62 | Behavioral patterns focus on the interactions between objects and how responsibilities are distributed among them. They define how objects communicate and collaborate to perform specific tasks. 63 | 64 | ## Importance of Design Patterns 65 | By leveraging design patterns, developers can create more robust, maintainable, and scalable software systems. Patterns provide a framework for solving common design problems and ensure that solutions adhere to best practices in software engineering. 66 | 67 | 1. **Reusability**: 68 | Design patterns provide tested and proven solutions that can be reused across different projects. This reduces the need to reinvent the wheel and helps in creating consistent and reliable solutions. 69 | 70 | 2. **Maintainability**: 71 | Patterns promote code organization and modularity, making it easier to maintain and update software. By following established patterns, changes to one part of the system can be made with minimal impact on other parts. 72 | 73 | 3. **Scalability**: 74 | Design patterns help in building scalable systems by promoting best practices and providing guidelines for expanding functionality. They make it easier to add new features or components without disrupting existing code. 75 | 76 | 4. **Communication**: 77 | Design patterns provide a common vocabulary for developers to discuss and understand solutions to design problems. They facilitate clear communication and collaboration within development teams. 78 | 79 | 5. **Flexibility**: 80 | Patterns offer ways to handle changing requirements and evolving designs by decoupling components and defining clear responsibilities. This flexibility allows systems to adapt to new needs or technologies more easily. 81 | 82 | ## Why Use Design Patterns? 83 | Design patterns act as a toolbox of proven solutions, helping developers create better, more efficient, and maintainable software. They offer a structured approach to problem-solving, improve code readability, and facilitate collaboration among team members. 84 | 85 | ## Overview Table of GoF Patterns 86 | 87 | | Pattern | Category | Description | 88 | |---------|----------|-------------| 89 | | **Abstract Factory** | Creational | Provide an interface for creating families of related or dependent objects without specifying their concrete classes. | 90 | | **Builder** | Creational | Separate the construction of a complex object from its representation so that the same process can create different representations. | 91 | | **Factory Method** | Creational | Define an interface for object creation, but let subclasses decide which class to instantiate. | 92 | | **Prototype** | Creational | Create new objects by copying an existing object (prototype) rather than creating from scratch. | 93 | | **Singleton** | Creational | Ensure a class has only one instance, and provide a global point of access to it. | 94 | | **Adapter** | Structural | Allow incompatible interfaces to work together by wrapping one with an adapter. | 95 | | **Bridge** | Structural | Decouple an abstraction from its implementation so the two can vary independently. | 96 | | **Composite** | Structural | Compose objects into tree structures to represent part-whole hierarchies; clients treat individual objects and compositions uniformly. | 97 | | **Decorator** | Structural | Attach additional responsibilities to objects dynamically. | 98 | | **Facade** | Structural | Provide a unified interface to a set of interfaces in a subsystem. | 99 | | **Flyweight** | Structural | Use sharing to support large numbers of fine-grained objects efficiently. | 100 | | **Proxy** | Structural | Provide a surrogate or placeholder for another object to control access or defer costly operations. | 101 | | **Chain of Responsibility** | Behavioral | Allow a request to be passed along a chain of handlers until one handles it. | 102 | | **Command** | Behavioral | Encapsulate a request as an object, thereby letting you parameterize clients with queues, requests, and operations. | 103 | | **Interpreter** | Behavioral | Define a representation for a grammar of a language, and an interpreter to deal with this grammar. | 104 | | **Iterator** | Behavioral | Provide a way to access elements of an aggregate object sequentially without exposing its underlying representation. | 105 | | **Mediator** | Behavioral | Define an object that encapsulates how a set of objects interact. | 106 | | **Memento** | Behavioral | Capture and externalize an object’s internal state so that it can be restored later, without breaking encapsulation. | 107 | | **Observer** | Behavioral | Define a one-to-many dependency so that when one object changes state, all its dependents are notified. | 108 | | **State** | Behavioral | Allow an object to alter its behavior when its internal state changes; object appears to change class. | 109 | | **Strategy** | Behavioral | Define a family of algorithms, encapsulate each one, and make them interchangeable. | 110 | | **Template Method** | Behavioral | Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. | 111 | | **Visitor** | Behavioral | Represent an operation to be performed on elements of an object structure without changing the classes of the elements. | 112 | 113 | ## Patterns vs. Anti-patterns 114 | Design patterns and anti-patterns play crucial roles in software development, each representing opposing approaches to solving programming challenges: 115 | - **Design Patterns**: 116 | - Provide standard solutions for recurring problems in programming. 117 | - Have been developed and refined over time to create software that is manageable, flexible, and efficient. 118 | - Help developers produce clean, predictable, and high-quality code. 119 | 120 | - **Anti-Patterns**: 121 | - Represent flawed strategies that initially seem like valid solutions but lead to significant problems over time. 122 | - Stem from logical fallacies, inexperience, or a desire for quick fixes. 123 | - Can result in systems that are difficult to maintain, improve, or understand. 124 | 125 | - **Causes of Anti-Patterns**: 126 | - Pressure to deliver quickly, leading to sub-optimal architectural designs. 127 | - Poor understanding and ineffective communication among team members. 128 | - Spread of poor design practices, causing numerous bugs and making new code integration challenging. 129 | 130 | ## When to Use or Avoid Each Pattern 131 | | Pattern | When to Use | When to Avoid | 132 | |---------|-------------|---------------| 133 | | **Abstract Factory** | When you need to create families of related objects without depending on concrete classes. | If you only need a few objects and don’t need family consistency. | 134 | | **Builder** | When constructing a complex object step by step with different representations. | If the object is simple and doesn’t need stepwise construction. | 135 | | **Factory Method** | When subclasses should decide which concrete class to instantiate. | If you don’t need flexibility in instantiation. | 136 | | **Prototype** | When creating new objects by cloning existing ones is cheaper than creating from scratch. | If objects are simple or cloning is more expensive than direct creation. | 137 | | **Singleton** | When exactly one instance must exist and be globally accessible. | If global state leads to hidden dependencies or testing becomes hard. | 138 | | **Adapter** | When you need to make incompatible interfaces work together. | If you can refactor the code to use a common interface instead. | 139 | | **Bridge** | When you want to decouple abstraction from implementation so both can vary. | If the hierarchy is stable and won’t evolve separately. | 140 | | **Composite** | When working with tree structures (part-whole hierarchies) and want uniform access. | If the structure is flat and simple, no hierarchy needed. | 141 | | **Decorator** | When you want to add behavior dynamically without modifying classes. | If object composition makes debugging/maintenance too complex. | 142 | | **Facade** | When you want to simplify a complex subsystem with a unified interface. | If a simple wrapper hides too much functionality needed by clients. | 143 | | **Flyweight** | When you need to handle many similar objects efficiently by sharing state. | If objects are unique and sharing state gives no benefit. | 144 | | **Proxy** | When you want a placeholder to control access (e.g., lazy load, security). | If indirection adds unnecessary complexity or overhead. | 145 | | **Chain of Responsibility** | When multiple handlers can process a request without hardcoding sender–receiver. | If request flow must be predictable and explicit. | 146 | | **Command** | When you need to encapsulate requests, support undo/redo, or queue/log actions. | If direct method calls are simpler and sufficient. | 147 | | **Interpreter** | When you have a grammar to interpret and it’s relatively simple. | If grammar is complex — use a parser/DSL instead. | 148 | | **Iterator** | When you want sequential access to elements without exposing structure. | If simple loops over collections are enough. | 149 | | **Mediator** | When you want to centralize and simplify complex communications between objects. | If communication is simple and a mediator adds indirection. | 150 | | **Memento** | When you need to save and restore object state without exposing internals. | If state saving is too costly in memory or performance. | 151 | | **Observer** | When you want one-to-many notifications of state changes. | If frequent updates cause performance issues or cascading changes. | 152 | | **State** | When an object’s behavior should change based on internal state. | If state changes are rare or can be handled with conditionals. | 153 | | **Strategy** | When you need interchangeable algorithms encapsulated behind a common interface. | If only one algorithm exists and will not change. | 154 | | **Template Method** | When you want to define the skeleton of an algorithm but let subclasses fill steps. | If subclassing leads to rigid inheritance and reduced flexibility. | 155 | | **Visitor** | When you need to perform operations on object structures without modifying them. | If the object structure changes often — adding visitors becomes painful. | 156 | 157 | ## .NET and Design Patterns 158 | The .NET platform, especially with C#, offers rich language features (like delegates, LINQ, async/await, and dependency injection) that make many design patterns more expressive and efficient to implement. Patterns like Dependency Injection, Singleton, Factory, and Observer are commonly used in .NET-based enterprise solutions and are well-supported by frameworks like ASP.NET Core and libraries like `Microsoft.Extensions.*` 159 | In this repository, each pattern is demonstrated using idiomatic C# to reflect best practices in the .NET ecosystem. 160 | 161 | ## .NET Mapping Cheatsheet 162 | - **Singleton** → `IServiceCollection.AddSingleton()`, `Lazy` 163 | - **Strategy** → Interfaces + DI, runtime selection via factory/Keyed services 164 | - **Observer** → `IObservable/IObserver`, C# events, `IChangeToken` 165 | - **Decorator** → Multiple registrations / `Scrutor` (service decoration) 166 | - **Adapter** → Wrapper for external SDKs (e.g., HTTP client), `HttpMessageHandler` 167 | - **Factory Method / Abstract Factory** → `IServiceProvider`, factory delegate `Func` 168 | - **Command** → MediatR, `IRequestHandler<>` 169 | - **Iterator** → `IEnumerable`, `yield return` 170 | - **Template Method** → Base classes + `virtual` methods 171 | - **Proxy** → `HttpClient` / generated clients, dynamic proxies (Castle, DispatchProxy) 172 | 173 | ## Repository Layout 174 | Each design pattern category has its own directory and each pattern inside has its own folder, its description and its source code. 175 | 176 | ## Examples and Use Cases 177 | Each pattern comes with practical examples demonstrating its application in real-world scenarios. These examples help developers understand when and how to use each pattern to solve specific design problems effectively. 178 | 179 | ## How to Contribute 180 | Thank you for considering to help out with the source code! 181 | If you'd like to contribute, please fork, fix, commit and send a pull request for the maintainers to review and merge into the main code base. 182 | 183 | * [Setting up Git](https://docs.github.com/en/get-started/getting-started-with-git/set-up-git) 184 | * [Fork the repository](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) 185 | * [Open an issue](https://github.com/engineering87/dotnet-design-patterns/issues) if you encounter a bug or have a suggestion for improvements/features 186 | 187 | ## Further Reading 188 | - [Common Design Patterns (.NET Design Guidelines)](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/common-design-patterns) – Official Microsoft guidance on commonly used design patterns in .NET. 189 | - [Discovering the Design Patterns You're Already Using in .NET (MSDN Magazine)](https://learn.microsoft.com/en-us/archive/msdn-magazine/2005/july/discovering-the-design-patterns-you-re-already-using-in-net) – An article showing how many design patterns are already embedded in the .NET Framework and ASP.NET. 190 | - [Design Patterns: Elements of Reusable Object-Oriented Software](https://en.wikipedia.org/wiki/Design_Patterns) – The original “Gang of Four” book that introduced the 23 classic design patterns. 191 | 192 | ## License 193 | Repository source code is available under MIT License, see [LICENSE](LICENSE) in the source. 194 | 195 | ## Contact 196 | Please contact at francesco.delre.87[at]gmail.com for any details. 197 | --------------------------------------------------------------------------------