├── Patterns
├── Proxy
│ ├── IUser.cs
│ ├── IAuthenticationController.cs
│ ├── IEntries.cs
│ ├── IProductInfo.cs
│ ├── Proxy.csproj
│ ├── AuthenticationController.cs
│ ├── Entries.cs
│ └── EntriesProxy.cs
├── FactoryMethod
│ ├── IPerks.cs
│ ├── FactoryMethod.csproj
│ ├── BasicPerks.cs
│ ├── GoldPerks.cs
│ ├── SilverPerks.cs
│ ├── EarningBonusCalculatorRefactored.cs
│ ├── EarningBonusCalculatorLegacy.cs
│ └── PerksFactory.cs
├── Observer
│ ├── IObserver.cs
│ ├── Observer.csproj
│ ├── Customer.cs
│ ├── ISubject.cs
│ └── SpecialsSubject.cs
├── Iterator
│ ├── MatrixDirection.cs
│ ├── Iterator.csproj
│ ├── AggregateObject.cs
│ ├── IMatrix.cs
│ ├── GenericIterator.cs
│ ├── NumberMatrix.cs
│ └── MatrixIterator.cs
├── Flyweight
│ ├── TextBlob.cs
│ ├── TextBlobFactory.cs
│ ├── Flyweight.csproj
│ ├── TextDownloader.cs
│ ├── XmlTextBlob.cs
│ └── XmlTextBlobFactory.cs
├── Command
│ ├── ICommand.cs
│ ├── IProduct.cs
│ ├── IInvoker.cs
│ ├── Command.csproj
│ ├── IProductList.cs
│ ├── ClearCommand.cs
│ ├── RemoveCommand.cs
│ ├── AddCommand.cs
│ └── ProductCommandInvoker.cs
├── Mediator
│ ├── IAlertScreen.cs
│ ├── Mediator.csproj
│ ├── Product.cs
│ ├── IMediator.cs
│ ├── IPurchaser.cs
│ ├── PurchaseMediator.cs
│ └── Purchaser.cs
├── SingletonDependencyInjection
│ ├── ILogger.cs
│ ├── SingletonDI.csproj
│ ├── Logger.cs
│ └── LazyLogger.cs
├── State
│ ├── IProduct.cs
│ ├── State.csproj
│ ├── ICouponState.cs
│ ├── ICoupon.cs
│ ├── InvalidCouponState.cs
│ ├── ValidCouponState.cs
│ └── Coupon.cs
├── TemplateMethod
│ ├── ITaxBracket.cs
│ ├── TemplateMethod.csproj
│ ├── IBook.cs
│ ├── BookPriceCalculator.cs
│ ├── LowIncomeBookPriceCalculator.cs
│ └── HighIncomeBookPriceCalculator.cs
├── Strategy
│ ├── IDiscountScheme.cs
│ ├── ICoupon.cs
│ ├── IProduct.cs
│ ├── Strategy.csproj
│ ├── NonMemberDiscountScheme.cs
│ ├── business_logic.txt
│ └── MemberDiscountScheme.cs
├── Bridge
│ ├── IPayment.cs
│ ├── Bridge.csproj
│ ├── IPaymentGateway.cs
│ ├── Order.cs
│ ├── PurchaseOrder.cs
│ ├── PaypalPayment.cs
│ └── CreditCardPayment.cs
├── Decorator
│ ├── IHtmlElement.cs
│ ├── Decorator.csproj
│ ├── HtmlElement.cs
│ ├── BoldenHtmlElement.cs
│ ├── ItalicizeHtmlElement.cs
│ ├── HtmlElementDecorator.cs
│ └── HyperLinkifyHtmlElement.cs
├── Visitor
│ ├── IVisitor.cs
│ ├── Visitor.csproj
│ ├── GameElement.cs
│ ├── Instruction.cs
│ ├── TextElement.cs
│ ├── Revealer.cs
│ ├── Concealer.cs
│ └── Sprite.cs
├── Facade
│ ├── IPaymentProcessor.cs
│ ├── Facade.csproj
│ ├── IMerchantAuthenticationType.cs
│ ├── ITransactionRequest.cs
│ ├── IBillingAddress.cs
│ ├── IEnvironment.cs
│ ├── ITransactionController.cs
│ ├── ICreditCard.cs
│ ├── business_logic.txt
│ └── PaymentProcessor.cs
├── Memento
│ ├── IProductOriginator.cs
│ ├── IProductCaretaker.cs
│ ├── Memento.csproj
│ ├── Product.cs
│ ├── ProductOriginator.cs
│ └── ProductCaretaker.cs
├── Adapter
│ ├── Adapter.csproj
│ ├── IGoodReadsProfile.cs
│ ├── ISocialMediaProfile.cs
│ └── SocialMediaProfileAdapter.cs
├── Builder
│ ├── Builder.csproj
│ ├── Product.cs
│ ├── IDIscountStrategy.cs
│ ├── SkuCodeStartDiscountStrategyBuilder.cs
│ ├── SkuCodeStartDiscountStrategy.cs
│ └── DiscountStrategyBuilder.cs
├── Composite
│ ├── Composite.csproj
│ ├── IBook.cs
│ ├── Book.cs
│ └── BookComposite.cs
├── Prototype
│ ├── Prototype.csproj
│ ├── Address.cs
│ ├── BasicCustomer.cs
│ └── Customer.cs
├── AbstractFactory
│ ├── AbstractFactory.csproj
│ ├── IProcessor.cs
│ ├── IStorage.cs
│ ├── ILaptopPartsFactory.cs
│ ├── AMDProcessor.cs
│ ├── HardDrive.cs
│ ├── IntelProcessor.cs
│ ├── SolidStateDrive.cs
│ ├── LenovoPartsFactory.cs
│ └── DellPartsFactory.cs
└── ChainOfResponsibility
│ ├── IPaymentGateway.cs
│ ├── ChainOfResponsibility.csproj
│ ├── ICreditCardHandler.cs
│ ├── ICreditCard.cs
│ ├── CreditCardHandlerBase.cs
│ ├── AmexCardHandler.cs
│ ├── VisaCardHandler.cs
│ └── MastercardHandler.cs
├── .gitignore
├── LICENSE
├── Tests
├── TemplateMethodTest.cs
├── FlyweightTest.cs
├── StateTest.cs
├── AdapterTest.cs
├── SingletonDITest.cs
├── BridgeTest.cs
├── MementoTest.cs
├── ObserverTest.cs
├── VisitorTest.cs
├── BuilderTest.cs
├── CompositeTest.cs
├── PrototypeTest.cs
├── Tests.csproj
├── AbstractFactory
│ └── AbstractFactoryTest.cs
├── ProxyTest.cs
├── FactoryMethodTest.cs
├── FacadeTestData.cs
├── IteratorTest.cs
├── FacadeTest.cs
├── MediatorTest.cs
├── ChainOfResponsibilityTest.cs
├── StrategyTest.cs
├── DecoratorTest.cs
└── CommandTest.cs
├── .github
└── workflows
│ └── dotnet.yml
├── README.md
└── DesignPatterns.sln
/Patterns/Proxy/IUser.cs:
--------------------------------------------------------------------------------
1 | namespace Proxy
2 | {
3 | public interface IUser
4 | {
5 | bool IsAdmin {get;set;}
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Patterns/FactoryMethod/IPerks.cs:
--------------------------------------------------------------------------------
1 | namespace FactoryMethod
2 | {
3 | public interface IPerks
4 | {
5 | decimal EarningBonus();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Patterns/Observer/IObserver.cs:
--------------------------------------------------------------------------------
1 | namespace Observer
2 | {
3 | public interface IObserver
4 | {
5 | string Update(ISubject subject);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Patterns/Iterator/MatrixDirection.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Iterator
3 | {
4 | public enum MatrixDirection
5 | {
6 | ByRow,
7 | ByColumn
8 | }
9 | }
--------------------------------------------------------------------------------
/Patterns/Flyweight/TextBlob.cs:
--------------------------------------------------------------------------------
1 | namespace Flyweight
2 | {
3 | public interface TextBlob
4 | {
5 | void Download(int id, string blobContent);
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Patterns/Proxy/IAuthenticationController.cs:
--------------------------------------------------------------------------------
1 | namespace Proxy
2 | {
3 | public interface IAuthenticationController
4 | {
5 | bool IsAdmin();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/Patterns/Command/ICommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Command
4 | {
5 | public interface ICommand
6 | {
7 | void Execute();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Patterns/Mediator/IAlertScreen.cs:
--------------------------------------------------------------------------------
1 | namespace Mediator
2 | {
3 | public interface IAlertScreen
4 | {
5 | void ShowMessage(string item, string location);
6 | }
7 | }
--------------------------------------------------------------------------------
/Patterns/SingletonDependencyInjection/ILogger.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace SingletonDI
3 | {
4 | public interface ILogger
5 | {
6 | void Log(string msg);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Patterns/State/IProduct.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace State
4 | {
5 | public interface IProduct
6 | {
7 | decimal Price {get;}
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Patterns/Command/IProduct.cs:
--------------------------------------------------------------------------------
1 | namespace Command
2 | {
3 | public interface IProduct
4 | {
5 | string Name { get; set; }
6 | decimal Price { get; set; }
7 | }
8 | }
--------------------------------------------------------------------------------
/Patterns/TemplateMethod/ITaxBracket.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | namespace TemplateMethod
5 | {
6 | public interface ITaxBracket
7 | {
8 | int TaxPercent();
9 | }
10 | }
--------------------------------------------------------------------------------
/Patterns/Strategy/IDiscountScheme.cs:
--------------------------------------------------------------------------------
1 | namespace Strategy
2 | {
3 | public interface IDiscountScheme
4 | {
5 | decimal ComputePrice(IProduct product, ICoupon coupon);
6 | }
7 | }
--------------------------------------------------------------------------------
/Patterns/Bridge/IPayment.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Bridge
4 | {
5 | public interface IPayment
6 | {
7 | void SubmitPayment(decimal amount);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Patterns/Decorator/IHtmlElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Decorator
4 | {
5 | public interface IHtmlElement
6 | {
7 | string GetHtmlElement();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Patterns/Proxy/IEntries.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Proxy
3 | {
4 | public interface IEntries
5 | {
6 | bool Delete(int id);
7 | IProductInfo? Get(int id);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Patterns/Visitor/IVisitor.cs:
--------------------------------------------------------------------------------
1 | namespace Visitor
2 | {
3 | public interface IVisitor
4 | {
5 | void Visit(GameElement gameObject);
6 | void Visit(TextElement textObject);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Patterns/Flyweight/TextBlobFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Flyweight
4 | {
5 | public interface TextBlobFactory
6 | {
7 | TextBlob GetTextBlob(int id);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Patterns/Proxy/IProductInfo.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Proxy
3 | {
4 | public interface IProductInfo
5 | {
6 | string Name { get; set; }
7 | int Id { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Patterns/Command/IInvoker.cs:
--------------------------------------------------------------------------------
1 | namespace Command
2 | {
3 | public interface IInvoker
4 | {
5 | bool AddCommand(string key, ICommand command);
6 | void InvokeCommand(string key);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Patterns/Facade/IPaymentProcessor.cs:
--------------------------------------------------------------------------------
1 | namespace Facade
2 | {
3 | public interface IPaymentProcessor
4 | {
5 | void InitializePaymentGatewayInterface();
6 | bool SubmitPayment();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Patterns/Memento/IProductOriginator.cs:
--------------------------------------------------------------------------------
1 | namespace Memento
2 | {
3 | public interface IProductOriginator
4 | {
5 | void SetMemento(Product product);
6 | Product GetMemento();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Patterns/Strategy/ICoupon.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Strategy
4 | {
5 | public interface ICoupon
6 | {
7 | int DiscountPercentage();
8 | bool IsExpired();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Patterns/Adapter/Adapter.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Bridge/Bridge.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Builder/Builder.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Command/Command.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Facade/Facade.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Memento/IProductCaretaker.cs:
--------------------------------------------------------------------------------
1 | namespace Memento
2 | {
3 | public interface IProductCaretaker
4 | {
5 | void AddProductMemento(Product product);
6 | Product GetLastMemento();
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Patterns/Memento/Memento.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Proxy/Proxy.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/State/State.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Visitor/Visitor.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Bridge/IPaymentGateway.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Bridge
4 | {
5 | public interface IPaymentGateway
6 | {
7 | void ProcessPayment(decimal amount, IPayment payment);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Patterns/Composite/Composite.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Decorator/Decorator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Flyweight/Flyweight.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Flyweight/TextDownloader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Flyweight
4 | {
5 | public interface TextDownloader
6 | {
7 | void DownloadFile(string url, string blobContent);
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Patterns/Iterator/Iterator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Mediator/Mediator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Observer/Observer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Prototype/Prototype.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Strategy/IProduct.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 |
4 | namespace Strategy
5 | {
6 | public interface IProduct
7 | {
8 | decimal SellingPrice();
9 |
10 | bool IsOnSale();
11 | }
12 | }
--------------------------------------------------------------------------------
/Patterns/Strategy/Strategy.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Facade/IMerchantAuthenticationType.cs:
--------------------------------------------------------------------------------
1 | namespace Facade
2 | {
3 | public interface IMerchantAuthenticationType
4 | {
5 | string LoginID {get;set;}
6 | string TransactionKey {get;set;}
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Patterns/FactoryMethod/FactoryMethod.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Mediator/Product.cs:
--------------------------------------------------------------------------------
1 | namespace Mediator
2 | {
3 | public sealed class Product
4 | {
5 | public string Item { get; set; } = string.Empty;
6 | public string Location { get; set; } = string.Empty;
7 | }
8 | }
--------------------------------------------------------------------------------
/Patterns/TemplateMethod/TemplateMethod.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/AbstractFactory/AbstractFactory.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/AbstractFactory/IProcessor.cs:
--------------------------------------------------------------------------------
1 | namespace AbstractFactory
2 | {
3 | //TODO: Use Generic Constraints
4 | public interface IProcessor
5 | {
6 | string BrandName();
7 | double SpeedInGigaHertz();
8 | }
9 | }
--------------------------------------------------------------------------------
/Patterns/ChainOfResponsibility/IPaymentGateway.cs:
--------------------------------------------------------------------------------
1 | namespace ChainOfResponsibility
2 | {
3 | public interface IPaymentGateway
4 | {
5 | bool SubmitVerification(ICreditCardHandler creditCardHandler, ICreditCard card);
6 | }
7 | }
--------------------------------------------------------------------------------
/Patterns/FactoryMethod/BasicPerks.cs:
--------------------------------------------------------------------------------
1 | namespace FactoryMethod
2 | {
3 | public class BasicPerks : IPerks
4 | {
5 | public decimal EarningBonus()
6 | {
7 | return 0m;
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Patterns/FactoryMethod/GoldPerks.cs:
--------------------------------------------------------------------------------
1 | namespace FactoryMethod
2 | {
3 | public class GoldPerks : IPerks
4 | {
5 | public decimal EarningBonus()
6 | {
7 | return 1.0m;
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Patterns/SingletonDependencyInjection/SingletonDI.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/Adapter/IGoodReadsProfile.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Mail;
2 |
3 | namespace Adapter
4 | {
5 | public interface IGoodReadsProfile
6 | {
7 | string Name { get; }
8 | MailAddress Email { get; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Patterns/ChainOfResponsibility/ChainOfResponsibility.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Patterns/FactoryMethod/SilverPerks.cs:
--------------------------------------------------------------------------------
1 | namespace FactoryMethod
2 | {
3 | public class SilverPerks : IPerks
4 | {
5 | public decimal EarningBonus()
6 | {
7 | return 0.5m;
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Patterns/Iterator/AggregateObject.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 |
3 | namespace Iterator
4 | {
5 | public abstract class AggregateObject : IEnumerable
6 | {
7 | public abstract IEnumerator GetEnumerator();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Patterns/Command/IProductList.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Command
4 | {
5 | public interface IProductList
6 | {
7 | string Name { get; set; }
8 | List Products { get; set;}
9 | }
10 | }
--------------------------------------------------------------------------------
/Patterns/Iterator/IMatrix.cs:
--------------------------------------------------------------------------------
1 | namespace Iterator
2 | {
3 | public interface IMatrix
4 | {
5 | T this[int row, int column] {get;set;}
6 |
7 | int TotalColumns();
8 | int TotalRows();
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Patterns/AbstractFactory/IStorage.cs:
--------------------------------------------------------------------------------
1 | namespace AbstractFactory
2 | {
3 | //TODO: Use Generic Constraints
4 | public interface IStorage
5 | {
6 | string HardwareType();
7 | int ReadSpeedInMBytesPerSec();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Patterns/Composite/IBook.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Composite
4 | {
5 | public interface IBook
6 | {
7 | decimal Price { get; }
8 | string Name { get; }
9 |
10 | int Discount { get; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Patterns/State/ICouponState.cs:
--------------------------------------------------------------------------------
1 |
2 | using System;
3 |
4 | namespace State
5 | {
6 | public interface ICouponState
7 | {
8 | void ChangeExpiryDate(DateTime date, ICoupon coupon);
9 | bool UseDiscount();
10 | }
11 |
12 | }
--------------------------------------------------------------------------------
/Patterns/TemplateMethod/IBook.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace TemplateMethod
4 | {
5 | public interface IBook
6 | {
7 | decimal Price { get; }
8 | string Name { get; }
9 | int Discount { get; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Patterns/Visitor/GameElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Visitor
4 | {
5 | public abstract class GameElement
6 | {
7 | public bool Active { get; set; } = false;
8 | public abstract void Accept(IVisitor visitor);
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Patterns/Visitor/Instruction.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Visitor
3 | {
4 | public class Instruction : TextElement
5 | {
6 | public override void Accept(IVisitor visitor)
7 | {
8 | visitor.Visit(this);
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Patterns/Mediator/IMediator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Mediator
4 | {
5 | public interface IMediator
6 | {
7 | bool BroadcastPurchaseCompletion(IPurchaser purchaser);
8 | bool AddPurchaser(IPurchaser purchaser);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Patterns/Mediator/IPurchaser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Mediator
4 | {
5 | public interface IPurchaser
6 | {
7 | void Receive(IPurchaser purchaser);
8 | void Complete(Product product);
9 | Product? GetProduct();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Patterns/AbstractFactory/ILaptopPartsFactory.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace AbstractFactory
3 | {
4 | // TODO: Use Generic Constraints
5 | public interface ILaptopPartsFactory
6 | {
7 | IStorage CreateStorage();
8 | IProcessor CreateProcessor();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Patterns/ChainOfResponsibility/ICreditCardHandler.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace ChainOfResponsibility
3 | {
4 | public interface ICreditCardHandler
5 | {
6 | ICreditCardHandler SetNext(ICreditCardHandler creditCardHandler);
7 | bool IsCreditCardValid(ICreditCard card);
8 | }
9 | }
--------------------------------------------------------------------------------
/Patterns/Facade/ITransactionRequest.cs:
--------------------------------------------------------------------------------
1 | namespace Facade
2 | {
3 | public interface ITransactionRequest
4 | {
5 | decimal Amount{get;set;}
6 | IBillingAddress BillingAddress{get;set;}
7 |
8 | ICreditCard CreditCard {get;set;}
9 |
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Patterns/Visitor/TextElement.cs:
--------------------------------------------------------------------------------
1 | namespace Visitor
2 | {
3 | public abstract class TextElement
4 | {
5 | public abstract void Accept(IVisitor visitor);
6 | public bool Active { get; set; } = false;
7 | public string Message { get; set; } = string.Empty;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Patterns/Builder/Product.cs:
--------------------------------------------------------------------------------
1 | namespace Builder
2 | {
3 | public class Product
4 | {
5 | public required string StockKeepingUnit { get; set; }
6 | public decimal RegularRetailPrice { get; set; }
7 | public required string Name { get; set; }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/Patterns/SingletonDependencyInjection/Logger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SingletonDI
4 | {
5 | public class Logger : ILogger
6 | {
7 | public void Log(string msg)
8 | {
9 | Console.WriteLine($"LOG: {msg}");
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Patterns/Adapter/ISocialMediaProfile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Mail;
3 |
4 | namespace Adapter
5 | {
6 | public interface ISocialMediaProfile
7 | {
8 | string Name { get; }
9 | string UserName { get; }
10 | MailAddress Email { get; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Patterns/Observer/Customer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Observer
4 | {
5 | public class Customer : IObserver
6 | {
7 | public string Update(ISubject subject)
8 | {
9 | return $"Customer received {subject.SubjectState}";
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Patterns/State/ICoupon.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace State
4 | {
5 | public interface ICoupon
6 | {
7 | void UpdateExpiryDate(DateTime dateTime);
8 | decimal ApplyDiscountTo(IProduct product);
9 |
10 | void SetCouponState(ICouponState state);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/Patterns/Facade/IBillingAddress.cs:
--------------------------------------------------------------------------------
1 | namespace Facade
2 | {
3 | public interface IBillingAddress
4 | {
5 | string FirstName {get;set;}
6 | string LastName {get; set;}
7 | string Address {get;set;}
8 | string City {get;set;}
9 | string ZipCode{get;set;}
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Patterns/Builder/IDIscountStrategy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Builder
4 | {
5 | public interface IDiscountStrategy
6 | {
7 | int DiscountInPercentage { get; set; }
8 | string SkuCode {get; set;}
9 | decimal CalculateDiscountedRetailPrice(Product product);
10 |
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Patterns/Observer/ISubject.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Observer
4 | {
5 | public interface ISubject
6 | {
7 | void Attach(IObserver observer);
8 |
9 | void Detach(IObserver observer);
10 |
11 | void Notify();
12 |
13 | string SubjectState {get; set;}
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Patterns/Builder/SkuCodeStartDiscountStrategyBuilder.cs:
--------------------------------------------------------------------------------
1 | namespace Builder
2 | {
3 | public class SkuCodeStartDiscountStrategyBuilder : DiscountStrategyBuilder
4 | {
5 | public SkuCodeStartDiscountStrategyBuilder()
6 | : base(new SkuCodeStartDiscountStrategy())
7 | {
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Patterns/Visitor/Revealer.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Visitor
3 | {
4 | public class Revealer : IVisitor
5 | {
6 | public void Visit(GameElement gameObject)
7 | {
8 | gameObject.Active = true;
9 | }
10 |
11 | public void Visit(TextElement textElement)
12 | {
13 | textElement.Active = true;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Patterns/Visitor/Concealer.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Visitor
3 | {
4 | public class Concealer : IVisitor
5 | {
6 | public void Visit(GameElement gameObject)
7 | {
8 | gameObject.Active = false;
9 | }
10 |
11 | public void Visit(TextElement textElement)
12 | {
13 | textElement.Active = false;
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Patterns/AbstractFactory/AMDProcessor.cs:
--------------------------------------------------------------------------------
1 | namespace AbstractFactory
2 | {
3 | public class AmdProcessor : IProcessor
4 | {
5 | public string BrandName()
6 | {
7 | return "AMD";
8 | }
9 | public double SpeedInGigaHertz()
10 | {
11 | return 2.1;
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/Patterns/AbstractFactory/HardDrive.cs:
--------------------------------------------------------------------------------
1 | namespace AbstractFactory
2 | {
3 |
4 | public class HardDrive : IStorage
5 | {
6 | public string HardwareType()
7 | {
8 | return "hdd";
9 | }
10 | public int ReadSpeedInMBytesPerSec()
11 | {
12 | return 50;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/Patterns/Facade/IEnvironment.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Facade
4 | {
5 | public enum EnvironmentTarget
6 | {
7 | UNINITIALIZED,
8 | SANDBOX,
9 | PRODUCTiON
10 | }
11 | public interface IEnvironment
12 | {
13 | EnvironmentTarget environmentVariableTarget {get;set;}
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Patterns/Visitor/Sprite.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Visitor
3 | {
4 | public class Sprite : GameElement
5 | {
6 | public string Name { get; }
7 | public Sprite(string name) { Name = name; }
8 | public override void Accept(IVisitor visitor)
9 | {
10 | visitor.Visit(this);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Patterns/AbstractFactory/IntelProcessor.cs:
--------------------------------------------------------------------------------
1 | namespace AbstractFactory
2 | {
3 | public class IntelProcessor : IProcessor
4 | {
5 | public string BrandName()
6 | {
7 | return "Intel";
8 | }
9 | public double SpeedInGigaHertz()
10 | {
11 | return 1.8;
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/Patterns/Bridge/Order.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Bridge
4 | {
5 | public abstract class Order
6 | {
7 | protected IPayment Payment { get; }
8 | public Order(IPayment payment)
9 | {
10 | Payment = payment;
11 | }
12 | public abstract void Checkout(decimal amount);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Patterns/Memento/Product.cs:
--------------------------------------------------------------------------------
1 | namespace Memento
2 | {
3 | public class Product
4 | {
5 | public string Name { get; set; } = string.Empty;
6 | public decimal Price { get; set; }
7 |
8 | public Product ShallowCopy()
9 | {
10 | return (Product)this.MemberwiseClone();
11 | }
12 |
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Patterns/AbstractFactory/SolidStateDrive.cs:
--------------------------------------------------------------------------------
1 | namespace AbstractFactory
2 | {
3 |
4 | public class SolidStateDrive : IStorage
5 | {
6 | public string HardwareType()
7 | {
8 | return "ssd";
9 | }
10 | public int ReadSpeedInMBytesPerSec()
11 | {
12 | return 250;
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/Patterns/Bridge/PurchaseOrder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Bridge
4 | {
5 | public class PurchaseOrder : Order
6 | {
7 | public PurchaseOrder(IPayment payment) : base(payment)
8 | {
9 | }
10 | public override void Checkout(decimal amount)
11 | {
12 | Payment.SubmitPayment(amount);
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Patterns/AbstractFactory/LenovoPartsFactory.cs:
--------------------------------------------------------------------------------
1 | namespace AbstractFactory
2 | {
3 | public class LenovoPartsFactory : ILaptopPartsFactory
4 | {
5 | public IStorage CreateStorage()
6 | {
7 | return new HardDrive();
8 | }
9 | public IProcessor CreateProcessor()
10 | {
11 | return new AmdProcessor();
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Patterns/Facade/ITransactionController.cs:
--------------------------------------------------------------------------------
1 | namespace Facade
2 | {
3 |
4 | public enum TransactionResponseType
5 | {
6 | OK,
7 | DECLINED
8 | }
9 | public interface ITransactionController
10 | {
11 | ITransactionRequest TransactionRequest {get;set;}
12 | void Execute();
13 |
14 | TransactionResponseType GetApiResponse();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Patterns/AbstractFactory/DellPartsFactory.cs:
--------------------------------------------------------------------------------
1 | namespace AbstractFactory
2 | {
3 | public class DellPartsFactory : ILaptopPartsFactory
4 | {
5 | public IStorage CreateStorage()
6 | {
7 | return new SolidStateDrive();
8 | }
9 | public IProcessor CreateProcessor()
10 | {
11 | return new IntelProcessor();
12 | }
13 | }
14 |
15 | }
--------------------------------------------------------------------------------
/Patterns/Command/ClearCommand.cs:
--------------------------------------------------------------------------------
1 | namespace Command
2 | {
3 | public class ClearCommand : ICommand
4 | {
5 | private IProductList _productList;
6 | public ClearCommand(IProductList productList)
7 | {
8 | _productList = productList;
9 | }
10 | public void Execute()
11 | {
12 | _productList.Products.Clear();
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Patterns/Proxy/AuthenticationController.cs:
--------------------------------------------------------------------------------
1 | namespace Proxy
2 | {
3 | public class AuthenticationController : IAuthenticationController
4 | {
5 | private IUser _user;
6 | public AuthenticationController(IUser user)
7 | {
8 | _user = user;
9 | }
10 | public bool IsAdmin()
11 | {
12 | return _user.IsAdmin;
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Patterns/Decorator/HtmlElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 |
4 | namespace Decorator
5 | {
6 | public class HtmlElement : IHtmlElement
7 | {
8 | private readonly string _value;
9 | HtmlElement(string value)
10 | {
11 | _value = value;
12 | }
13 |
14 | public string GetHtmlElement()
15 | {
16 | return _value;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Patterns/ChainOfResponsibility/ICreditCard.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ChainOfResponsibility
4 | {
5 | // Credit card numbers are created in a consistent way.
6 | // American Express cards start with either 34 or 37.
7 | // Mastercard numbers begin with 51–55.
8 | // Visa cards start with 4
9 | public interface ICreditCard
10 | {
11 | string Number { get; set; }
12 |
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Patterns/Facade/ICreditCard.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Facade
4 | {
5 | public enum CreditCard
6 | {
7 | VISA,
8 | MASTERCARD,
9 | AMEX
10 | }
11 | public interface ICreditCard
12 | {
13 | CreditCard Type {get;set;}
14 | string AccountNumber {get;set;}
15 |
16 | string CVC {get;set;}
17 |
18 | DateTime ExpiryDate {get;set;}
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Patterns/Decorator/BoldenHtmlElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Decorator
4 | {
5 | public class BoldenHtmlElement : HtmlElementDecorator
6 | {
7 | public BoldenHtmlElement(IHtmlElement htmlElement) : base(htmlElement)
8 | {
9 | }
10 |
11 | public override string GetHtmlElement()
12 | {
13 | return $"{base.GetWrappedHtmlElement()}";
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Patterns/Iterator/GenericIterator.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 |
3 | namespace Iterator
4 | {
5 | public abstract class GenericIterator : IEnumerator
6 | {
7 |
8 | object IEnumerator.Current => Current();
9 |
10 | public abstract object Current();
11 |
12 | public abstract bool MoveNext();
13 |
14 | public abstract void Reset();
15 |
16 | public abstract bool HasNext();
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Patterns/Prototype/Address.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Prototype
4 | {
5 | public class Address
6 | {
7 | public string StreetAddress { get; set; } = string.Empty;
8 | public string City { get; set; } = string.Empty;
9 | public string State { get; set; } = string.Empty;
10 | public string Country { get; set; } = string.Empty;
11 | public string PostCode { get; set; } = string.Empty;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Patterns/Decorator/ItalicizeHtmlElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Decorator
4 | {
5 | public class ItalicizeHtmlElement : HtmlElementDecorator
6 | {
7 | public ItalicizeHtmlElement(IHtmlElement htmlElement) : base(htmlElement)
8 | {
9 |
10 | }
11 |
12 | public override string GetHtmlElement()
13 | {
14 | return $"{base.GetWrappedHtmlElement()}";
15 | }
16 |
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *.*~
3 | project.lock.json
4 | .DS_Store
5 | *.pyc
6 |
7 | # Visual Studio Code
8 | .vscode
9 |
10 | # User-specific files
11 | *.suo
12 | *.user
13 | *.userosscache
14 | *.sln.docstates
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | build/
24 | bld/
25 | [Bb]in/
26 | [Oo]bj/
27 | msbuild.log
28 | msbuild.err
29 | msbuild.wrn
30 |
31 | # Visual Studio 2015
32 | .vs/
--------------------------------------------------------------------------------
/Patterns/Bridge/PaypalPayment.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 | namespace Bridge
4 | {
5 | public class PaypalPayment : IPayment
6 | {
7 | private IPaymentGateway _mPaymentGateway;
8 |
9 | public PaypalPayment(IPaymentGateway paymentGateway)
10 | {
11 | _mPaymentGateway = paymentGateway;
12 | }
13 | public void SubmitPayment(decimal amount)
14 | {
15 | _mPaymentGateway.ProcessPayment(amount, this);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Patterns/Bridge/CreditCardPayment.cs:
--------------------------------------------------------------------------------
1 |
2 |
3 | namespace Bridge
4 | {
5 | public class CreditCardPayment : IPayment
6 | {
7 | private IPaymentGateway _mPaymentGateway;
8 |
9 | public CreditCardPayment(IPaymentGateway paymentGateway)
10 | {
11 | _mPaymentGateway = paymentGateway;
12 | }
13 | public void SubmitPayment(decimal amount)
14 | {
15 | _mPaymentGateway.ProcessPayment(amount, this);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Patterns/Composite/Book.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Composite
4 | {
5 | public class Book : IBook
6 | {
7 | public decimal Price { get; private set; }
8 | public string Name { get; private set; }
9 |
10 | public int Discount {get; private set;}
11 |
12 | public Book(string name, decimal price, int discount = 0)
13 | {
14 | Price = price;
15 | Name = name;
16 | Discount = discount;
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/Patterns/Prototype/BasicCustomer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Prototype
4 | {
5 | public abstract class BasicCustomer : ICloneable
6 | {
7 | public string FirstName { get; set; } = string.Empty;
8 | public string LastName { get; set; } = string.Empty;
9 | public Address? HomeAddress { get; set; }
10 | public Address? BillingAddress { get; set; }
11 |
12 | public abstract object Clone();
13 | public abstract Customer DeepClone();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Patterns/Command/RemoveCommand.cs:
--------------------------------------------------------------------------------
1 | namespace Command
2 | {
3 | public class RemoveCommand : ICommand
4 | {
5 | private IProductList _productList;
6 | private IProduct _product;
7 | public RemoveCommand(IProductList productList, IProduct product)
8 | {
9 | _productList = productList;
10 | _product = product;
11 | }
12 | public void Execute()
13 | {
14 | _productList.Products.Remove(_product);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Patterns/Decorator/HtmlElementDecorator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Decorator
4 | {
5 | public abstract class HtmlElementDecorator : IHtmlElement
6 | {
7 | IHtmlElement _htmlElement;
8 | public HtmlElementDecorator(IHtmlElement htmlElement) => _htmlElement = htmlElement;
9 |
10 | public abstract string GetHtmlElement();
11 |
12 | protected string GetWrappedHtmlElement()
13 | {
14 | return _htmlElement.GetHtmlElement();
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Patterns/Command/AddCommand.cs:
--------------------------------------------------------------------------------
1 | namespace Command
2 | {
3 | public class AddCommand : ICommand
4 | {
5 | private IProduct _product;
6 | private IProductList _productList;
7 |
8 | public AddCommand(IProductList productList, IProduct product)
9 | {
10 | _productList = productList;
11 | _product = product;
12 | }
13 |
14 | public void Execute()
15 | {
16 | _productList.Products.Add(_product);
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Patterns/State/InvalidCouponState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace State
4 | {
5 | public class InvalidCouponState : ICouponState
6 | {
7 | public void ChangeExpiryDate(DateTime dateTime, ICoupon coupon)
8 | {
9 | if (dateTime >= DateTime.Today)
10 | {
11 | coupon.SetCouponState(new ValidCouponState());
12 | }
13 | }
14 |
15 | public bool UseDiscount()
16 | {
17 | return false;
18 | }
19 | }
20 |
21 | }
--------------------------------------------------------------------------------
/Patterns/TemplateMethod/BookPriceCalculator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace TemplateMethod
4 | {
5 | public abstract class BookPriceCalculator
6 | {
7 | protected abstract decimal ComputeTotalPriceBeforeTax(IBook books);
8 | protected abstract decimal ApplyTax(decimal priceBeforeTax);
9 |
10 | public decimal CalculatePrice(IBook books)
11 | {
12 | var priceBeforeTax = ComputeTotalPriceBeforeTax(books);
13 | return ApplyTax(priceBeforeTax);
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Patterns/State/ValidCouponState.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace State
4 | {
5 | public class ValidCouponState : ICouponState
6 | {
7 | public void ChangeExpiryDate(DateTime dateTime, ICoupon coupon)
8 | {
9 | if (dateTime < DateTime.Today)
10 | {
11 | coupon.SetCouponState(new InvalidCouponState());
12 | }
13 |
14 | }
15 |
16 | public bool UseDiscount()
17 | {
18 | return true;
19 | }
20 | }
21 |
22 | }
--------------------------------------------------------------------------------
/Patterns/Flyweight/XmlTextBlob.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Flyweight
4 | {
5 | public class XmlTextBlob : TextBlob
6 | {
7 | private TextDownloader textDownloader;
8 |
9 | public XmlTextBlob(TextDownloader textDownloader)
10 | {
11 | this.textDownloader = textDownloader;
12 | }
13 | public void Download(int id, string blobContent)
14 | {
15 | textDownloader.DownloadFile($"https://localhost:5001/api/getitem/{id}", blobContent);
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Patterns/Decorator/HyperLinkifyHtmlElement.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Decorator
4 | {
5 | public class HyperLinkifyHtmlElement : HtmlElementDecorator
6 | {
7 | private string _link;
8 | public HyperLinkifyHtmlElement(string link, IHtmlElement htmlElement) : base(htmlElement)
9 | {
10 | _link = link;
11 | }
12 |
13 | public override string GetHtmlElement()
14 | {
15 | return $"{base.GetWrappedHtmlElement()}";
16 | }
17 | }
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/Patterns/Strategy/NonMemberDiscountScheme.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 |
4 | namespace Strategy
5 | {
6 | public class NonMemberDiscountScheme : IDiscountScheme
7 | {
8 | public decimal ComputePrice(IProduct product, ICoupon coupon)
9 | {
10 | if (coupon.IsExpired())
11 | {
12 | return product.SellingPrice();
13 | }
14 | var discount = product.IsOnSale() ? 0M : (product.SellingPrice() * (coupon.DiscountPercentage()/ 100M));
15 | return product.SellingPrice() - discount;
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/Patterns/TemplateMethod/LowIncomeBookPriceCalculator.cs:
--------------------------------------------------------------------------------
1 | namespace TemplateMethod
2 | {
3 | public class LowIncomeBookPriceCalculator : BookPriceCalculator
4 | {
5 | private readonly int _discount;
6 | public LowIncomeBookPriceCalculator(int discount)
7 | {
8 | _discount = discount;
9 | }
10 | protected override decimal ComputeTotalPriceBeforeTax(IBook books)
11 | {
12 | return books.Price - (books.Price * (_discount / 100.0M));
13 | }
14 | protected override decimal ApplyTax(decimal priceBeforeTax)
15 | {
16 | return priceBeforeTax;
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/Patterns/Builder/SkuCodeStartDiscountStrategy.cs:
--------------------------------------------------------------------------------
1 | namespace Builder
2 | {
3 | public class SkuCodeStartDiscountStrategy : IDiscountStrategy
4 | {
5 | public int DiscountInPercentage { get; set; }
6 | public string SkuCode { get; set; } = string.Empty;
7 | public decimal CalculateDiscountedRetailPrice(Product product)
8 | {
9 | if (!product.StockKeepingUnit.StartsWith(SkuCode))
10 | {
11 | return product.RegularRetailPrice;
12 | }
13 |
14 | return product.RegularRetailPrice - (DiscountInPercentage / 100m * product.RegularRetailPrice);
15 | }
16 |
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Patterns/SingletonDependencyInjection/LazyLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace SingletonDI
4 | {
5 | public sealed class LazyLogger
6 | {
7 | // Reference: CSharpInDepth using .Net4 Lazy
8 | // Implicitly uses LazyThreadSafetyMode.ExecutionAndPublication as the
9 | // thread safety mode for the Lazy
10 | private static readonly Lazy _lazyLogger = new Lazy(
11 | () => new Logger()
12 | );
13 | public static Logger Instance
14 | {
15 | get
16 | {
17 | return _lazyLogger.Value;
18 | }
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Patterns/Strategy/business_logic.txt:
--------------------------------------------------------------------------------
1 |
2 | User Story:
3 | As a store owner, I want to be able to compute for the correct
4 | discount per customer so that the dogmandu members get extra discounts.
5 |
6 |
7 | Business Logic:
8 | At the DogMandu Anniversary Sale shop, a discount coupon is provided
9 | to each customer (discount can be arbitrary). The discount has an added
10 | 5% if the customer is a dogmandu member.
11 | However, if a coupon is expired, despite
12 | being a member, no discount is given.
13 | Also, items already on sale are excluded
14 | from discounts for non members. Members however still get the
15 | discount on these items plus the base member discount of 5%.
16 |
17 |
--------------------------------------------------------------------------------
/Patterns/Adapter/SocialMediaProfileAdapter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Mail;
3 |
4 | namespace Adapter
5 | {
6 | public class SocialMediaProfileAdapter : IGoodReadsProfile
7 | {
8 | private readonly ISocialMediaProfile _socialMediaProfile;
9 | public SocialMediaProfileAdapter(ISocialMediaProfile? socialMediaProfile)
10 | {
11 | ArgumentNullException.ThrowIfNull(socialMediaProfile);
12 | _socialMediaProfile = socialMediaProfile;
13 | }
14 |
15 | public string Name { get { return _socialMediaProfile.Name; } }
16 |
17 | public MailAddress Email { get { return _socialMediaProfile.Email; } }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Patterns/Memento/ProductOriginator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Memento
4 | {
5 | public class ProductOriginator : IProductOriginator
6 | {
7 | private Product? _product;
8 |
9 | public ProductOriginator(Product product)
10 | {
11 | ArgumentNullException.ThrowIfNull(product);
12 | SetMemento(product);
13 | }
14 |
15 | public void SetMemento(Product product)
16 | {
17 | _product = product;
18 | }
19 |
20 | public Product GetMemento()
21 | {
22 | ArgumentNullException.ThrowIfNull(_product);
23 | return _product;
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Patterns/FactoryMethod/EarningBonusCalculatorRefactored.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FactoryMethod
4 | {
5 | public class EarningBonusCalculator
6 | {
7 | private readonly PerksFactory
8 | perksFactory;
9 |
10 | public EarningBonusCalculator(PerksFactory perksFactory)
11 | {
12 | this.perksFactory = perksFactory;
13 | }
14 | public int UpdatedMiles(int currentTotalMiles, int newMilesEarned)
15 | {
16 | var perks = perksFactory.GetPerks(currentTotalMiles);
17 | return currentTotalMiles + newMilesEarned + Convert.ToInt32(Math.Floor(newMilesEarned * perks?.EarningBonus() ?? 0));
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Patterns/Memento/ProductCaretaker.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace Memento
6 | {
7 | public class ProductCaretaker : IProductCaretaker
8 | {
9 | private IList productMementos = new List();
10 | public void AddProductMemento(Product product)
11 | {
12 | productMementos.Add(product.ShallowCopy());
13 | }
14 |
15 | public Product GetLastMemento()
16 | {
17 | var product = productMementos.DefaultIfEmpty(null).Last();
18 |
19 | ArgumentNullException.ThrowIfNull(product);
20 |
21 | return product;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Patterns/Proxy/Entries.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Proxy
4 | {
5 | public class Entries : IEntries
6 | {
7 | private Dictionary _products;
8 | public Entries(Dictionary products)
9 | {
10 | _products = products;
11 | }
12 |
13 | public bool Delete(int id)
14 | {
15 | return _products.Remove(id);
16 | }
17 | public IProductInfo? Get(int id)
18 | {
19 | if (!_products.ContainsKey(id))
20 | {
21 | return null;
22 | }
23 |
24 | return _products[id];
25 | }
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Patterns/Composite/BookComposite.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace Composite
6 | {
7 | public class BookComposite : IBook
8 | {
9 | private List _books;
10 | public decimal Price => _books.Select(book => book.Price).Sum();
11 | public string Name { get; private set; }
12 | public int Discount {get; private set;}
13 | public BookComposite(int discount, string name)
14 | {
15 | Discount = discount;
16 | Name = name;
17 | _books = new List();
18 | }
19 |
20 | public void Add(IBook book)
21 | {
22 | _books.Add(book);
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/Patterns/ChainOfResponsibility/CreditCardHandlerBase.cs:
--------------------------------------------------------------------------------
1 | namespace ChainOfResponsibility
2 | {
3 | public abstract class CreditCardHandlerBase : ICreditCardHandler
4 | {
5 | private ICreditCardHandler? nextCreditCardHandler;
6 | public ICreditCardHandler SetNext(ICreditCardHandler creditCardHandler)
7 | {
8 | nextCreditCardHandler = creditCardHandler;
9 | return creditCardHandler;
10 | }
11 |
12 | public virtual bool IsCreditCardValid(ICreditCard card)
13 | {
14 | if (nextCreditCardHandler != null)
15 | {
16 | return nextCreditCardHandler.IsCreditCardValid(card);
17 | }
18 |
19 | return false;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Patterns/Observer/SpecialsSubject.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Observer
4 | {
5 | public class SpecialsSubject : ISubject
6 | {
7 | public delegate void Callback(string s);
8 | public required string SubjectState { get; set; }
9 |
10 | private readonly List _observers = [];
11 |
12 | public void Attach(IObserver observer)
13 | {
14 | _observers.Add(observer);
15 | }
16 |
17 | public void Detach(IObserver observer)
18 | {
19 | _observers.Remove(observer);
20 | }
21 |
22 | public void Notify()
23 | {
24 | _observers.ForEach(observer => observer.Update(this));
25 | }
26 |
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Patterns/ChainOfResponsibility/AmexCardHandler.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace ChainOfResponsibility
3 | {
4 | public class AmexCardHandler : CreditCardHandlerBase
5 | {
6 | private IPaymentGateway paymentGateway;
7 | private const string AmexCardStartingNumber = "3";
8 | public AmexCardHandler(IPaymentGateway paymentGateway)
9 | {
10 | this.paymentGateway = paymentGateway;
11 | }
12 |
13 | public override bool IsCreditCardValid(ICreditCard card)
14 | {
15 | if (card.Number.StartsWith(AmexCardStartingNumber))
16 | {
17 | return paymentGateway.SubmitVerification(this, card);
18 | }
19 |
20 | return base.IsCreditCardValid(card);
21 | }
22 |
23 | }
24 | }
--------------------------------------------------------------------------------
/Patterns/ChainOfResponsibility/VisaCardHandler.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace ChainOfResponsibility
3 | {
4 | public class VisaCardHandler : CreditCardHandlerBase
5 | {
6 | private IPaymentGateway paymentGateway;
7 | private const string VisaCardStartingNumber = "4";
8 | public VisaCardHandler(IPaymentGateway paymentGateway)
9 | {
10 | this.paymentGateway = paymentGateway;
11 | }
12 |
13 | public override bool IsCreditCardValid(ICreditCard card)
14 | {
15 | if (card.Number.StartsWith(VisaCardStartingNumber))
16 | {
17 | return paymentGateway.SubmitVerification(this, card);
18 | }
19 |
20 | return base.IsCreditCardValid(card);
21 | }
22 |
23 | }
24 | }
--------------------------------------------------------------------------------
/Patterns/ChainOfResponsibility/MastercardHandler.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace ChainOfResponsibility
3 | {
4 | public class MastercardHandler : CreditCardHandlerBase
5 | {
6 | private IPaymentGateway paymentGateway;
7 | private const string MasterCardStartingNumber = "5";
8 | public MastercardHandler(IPaymentGateway paymentGateway)
9 | {
10 | this.paymentGateway = paymentGateway;
11 | }
12 |
13 | public override bool IsCreditCardValid(ICreditCard card)
14 | {
15 | if (card.Number.StartsWith(MasterCardStartingNumber))
16 | {
17 | return paymentGateway.SubmitVerification(this, card);
18 | }
19 |
20 | return base.IsCreditCardValid(card);
21 | }
22 |
23 | }
24 | }
--------------------------------------------------------------------------------
/Patterns/TemplateMethod/HighIncomeBookPriceCalculator.cs:
--------------------------------------------------------------------------------
1 | namespace TemplateMethod
2 | {
3 | public class HighIncomeBookPriceCalculator : BookPriceCalculator
4 | {
5 | private static readonly int MTaxPercentage = 12;
6 | private readonly int _discount;
7 | public HighIncomeBookPriceCalculator(int discountPercentage)
8 | {
9 | _discount = discountPercentage;
10 | }
11 | protected override decimal ComputeTotalPriceBeforeTax(IBook books)
12 | {
13 | return books.Price - (books.Price * (_discount / 100.0M));
14 | }
15 | protected override decimal ApplyTax(decimal priceBeforeTax)
16 | {
17 | return priceBeforeTax + (priceBeforeTax * (MTaxPercentage / 100.0M));
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/Patterns/Command/ProductCommandInvoker.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Command
4 | {
5 | public class ProductCommandInvoker : IInvoker
6 | {
7 | private Dictionary _commands;
8 |
9 | public ProductCommandInvoker()
10 | {
11 | _commands = new Dictionary();
12 | }
13 |
14 | public bool AddCommand(string key, ICommand command)
15 | {
16 | if (_commands.ContainsKey(key))
17 | {
18 | return false;
19 | }
20 | _commands[key] = command;
21 | return true;
22 | }
23 |
24 | public void InvokeCommand(string key)
25 | {
26 | _commands[key].Execute();
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Patterns/FactoryMethod/EarningBonusCalculatorLegacy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FactoryMethod
4 | {
5 | public class EarningBonusCalculatorLegacy
6 | {
7 | public int UpdatedMiles(int currentTotalMiles, int newMilesEarned)
8 | {
9 | if (currentTotalMiles >= 20000)
10 | {
11 | return currentTotalMiles + newMilesEarned + Convert.ToInt32(Math.Floor(newMilesEarned * 1.0));
12 | }
13 | else if (currentTotalMiles >= 10000)
14 | {
15 | return currentTotalMiles + newMilesEarned + Convert.ToInt32(Math.Floor(newMilesEarned * 0.5));
16 | }
17 | else
18 | {
19 | return currentTotalMiles + newMilesEarned;
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Patterns/Proxy/EntriesProxy.cs:
--------------------------------------------------------------------------------
1 | namespace Proxy
2 | {
3 | public class EntriesProxy : IEntries
4 | {
5 | private IAuthenticationController _authCtrl;
6 | private IEntries _realEntries;
7 | public EntriesProxy(IAuthenticationController authCtrl, IEntries realEntries)
8 | {
9 | _authCtrl = authCtrl;
10 | _realEntries = realEntries;
11 | }
12 |
13 | public bool Delete(int id)
14 | {
15 | var result = false;
16 | if (_authCtrl.IsAdmin())
17 | {
18 | result = _realEntries.Delete(id);
19 | }
20 | return result;
21 | }
22 | public IProductInfo? Get(int id)
23 | {
24 | return _realEntries?.Get(id) ?? null;
25 | }
26 |
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Patterns/Strategy/MemberDiscountScheme.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 |
4 | namespace Strategy
5 | {
6 | public class MemberDiscountScheme : IDiscountScheme
7 | {
8 | struct Discount
9 | {
10 | public const int BaseMemberDiscount = 5;
11 | }
12 |
13 | public decimal ComputePrice(IProduct product, ICoupon coupon)
14 | {
15 | var memberBaseDiscount = product.SellingPrice() * (Discount.BaseMemberDiscount / 100M);
16 | var memberDiscountedPrice = product.SellingPrice() - memberBaseDiscount;
17 | if (coupon.IsExpired())
18 | {
19 | return memberDiscountedPrice;
20 | }
21 |
22 | return memberDiscountedPrice - (product.SellingPrice() * (coupon.DiscountPercentage()/ 100M));
23 | }
24 |
25 | }
26 | }
--------------------------------------------------------------------------------
/Patterns/Flyweight/XmlTextBlobFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Flyweight
5 | {
6 | public class XmlTextBlobFactory : TextBlobFactory
7 | {
8 | private Dictionary textBlobDictionary = new Dictionary();
9 | private TextDownloader textDownloader;
10 | public XmlTextBlobFactory(TextDownloader textDownloader)
11 | {
12 | this.textDownloader = textDownloader;
13 | }
14 |
15 | public TextBlob GetTextBlob(int id)
16 | {
17 | if (textBlobDictionary.ContainsKey(id))
18 | {
19 | return textBlobDictionary[id];
20 | }
21 |
22 | var textBlob = new XmlTextBlob(textDownloader);
23 | textBlobDictionary[id] = textBlob;
24 | return textBlob;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Patterns/Builder/DiscountStrategyBuilder.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace Builder
3 | {
4 | public abstract class DiscountStrategyBuilder
5 | {
6 | private IDiscountStrategy _discountStrategy;
7 |
8 | public DiscountStrategyBuilder(IDiscountStrategy discountStrategy)
9 | {
10 | _discountStrategy = discountStrategy;
11 | }
12 |
13 | public DiscountStrategyBuilder ApplicableToSKUCode(string skuCode)
14 | {
15 | _discountStrategy.SkuCode = skuCode;
16 | return this;
17 | }
18 |
19 | public DiscountStrategyBuilder WithDiscountInPercentage(int discountInPercentage)
20 | {
21 | _discountStrategy.DiscountInPercentage = discountInPercentage;
22 | return this;
23 | }
24 | public IDiscountStrategy Build()
25 | {
26 | return _discountStrategy;
27 | }
28 |
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Patterns/Iterator/NumberMatrix.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 |
3 | namespace Iterator
4 | {
5 | public class NumberMatrix : AggregateObject, IMatrix
6 | {
7 | private int[,] _data;
8 | public MatrixDirection IteratorDirection { get; set; }
9 |
10 | public int TotalRows() => _data.GetLength(0);
11 | public int TotalColumns() => _data.GetLength(1);
12 |
13 | public NumberMatrix(MatrixDirection iteratorDirection, int width, int height)
14 | {
15 | _data = new int[width, height];
16 | IteratorDirection = iteratorDirection;
17 | }
18 |
19 | public int this[int row, int column]
20 | {
21 | get { return _data[row, column]; }
22 | set { _data[row, column] = value; }
23 | }
24 |
25 | public override IEnumerator GetEnumerator()
26 | {
27 | return new MatrixIterator(this, IteratorDirection);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Patterns/Mediator/PurchaseMediator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 |
5 | namespace Mediator
6 | {
7 | public class PurchaseMediator : IMediator
8 | {
9 | private List _activePurchasers;
10 |
11 | public PurchaseMediator()
12 | {
13 | _activePurchasers = new List();
14 | }
15 | public bool BroadcastPurchaseCompletion(IPurchaser purchaser)
16 | {
17 | var isPurchaserActive = _activePurchasers.Remove(purchaser);
18 |
19 | if (isPurchaserActive)
20 | {
21 | _activePurchasers.ForEach(p => p.Receive(purchaser));
22 | }
23 |
24 | return isPurchaserActive;
25 | }
26 | public bool AddPurchaser(IPurchaser purchaser)
27 | {
28 | if (_activePurchasers.Contains(purchaser) == false)
29 | {
30 | _activePurchasers.Add(purchaser);
31 | return true;
32 | }
33 |
34 | return false;
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Dean Agan
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 |
--------------------------------------------------------------------------------
/Tests/TemplateMethodTest.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 | using Moq;
3 | using FluentAssertions;
4 |
5 | namespace TemplateMethod.Test
6 | {
7 | public class TemplateMethodShould
8 | {
9 | [Fact]
10 | public void ApplyTaxes_WhenBuyerIsHighIncomeEarner()
11 | {
12 | // Arrange
13 | var highIncomeBuyer = new HighIncomeBookPriceCalculator(5);
14 | var book = Mock.Of(book => book.Price == 100.0M);
15 |
16 | // Act
17 | var priceAfterTax = highIncomeBuyer.CalculatePrice(book);
18 |
19 | // Assert
20 | priceAfterTax.Should().Be(106.4M);
21 | }
22 |
23 | [Fact]
24 | public void NotApplyTaxes_WhenBuyerIsLowIncomeEarner()
25 | {
26 | // Arrange
27 | var lowIncomeBuyer = new LowIncomeBookPriceCalculator(5);
28 | var book = Mock.Of(book => book.Price == 100.0M);
29 |
30 | // Act
31 | var priceAfterTax = lowIncomeBuyer.CalculatePrice(book);
32 |
33 | // Assert
34 | priceAfterTax.Should().Be(95.0M);
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a .NET project
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
3 |
4 | name: .NET
5 |
6 | on:
7 | push:
8 | branches: [ "master" ]
9 | pull_request:
10 | branches: [ "master" ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v4
19 | - name: Setup .NET
20 | uses: actions/setup-dotnet@v4
21 | with:
22 | dotnet-version: 8.0.x
23 | - name: Restore dependencies
24 | run: dotnet restore
25 | - name: Build
26 | run: dotnet build --no-restore
27 | - name: Test
28 | run: dotnet test --no-build --verbosity normal
29 | - name: Generate coverage report
30 | run: |
31 | cd ./Tests
32 | dotnet test /p:CollectCoverage=true /p:CoverletOutput=TestResults/ /p:CoverletOutputFormat=lcov
33 | - name: Publish coverage report to coveralls.io
34 | uses: coverallsapp/github-action@master
35 | with:
36 | github-token: ${{ secrets.GITHUB_TOKEN }}
37 | path-to-lcov: ./Tests/TestResults/coverage.info
38 |
--------------------------------------------------------------------------------
/Patterns/FactoryMethod/PerksFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace FactoryMethod
6 | {
7 | public class PerksFactory
8 | {
9 | private readonly List<(int, string)> thresholds;
10 | private const string DEFAULT_PERKS_TYPE = "BasicPerks";
11 |
12 | public PerksFactory(List<(int, string)> thresholds)
13 | {
14 | this.thresholds = thresholds;
15 | }
16 | public IPerks? GetPerks(int totalMiles)
17 | {
18 | var perks = thresholds.Where(th => totalMiles >= th.Item1)
19 | .Select(p => p.Item2)
20 | .DefaultIfEmpty("BasicPerks")
21 | .First();
22 |
23 | var fullyQualifiedPerksName = $"FactoryMethod.{perks}";
24 |
25 | var perksType = Type.GetType(fullyQualifiedPerksName);
26 |
27 | if (perksType == null)
28 | {
29 | return null;
30 | }
31 |
32 | return (IPerks?)Activator.CreateInstance(perksType);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Patterns/Facade/business_logic.txt:
--------------------------------------------------------------------------------
1 | User Story: As a customer, I want to be able to pay for my purchases in a secure way.
2 |
3 | We are integrating a payment gateway into our site. The task for this is to implement
4 | a way to pay securely using an SDK.
5 |
6 | In using the payment gateway SDK, these are the following steps:
7 |
8 | 1. IEnvironment - Set the environment. Assume step to either be SANDBOX or PRODUCTION.
9 | 2. IMerchantAuthenticationType - Assume interface requires login id and transaction key.
10 | 3. IBillingAddress - A billing address type. Require first name, last name, address, city and zip code.
11 | 3. ICreditCard - Can be a visa, mastercard or amex credit card. Must implement typename, account number, cvc and expiry date.
12 | 4. ITransactionRequest - Requires amount in decimal, IBillingAddress and ICreditCardType supplied.
13 | 5. ITransactionController - Requires an ITransactionRequest, an Execute function and a GetApiResponse function.
14 | The GetApiResponse function returns either OK or Declined.
15 | - Decline if
16 | + Environment not Set
17 | + Merchant authentication not set.
18 | + ICreditCardType has expired date.
19 | - Otherwise, returns OK.
--------------------------------------------------------------------------------
/Patterns/Facade/PaymentProcessor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Facade
4 | {
5 | public class PaymentProcessor : IPaymentProcessor
6 | {
7 | private readonly IEnvironment _environment;
8 | private readonly IMerchantAuthenticationType _merchAuthType;
9 | private readonly ITransactionController _txnCtrl;
10 | public PaymentProcessor(
11 | IEnvironment environment,
12 | IMerchantAuthenticationType merchAuthType,
13 | ITransactionController txnCtrl)
14 | {
15 | // TODO: Add data invariance. Use contracts?
16 | _environment = environment;
17 | _merchAuthType = merchAuthType;
18 | _txnCtrl = txnCtrl;
19 | }
20 | public void InitializePaymentGatewayInterface()
21 | {
22 | _environment.environmentVariableTarget = EnvironmentTarget.SANDBOX;
23 | _merchAuthType.TransactionKey = "transaction_key";
24 | _merchAuthType.LoginID = "login_id";
25 | }
26 | public bool SubmitPayment()
27 | {
28 | _txnCtrl.Execute();
29 | var t = _txnCtrl.GetApiResponse() == TransactionResponseType.OK;
30 | return t;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Patterns/Mediator/Purchaser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Mediator
4 | {
5 | public class Purchaser : IPurchaser
6 | {
7 | public string ItemBought { get; private set; } = string.Empty;
8 | public string Location { get; private set; } = string.Empty;
9 | private Product? _product;
10 | private IAlertScreen _alertScreen;
11 | private IMediator _mediator;
12 |
13 | public Purchaser(IAlertScreen? alertScreen, IMediator? mediator)
14 | {
15 | ArgumentNullException.ThrowIfNull(alertScreen);
16 | ArgumentNullException.ThrowIfNull(mediator);
17 |
18 | _alertScreen = alertScreen;
19 | _mediator = mediator;
20 | }
21 |
22 | public void Receive(IPurchaser purchaser)
23 | {
24 | var product = purchaser.GetProduct();
25 | if (product != null)
26 | {
27 | _alertScreen.ShowMessage(product.Item, product.Location);
28 | }
29 | }
30 |
31 | public void Complete(Product product)
32 | {
33 | _product = product;
34 | _mediator.BroadcastPurchaseCompletion(this);
35 | }
36 |
37 | public Product? GetProduct()
38 | {
39 | return _product;
40 | }
41 | }
42 | }
--------------------------------------------------------------------------------
/Tests/FlyweightTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Xunit;
3 | using Moq;
4 | using FluentAssertions;
5 |
6 | namespace Flyweight.Test
7 | {
8 | public class FlyweightShould
9 | {
10 | private TextDownloader _textDownloader;
11 | public FlyweightShould()
12 | {
13 | this._textDownloader = Mock.Of();
14 | }
15 | [Fact]
16 | public void NotRecreateObject_WhenObjectIsSame()
17 | {
18 | // Arrange
19 | var xmlTextBlob = new XmlTextBlobFactory(this._textDownloader);
20 |
21 | // Act
22 | var blob1 = xmlTextBlob.GetTextBlob(1);
23 | var blob2 = xmlTextBlob.GetTextBlob(1);
24 |
25 | // Assert
26 | blob1.GetHashCode().Should().Be(blob2.GetHashCode());
27 | }
28 |
29 | [Fact]
30 | public void InvokeMatchingId_WhenXmlTextBlobDownloadInvoked()
31 | {
32 | // Arrange
33 | var xmlTextBlob = new XmlTextBlobFactory(this._textDownloader);
34 | var blob = xmlTextBlob.GetTextBlob(1);
35 | // Act
36 | blob.Download(1, "Hello");
37 | // Assert
38 | Mock.Get(_textDownloader).Verify(td => td.DownloadFile($"https://localhost:5001/api/getitem/1", It.IsAny()));
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Patterns/State/Coupon.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace State
5 | {
6 | public class Coupon : ICoupon
7 | {
8 | private int _discount;
9 | private ICouponState _currentState;
10 | private DateTime _expiry;
11 |
12 | public Coupon(int discount, DateTime expiry)
13 | {
14 | if (expiry < DateTime.Today)
15 | {
16 | throw new ArgumentException("Coupon must be constructed with valid expiry date");
17 | }
18 | _expiry = expiry;
19 | _discount = discount;
20 | // Because coupon states are internal, we will
21 | // couple them with the specific states so they
22 | // are highly cohesive. For this implementation,
23 | // we will construct on state change.
24 | _currentState = new ValidCouponState();
25 | }
26 |
27 | public void SetCouponState(ICouponState state)
28 | {
29 | _currentState = state;
30 | }
31 |
32 | public void UpdateExpiryDate(DateTime dateTime)
33 | {
34 | _currentState.ChangeExpiryDate(dateTime, this);
35 | }
36 |
37 | public decimal ApplyDiscountTo(IProduct product)
38 | {
39 | var price = product.Price;
40 | return _currentState.UseDiscount() ? price - (price * (_discount/100.0M)) : price;
41 | }
42 | }
43 |
44 | }
--------------------------------------------------------------------------------
/Tests/StateTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Xunit;
3 | using Moq;
4 | using FluentAssertions;
5 |
6 | namespace State.Test
7 | {
8 | public class StateShould
9 | {
10 | private readonly IProduct _product = Mock.Of ( p => p.Price == 100.0M);
11 | [Fact]
12 | public void ReturnDiscountedProductPrice_WhenCoupon_IsValid()
13 | {
14 | // Arrange
15 | var expiry = DateTime.Today.AddDays(2);
16 | var coupon = new Coupon(5, expiry);
17 | // Act
18 | var price = coupon.ApplyDiscountTo(_product);
19 | // Assert
20 | price.Should().Be(95.0M);
21 | }
22 |
23 | [Fact]
24 | public void ReturnSameProductPrice_WhenCouponIsExpired()
25 | {
26 | // Arrange
27 | var expiry = DateTime.Today.AddDays(2);
28 | var coupon = new Coupon(5, expiry);
29 | coupon.UpdateExpiryDate(expiry.AddDays(-4));
30 | // Act
31 | var price = coupon.ApplyDiscountTo(_product);
32 | // Assert
33 | price.Should().Be(100.0M);
34 | }
35 |
36 | [Fact]
37 | public void ThrowArgumentException_WhenCouponConstructedAsExpired()
38 | {
39 | // Arrange
40 | var expiry = DateTime.Today.AddDays(-2);
41 | // Act
42 | Action act = () => new Coupon(5, expiry);
43 | // Assert
44 | act.Should().ThrowExactly();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Tests/AdapterTest.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Xunit;
3 | using Moq;
4 | using FluentAssertions;
5 | using AutoFixture;
6 | using System.Net.Mail;
7 |
8 | namespace Adapter.Tests
9 | {
10 | public class AdapterShould
11 | {
12 | private readonly Fixture _fixture = new();
13 |
14 | [Fact]
15 | public void Return_SocialMediaProfileContent_WhenAccessingViaAdapter()
16 | {
17 | // Arrange
18 | var mockSocialMediaProfile = Mock.Of(msmp => msmp.Name == _fixture.Create() &&
19 | msmp.UserName == _fixture.Create() &&
20 | msmp.Email == _fixture.Create());
21 |
22 | // Act
23 | var goodReadsProfile = new SocialMediaProfileAdapter(mockSocialMediaProfile);
24 |
25 | // Assert
26 | using (new FluentAssertions.Execution.AssertionScope("profile"))
27 | {
28 | goodReadsProfile.Name.Should().Be(mockSocialMediaProfile.Name);
29 | goodReadsProfile.Email.Should().Be(mockSocialMediaProfile.Email);
30 | }
31 |
32 | }
33 |
34 | [Fact]
35 | public void ThrowException_WhenSocialMediaAdapteeIsNull()
36 | {
37 | // Act
38 | Action act = () => new SocialMediaProfileAdapter(null);
39 |
40 | // Assert
41 | act.Should().ThrowExactly();
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Tests/SingletonDITest.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 | using Moq;
3 | using FluentAssertions;
4 | using Ninject;
5 |
6 | namespace SingletonDI.Test
7 | {
8 | public class SingletonDIShould
9 | {
10 |
11 | [Fact]
12 | public void ReturnSameInstance_WhenComparingLazyLoggerSingleton()
13 | {
14 | // Arrange
15 | var logger1 = LazyLogger.Instance;
16 | // Act
17 | var logger2 = LazyLogger.Instance;
18 | // Assert
19 | logger1.Should().BeSameAs(logger2);
20 | }
21 |
22 | [Fact]
23 | public void ReturnDifferentInstance_WhenComparingInstanceCreatedByNinjectInTransientScope()
24 | {
25 | // Arrange
26 | var container = new StandardKernel();
27 | container.Bind().To();
28 | // Act
29 | var logger1 = container.Get();
30 | var logger2 = container.Get();
31 | // Assert
32 | logger1.Should().NotBeSameAs(logger2);
33 | }
34 |
35 | [Fact]
36 | public void ReturnSameInstance_WhenComparingInstanceCreatedByNinjectInSingletonScope()
37 | {
38 | // Arrange
39 | var container = new StandardKernel();
40 | container.Bind().To().InSingletonScope();
41 | // Act
42 | var logger1 = container.Get();
43 | var logger2 = container.Get();
44 | // Assert
45 | logger1.Should().BeSameAs(logger2);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Tests/BridgeTest.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Xunit;
3 | using Moq;
4 | using FluentAssertions;
5 |
6 | namespace Bridge.Test
7 | {
8 | public class BridgeShould
9 | {
10 | private readonly IPaymentGateway _mPaymentGateway;
11 |
12 | public BridgeShould()
13 | {
14 | _mPaymentGateway = Mock.Of();
15 | }
16 |
17 | public delegate IPayment PaymentMethodCreator(IPaymentGateway gateway);
18 |
19 | public static IEnumerable