Add code examples, and documentation

This commit is contained in:
Aaron Po
2026-08-12 00:03:32 -04:00
commit 77c16e69f6
79 changed files with 4458 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
namespace Bridge_Example;
//This is one of the refined abstraction classes. Note that it can make use of _sender since it inherits it from its superclass. Note also that since EmailSender and SmsSender implement IMessageSender, their specific SendMessage() method will be called, depending on what's passed into the constructor (see the main method)
public class AlertNotification : Notification
{
public AlertNotification(IMessageSender sender)
: base(sender) { }
public override void Notify(string message)
{
_sender.SendMessage($"ALERT: {message}");
}
}

View File

@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>Bridge_Example</RootNamespace>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,16 @@
#region
using System;
#endregion
namespace Bridge_Example;
//This is one of the concrete implementors, which implements the implementor interface IMessageSender
public class EmailSender : IMessageSender
{
public void SendMessage(string message)
{
Console.WriteLine($"Email sent: {message}");
}
}

View File

@@ -0,0 +1,7 @@
namespace Bridge_Example;
//This class is the implementor. It gets implemented by concrete classes.
public interface IMessageSender
{
void SendMessage(string message);
}

View File

@@ -0,0 +1,14 @@
namespace Bridge_Example;
//This is the abstraction
public abstract class Notification
{
protected readonly IMessageSender _sender;
protected Notification(IMessageSender sender)
{
_sender = sender;
}
public abstract void Notify(string message);
}

View File

@@ -0,0 +1,17 @@
namespace Bridge_Example;
internal class Program
{
private static void Main(string[] args)
{
Notification n1 = new AlertNotification(new EmailSender());
Notification n2 = new AlertNotification(new SmsSender());
Notification n3 = new ReminderNotification(new EmailSender());
Notification n4 = new ReminderNotification(new SmsSender());
n1.Notify("Server is down");
n2.Notify("Server is down");
n3.Notify("Meeting at 3pm");
n4.Notify("Meeting at 3pm");
}
}

View File

@@ -0,0 +1,13 @@
namespace Bridge_Example;
//This is one of the refined abstraction classes. Note that it can make use of _sender since it inherits it from its superclass. Note also that since EmailSender and SmsSender implement IMessageSender, their specific SendMessage() method will be called, depending on what's passed into the constructor (see the main method)
public class ReminderNotification : Notification
{
public ReminderNotification(IMessageSender sender)
: base(sender) { }
public override void Notify(string message)
{
_sender.SendMessage($"Reminder: {message}");
}
}

View File

@@ -0,0 +1,16 @@
#region
using System;
#endregion
namespace Bridge_Example;
//This is another concrete implementor class, which implements the implementor interface IMessageSender
public class SmsSender : IMessageSender
{
public void SendMessage(string message)
{
Console.WriteLine($"SMS sent: {message}");
}
}

View File

@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,102 @@
public interface IIceCream
{
void Prepare();
decimal GetPrice();
}
public class ChocolateIceCream : IIceCream
{
public void Prepare()
{
Console.WriteLine("Preparing a chocolate ice cream.");
}
public decimal GetPrice()
{
return 2.50m; // base price for chocolate ice cream
}
}
public class VanillaIceCream : IIceCream
{
public void Prepare()
{
Console.WriteLine("Preparing a vanilla ice cream.");
}
public decimal GetPrice()
{
return 2.00m; // base price for vanilla ice cream
}
}
public abstract class IceCreamDecorator(IIceCream decorated) : IIceCream
{
protected IIceCream _decorated = decorated;
public abstract void Prepare();
public abstract decimal GetPrice();
}
public class SprinkleDecorator(IIceCream decorated)
: IceCreamDecorator(decorated)
{
public override void Prepare()
{
// call the base first
_decorated.Prepare();
Console.WriteLine("Adding sprinkles!");
}
public override decimal GetPrice()
{
return _decorated.GetPrice() + 0.50m; // add price for sprinkles
}
}
public class ChocolateSyrupDecorator(IIceCream decorated)
: IceCreamDecorator(decorated)
{
public override void Prepare()
{
// call the base prepare first
_decorated.Prepare();
Console.WriteLine("Adding chocolate syrup!");
}
public override decimal GetPrice()
{
return _decorated.GetPrice() + 0.75m; // add price for chocolate syrup
}
}
public class CaramelSyrupDecorator(IIceCream decorated)
: IceCreamDecorator(decorated)
{
public override void Prepare()
{
// call the base prepare first
_decorated.Prepare();
Console.WriteLine("Adding caramel syrup!");
}
public override decimal GetPrice()
{
return _decorated.GetPrice() + 0.75m; // add price for caramel syrup
}
}
internal class Program
{
static void Main(string[] args)
{
decimal price = new CaramelSyrupDecorator(
new ChocolateSyrupDecorator(
new SprinkleDecorator(
new ChocolateIceCream()
)
)
).GetPrice();
Console.WriteLine($"Total price: {price:C}");
}
}

View File

@@ -0,0 +1,66 @@
#region
using System;
using ShapeDecorations.Shapes;
using ShapeDecorations.Shapes.Decorators;
#endregion
namespace ShapeDecorations;
internal class Program
{
private static void Main(string[] args)
{
// scoped to allow for re-use of variable names
{
// First create a concrete shape, since we need one to be able to decorate anything
var circle = new Circle();
circle.Draw();
Console.WriteLine();
// Now we decorate the shape with a red color
var red = new RedColor(circle);
red.Draw();
Console.WriteLine();
// Since the decorator itself is an IShape, we can further decorate it
var blueBorder = new BlueBorder(red);
blueBorder.Draw();
Console.WriteLine();
// And can continue to decorate each ShapeDecorator with as many decorator classes as we like
var huge = new HugeSize(blueBorder);
huge.Draw();
Console.WriteLine();
}
{
// Always must start with a concrete IShape implementation
var rect = new Rectangle();
rect.Draw();
Console.WriteLine();
// Note that the order in which we decorate doesn't matter
var blueBorder = new BlueBorder(rect);
blueBorder.Draw();
Console.WriteLine();
var huge = new HugeSize(blueBorder);
huge.Draw();
Console.WriteLine();
var red = new RedColor(huge);
red.Draw();
Console.WriteLine();
}
}
}

View File

@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>ShapeDecorations</RootNamespace>
<AssemblyName>ShapeDecorations</AssemblyName>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,15 @@
#region
using System;
#endregion
namespace ShapeDecorations.Shapes;
public class Circle : IShape
{
public void Draw()
{
Console.WriteLine("Drawing a circle");
}
}

View File

@@ -0,0 +1,25 @@
#region
using System;
#endregion
namespace ShapeDecorations.Shapes.Decorators;
/// <summary>
/// See the RedColor class for details on the implementation
/// </summary>
public class BlueBorder : ShapeDecorator
{
/// <summary>
/// See the RedColor class for details on the implementation
/// </summary>
public BlueBorder(IShape decorated)
: base(decorated) { }
public override void Draw()
{
_decorated.Draw();
Console.WriteLine("\tWith a blue border");
}
}

View File

@@ -0,0 +1,26 @@
#region
using System;
#endregion
namespace ShapeDecorations.Shapes.Decorators;
public class HugeSize : ShapeDecorator
{
/// <summary>
/// See the RedColor class for details on the implementation
/// </summary>
/// <param name="decorated">
/// The IShape (whtether concrete IShape or concrete
/// ShapeDecorator) to be decorated
/// </param>
public HugeSize(IShape decorated)
: base(decorated) { }
public override void Draw()
{
_decorated.Draw();
Console.WriteLine("\tThat is enourmous in size");
}
}

View File

@@ -0,0 +1,32 @@
#region
using System;
#endregion
namespace ShapeDecorations.Shapes.Decorators;
public class RedColor : ShapeDecorator
{
/// <summary>
/// Public ctor. Calls the base class with the passed IShape, thus decorating
/// it.
/// Implementation is left empty, as the base class does all the work needed.
/// </summary>
/// <param name="decorated"></param>
public RedColor(IShape decorated)
: base(decorated) { }
/// <summary>
/// Performs the actual drawing logic, but first calls the decorated member,
/// adding its own logic afterwards.
/// </summary>
public override void Draw()
{
// First calls decorated member
_decorated.Draw();
// Then adds additional drawing logic
Console.WriteLine("\tWhich is red in color");
}
}

View File

@@ -0,0 +1,33 @@
namespace ShapeDecorations.Shapes.Decorators;
public abstract class ShapeDecorator : IShape
{
/// <summary>
/// Maintains a reference to the shape which it decorates
/// this allows implementors to add additional steps to the "drawing" process.
/// Marked "protected" so that inheriting classes have access to it.
/// </summary
protected IShape _decorated;
/// <summary>
/// Acceps a reference to any IShape.
/// Since the ShapeDecorator itself IS an IShape, this
/// decorator can also decorate other decorators
/// However, since a ShapeDecorator has to be instantiated with an existing
/// IShape,
/// at some point in the chain of decoration, there must be a concrete shape
/// (specifically, a concrete IShape that was createad without having another
/// IShape passed to it)
/// </summary>
/// <param name="decorated"></param>
public ShapeDecorator(IShape decorated)
{
_decorated = decorated;
}
/// <summary>
/// Marking this abstract satisfies the implementation of IShape,
/// but forces inheriting classes to implement their own drawing logic
/// </summary>
public abstract void Draw();
}

View File

@@ -0,0 +1,6 @@
namespace ShapeDecorations.Shapes;
public interface IShape
{
void Draw();
}

View File

@@ -0,0 +1,15 @@
#region
using System;
#endregion
namespace ShapeDecorations.Shapes;
public class Rectangle : IShape
{
public void Draw()
{
Console.WriteLine("Drawing a Rectangle");
}
}

View File

@@ -0,0 +1,14 @@
namespace CarEngineFacade;
public class AirFlowController
{
public void TakeAir()
{
// implementation
}
public void Off()
{
// implementation
}
}

View File

@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>CarEngineFacade</RootNamespace>
<AssemblyName>CarEngineFacade</AssemblyName>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,14 @@
namespace CarEngineFacade;
public class CatalyticConverter
{
public void On()
{
// implementation
}
public void Off()
{
// implementation
}
}

View File

@@ -0,0 +1,19 @@
namespace CarEngineFacade;
public class CoolingController
{
public void Run()
{
// implementation
}
public void Stop()
{
// implementation
}
public void Cool()
{
// implementation
}
}

View File

@@ -0,0 +1,29 @@
namespace CarEngineFacade;
public class Facade
{
private readonly AirFlowController _air = new();
private readonly CatalyticConverter _cat = new();
private readonly CoolingController _cool = new();
private readonly FuelInjector _fuel = new();
private readonly Starter _start = new();
public void Start()
{
_air.TakeAir();
_fuel.On();
_fuel.Inject();
_start.Start();
_cool.Run();
_cat.On();
}
public void Stop()
{
_fuel.Off();
_cat.Off();
_cool.Cool();
_cool.Stop();
_air.Off();
}
}

View File

@@ -0,0 +1,19 @@
namespace CarEngineFacade;
public class FuelInjector
{
public void On()
{
// implementation
}
public void Inject()
{
// implementation
}
public void Off()
{
// implementation
}
}

View File

@@ -0,0 +1,38 @@
namespace CarEngineFacade;
internal class Program
{
private static void Main(string[] args)
{
//// without the facade, starting the engine involves creating all the objects
//var airflow = new AirFlowController();
//var fuel = new FuelInjector();
//var start = new Starter();
//var cool = new CoolingController();
//var cat = new CatalyticConverter();
//// then performing all the steps in the correct order
//airflow.TakeAir();
//fuel.On();
//fuel.Inject();
//start.Start();
//cool.Run();
//cat.On();
//// and shut down also requires steps in the correct order
//fuel.Off();
//cat.Off();
//cool.Cool();
//cool.Stop();
//airflow.Off();
// with the Facade, all creation is handled internally
var facade = new Facade();
// as is starting
facade.Start();
// and stopping
facade.Stop();
}
}

View File

@@ -0,0 +1,9 @@
namespace CarEngineFacade;
public class Starter
{
public void Start()
{
// implementation
}
}

View File

@@ -0,0 +1,14 @@
namespace CarEngineFacadeRecording;
public class AirFlowController
{
public void TakeAir()
{
// implementation
}
public void Off()
{
// implementation
}
}

View File

@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,14 @@
namespace CarEngineFacadeRecording;
public class CatalyticConverter
{
public void On()
{
// implementation
}
public void Off()
{
// implementation
}
}

View File

@@ -0,0 +1,19 @@
namespace CarEngineFacadeRecording;
public class CoolingController
{
public void Run()
{
// implementation
}
public void Stop()
{
// implementation
}
public void Cool()
{
// implementation
}
}

View File

@@ -0,0 +1,29 @@
namespace CarEngineFacadeRecording;
public class Facade
{
private readonly AirFlowController _air = new();
private readonly CatalyticConverter _cat = new();
private readonly CoolingController _cool = new();
private readonly FuelInjector _fuel = new();
private readonly Starter _start = new();
public void Start()
{
_air.TakeAir();
_fuel.On();
_fuel.Inject();
_start.Start();
_cool.Run();
_cat.On();
}
public void Stop()
{
_fuel.Off();
_cat.Off();
_cool.Cool();
_cool.Stop();
_air.Off();
}
}

View File

@@ -0,0 +1,19 @@
namespace CarEngineFacadeRecording;
public class FuelInjector
{
public void On()
{
// implementation
}
public void Inject()
{
// implementation
}
public void Off()
{
// implementation
}
}

View File

@@ -0,0 +1,36 @@
#region
using CarEngineFacadeRecording;
#endregion
//// without the facade, starting the engine involves creating all the objects
//var airflow = new AirFlowController();
//var fuel = new FuelInjector();
//var start = new Starter();
//var cool = new CoolingController();
//var cat = new CatalyticConverter();
//// then performing all the steps in the correct order
//airflow.TakeAir();
//fuel.On();
//fuel.Inject();
//start.Start();
//cool.Run();
//cat.On();
//// and shut down also requires steps in the correct order
//fuel.Off();
//cat.Off();
//cool.Cool();
//cool.Stop();
//airflow.Off();
// with the Facade, all creation is handled internally
var facade = new Facade();
// as is starting
facade.Start();
// and stopping
facade.Stop();

View File

@@ -0,0 +1,9 @@
namespace CarEngineFacadeRecording;
public class Starter
{
public void Start()
{
// implementation
}
}

View File

@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<RootNamespace>AirTrafficControl</RootNamespace>
<AssemblyName>AirTrafficControl</AssemblyName>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,363 @@
using System;
using System.Linq;
namespace AirTrafficControl;
public enum AirTrafficRequest
{
LandingRequest,
TakeoffRequest,
RunwayCrossingRequest,
LandingRequestDone,
TakeoffRequestDone,
RunwayCrossingRequestDone,
}
public interface IColleague
{
void ReceiveMessage(string instruction, bool accepted);
}
public interface IMediator
{
void Notify(IColleague sender, AirTrafficRequest request);
}
public class Flight : IColleague
{
private readonly IMediator _mediator;
public string FlightNumber { get; }
public Flight(string flightNumber, IMediator mediator)
{
FlightNumber = flightNumber;
_mediator = mediator;
}
public void RequestLanding()
{
Console.WriteLine($"Flight {FlightNumber} requesting landing.");
_mediator.Notify(this, AirTrafficRequest.LandingRequest);
}
public void RequestTakeoff()
{
Console.WriteLine($"Flight {FlightNumber} requesting takeoff.");
_mediator.Notify(this, AirTrafficRequest.TakeoffRequest);
}
public void LandingCompleted()
{
Console.WriteLine($"Flight {FlightNumber} has completed landing.");
_mediator.Notify(this, AirTrafficRequest.LandingRequestDone);
}
public void TakeoffCompleted()
{
Console.WriteLine($"Flight {FlightNumber} has completed takeoff.");
_mediator.Notify(this, AirTrafficRequest.TakeoffRequestDone);
}
public void ReceiveMessage(string instruction, bool accepted)
{
if (accepted)
{
Console.WriteLine(
$"Flight {FlightNumber} received instruction: {instruction}"
);
}
else
{
Console.WriteLine(
$"Flight {FlightNumber} received rejection for instruction: {instruction}"
);
}
}
}
public class GroundVehicle : IColleague
{
private readonly IMediator _mediator;
public string VehicleId { get; }
public GroundVehicle(string vehicleId, IMediator mediator)
{
VehicleId = vehicleId;
_mediator = mediator;
}
public void RequestRunwayCrossing()
{
Console.WriteLine(
$"Ground vehicle {VehicleId} requesting runway crossing."
);
_mediator.Notify(this, AirTrafficRequest.RunwayCrossingRequest);
}
public void RunwayCrossingCompleted()
{
Console.WriteLine(
$"Ground vehicle {VehicleId} has completed runway crossing."
);
_mediator.Notify(this, AirTrafficRequest.RunwayCrossingRequestDone);
}
public void ReceiveMessage(string instruction, bool accepted)
{
if (accepted)
{
Console.WriteLine(
$"Ground vehicle {VehicleId} received instruction: {instruction}"
);
}
else
{
Console.WriteLine(
$"Ground vehicle {VehicleId} received rejection for instruction: {instruction}"
);
}
}
}
public class AirTrafficControlTower : IMediator
{
private class Runway
{
public string Name { get; init; } = "";
public IColleague? OccupiedBy { get; set; }
public Runway(string name)
{
Name = name;
}
}
private readonly Runway[] _runways = new Runway[30];
public AirTrafficControlTower()
{
// create runways
for (int i = 0; i < _runways.Length; i++)
{
_runways[i] = new Runway($"Runway R{i + 1}");
}
}
public void Notify(IColleague sender, AirTrafficRequest request)
{
switch (request)
{
case AirTrafficRequest.LandingRequest:
HandleLandingRequest(sender);
break;
case AirTrafficRequest.TakeoffRequest:
HandleTakeoffRequest(sender);
break;
case AirTrafficRequest.RunwayCrossingRequest:
HandleRunwayCrossingRequest(sender);
break;
case AirTrafficRequest.LandingRequestDone:
HandleLandingRequestDone(sender);
break;
case AirTrafficRequest.TakeoffRequestDone:
HandleTakeoffRequestDone(sender);
break;
case AirTrafficRequest.RunwayCrossingRequestDone:
HandleRunwayCrossingRequestDone(sender);
break;
default:
break;
}
}
void HandleLandingRequest(IColleague sender)
{
Runway? val = _runways.FirstOrDefault(r => r.OccupiedBy is null);
if (val is not null)
{
val.OccupiedBy = sender;
sender.ReceiveMessage(
$"Landing approved on {val.Name}.",
accepted: true
);
}
else
{
sender.ReceiveMessage(
"No available runways for landing.",
accepted: false
);
}
}
void HandleTakeoffRequest(IColleague sender)
{
Runway? val = _runways.FirstOrDefault(r => r.OccupiedBy is null);
if (val is not null)
{
val.OccupiedBy = sender;
sender.ReceiveMessage(
$"Takeoff approved on {val.Name}.",
accepted: true
);
}
else
{
sender.ReceiveMessage(
"No available runways for takeoff.",
accepted: false
);
}
}
void HandleLandingRequestDone(IColleague sender)
{
Runway? val = _runways.FirstOrDefault(r => r.OccupiedBy == sender);
if (val is not null)
{
val.OccupiedBy = null;
sender.ReceiveMessage(
$"You have cleared {val.Name} after landing.",
accepted: true
);
}
else
{
sender.ReceiveMessage(
"You were not occupying any runway.",
accepted: false
);
}
}
void HandleTakeoffRequestDone(IColleague sender)
{
Runway? val = _runways.FirstOrDefault(r => r.OccupiedBy == sender);
if (val is not null)
{
val.OccupiedBy = null;
sender.ReceiveMessage(
$"You have cleared {val.Name} after takeoff.",
accepted: true
);
}
else
{
sender.ReceiveMessage(
"You were not occupying any runway.",
accepted: false
);
}
}
void HandleRunwayCrossingRequestDone(IColleague sender)
{
Runway? val = _runways.FirstOrDefault(r => r.OccupiedBy == sender);
if (val is not null)
{
val.OccupiedBy = null;
sender.ReceiveMessage(
$"You have cleared {val.Name} after crossing.",
accepted: true
);
}
else
{
sender.ReceiveMessage(
"You were not occupying any runway.",
accepted: false
);
}
}
void HandleRunwayCrossingRequest(IColleague sender)
{
Runway? val = _runways.FirstOrDefault(r => r.OccupiedBy is null);
if (val is not null)
{
val.OccupiedBy = sender;
sender.ReceiveMessage(
$"Crossing approved on {val.Name}.",
accepted: true
);
}
else
{
sender.ReceiveMessage(
"No available runways for crossing.",
accepted: false
);
}
}
}
internal class Program
{
public static void Main()
{
var tower = new AirTrafficControlTower();
Flight[] flights = new Flight[1000];
for (int i = 0; i < flights.Length; i++)
{
flights[i] = new Flight($"F{i + 1:D4}", tower);
}
GroundVehicle[] vehicles = new GroundVehicle[10];
for (int i = 0; i < vehicles.Length; i++)
{
vehicles[i] = new GroundVehicle($"V{i + 1:D3}", tower);
}
// create simulation with random events
Random rand = new Random();
ulong tick = 0;
while (tick < 100_000)
{
tick++;
// randomly select a flight or vehicle to make a request
int index = rand.Next(0, flights.Length + vehicles.Length);
if (index < flights.Length)
{
Flight flight = flights[index];
int action = rand.Next(0, 4);
switch (action)
{
case 0:
flight.RequestLanding();
break;
case 1:
flight.RequestTakeoff();
break;
case 2:
flight.LandingCompleted();
break;
case 3:
flight.TakeoffCompleted();
break;
}
}
else
{
GroundVehicle vehicle = vehicles[index - flights.Length];
int action = rand.Next(0, 2);
switch (action)
{
case 0:
vehicle.RequestRunwayCrossing();
break;
case 1:
vehicle.RunwayCrossingCompleted();
break;
}
}
}
}
}

View File

@@ -0,0 +1,24 @@
namespace MementoPattern;
public class Caretaker
{
//container that could hold memento of Originator
//object
private readonly Stack<IMemento> _mementos = new();
private readonly IOriginator _originator;
public Caretaker(IOriginator originator)
{
_originator = originator;
}
public void Save()
{
_mementos.Push(_originator.GetMemento());
}
public void Undo()
{
_originator.SetMemento(_mementos.Pop());
}
}

View File

@@ -0,0 +1,3 @@
namespace MementoPattern;
public interface IMemento { }

View File

@@ -0,0 +1,7 @@
namespace MementoPattern;
public interface IOriginator
{
IMemento GetMemento();
void SetMemento(IMemento memento);
}

View File

@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,46 @@
namespace MementoPattern;
public class Originator : IOriginator
{
private Guid _id;
public Originator()
{
_id = Guid.NewGuid();
Console.WriteLine($"Starting ID: {_id}");
Console.WriteLine();
}
public IMemento GetMemento()
{
Memento memento = new Memento();
memento.Id = _id;
Console.WriteLine("Creating Memento...");
Console.WriteLine();
return memento;
}
public void SetMemento(IMemento memento)
{
if (!(memento is Memento))
return;
Console.WriteLine("Restting ID...");
_id = (memento as Memento).Id;
Console.WriteLine($"ID is reset to {_id}");
Console.WriteLine();
}
public void UpdateId()
{
Console.WriteLine("Updating Id...");
_id = Guid.NewGuid();
Console.WriteLine($"Updated ID is now {_id}");
Console.WriteLine();
}
private class Memento : IMemento
{
public Guid Id;
}
}

View File

@@ -0,0 +1,45 @@
namespace MementoPattern;
public class Program
{
private static void Main(string[] args)
{
Originator originator = new Originator();
Caretaker caretaker = new Caretaker(originator);
caretaker.Save();
Console.WriteLine(
"After the first save, the originator's first ID is saved as a memento and pushed on the caretaker's stack. Enter any input to continue."
);
Console.ReadLine();
originator.UpdateId();
originator.UpdateId();
caretaker.Save();
Console.WriteLine(
"After two updates and a save, only the second update is saved as a memento and pushed on the caretaker's stack. Enter any input to continue."
);
Console.ReadLine();
originator.UpdateId();
caretaker.Undo();
Console.WriteLine(
"After this latest update, since we called Undo() the ID will be changed from the latest updated ID to the prior one (i.e. the latest one that was actually saved to the stack). This is the main point of memento. Enter any input to continue."
);
Console.ReadLine();
originator.UpdateId();
caretaker.Save();
Console.WriteLine(
"A new ID is updated and pushed onto the stack. Enter any input to continue."
);
Console.ReadLine();
originator.UpdateId();
caretaker.Undo();
caretaker.Undo();
}
}

View File

@@ -0,0 +1,94 @@
namespace UpdatedOne;
public interface IObserver<TSubject>
{
void Update(TSubject subject);
}
public abstract class Subject<TSubject>
{
private readonly List<IObserver<TSubject>> _observers = new();
public void Subscribe(IObserver<TSubject> observer)
{
if (!_observers.Contains(observer))
_observers.Add(observer);
}
public void Unsubscribe(IObserver<TSubject> observer)
{
_observers.Remove(observer);
}
protected void Notify(TSubject subject)
{
foreach (IObserver<TSubject> observer in _observers.ToArray())
observer.Update(subject);
}
}
public class Data : Subject<Data>
{
private int _value;
public Data(int value)
{
_value = value;
}
public void SetData(int value)
{
if (_value == value)
return;
_value = value;
Console.WriteLine($"Data changed to {_value}");
Notify(this);
}
public int GetData()
{
return _value;
}
}
public class BarGraph : IObserver<Data>
{
public void Update(Data subject)
{
int value = subject.GetData();
Console.WriteLine($"Bar Graph updated: {value}");
}
}
public class PieChart : IObserver<Data>
{
public void Update(Data subject)
{
int value = subject.GetData();
Console.WriteLine($"Pie Chart updated: {value}");
}
}
internal static class Program
{
private static void Main()
{
Data data = new Data(2);
BarGraph barGraph = new BarGraph();
PieChart pieChart = new PieChart();
data.Subscribe(barGraph);
data.Subscribe(pieChart);
data.SetData(3);
data.Unsubscribe(barGraph);
data.Unsubscribe(pieChart);
}
}

View File

@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,81 @@
#region
using System;
#endregion
namespace BadCarState;
public class Car
{
private State _state = State.Off;
public bool HandleInput(string input)
{
switch (input)
{
case "turn-clockwise":
switch (_state)
{
case State.Off:
Console.WriteLine("The engine has started");
Console.WriteLine();
_state = State.Stopped;
break;
case State.Stopped:
case State.Driving:
Console.WriteLine("You hear a grinding noise...");
Console.WriteLine();
break;
}
break;
case "turn-counter":
switch (_state)
{
case State.Stopped:
Console.WriteLine("The engine has stopped");
Console.WriteLine();
_state = State.Off;
break;
case State.Driving:
Console.WriteLine(
"The engine turns off, and the car stops suddenly"
);
Console.WriteLine();
_state = State.Off;
break;
}
break;
case "gas":
switch (_state)
{
case State.Stopped:
Console.WriteLine("The car begins to drive");
Console.WriteLine();
_state = State.Driving;
break;
}
break;
case "brake":
switch (_state)
{
case State.Driving:
Console.WriteLine("The car slows to a stop");
Console.WriteLine();
_state = State.Stopped;
break;
}
break;
case "exit":
return false;
}
return true;
}
private enum State
{
Off,
Stopped,
Driving,
}
}

View File

@@ -0,0 +1,41 @@
#region
using System;
#endregion
namespace BadCarState;
internal class Program
{
private static void Main(string[] args)
{
var car = new Car();
string input;
bool keepRunning = true;
Console.WriteLine("Welcome to the Driving Simulater");
Console.WriteLine();
Console.WriteLine("Usage:");
Console.WriteLine(" turn-clockwise -Turns the car's key clockwise");
Console.WriteLine(
" turn-counter -Turns the car's key counter clockwise"
);
Console.WriteLine(" gas -Presses the gas pedal");
Console.WriteLine(" brake -Presses the brake pedal");
Console.WriteLine(" exit -Exits the simulator");
Console.WriteLine();
do
{
Console.Write("> ");
input = Console.ReadLine();
Console.WriteLine();
keepRunning = car.HandleInput(input);
} while (keepRunning);
Console.WriteLine();
Console.WriteLine("goodbye");
Console.WriteLine();
}
}

View File

@@ -0,0 +1,44 @@
#region
using CarState.States;
#endregion
namespace CarState;
public class Car
{
private State _state;
public Car()
{
ChangeState(new Off(this));
}
public bool HandleInput(string input)
{
switch (input)
{
case "turn-clockwise":
_state.TurnKeyClockwise();
break;
case "turn-counter":
_state.TurnKeyCounterClockwise();
break;
case "gas":
_state.PressGas();
break;
case "brake":
_state.PressBrake();
break;
case "exit":
return false;
}
return true;
}
public void ChangeState(State state)
{
_state = state;
}
}

View File

@@ -0,0 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,41 @@
#region
using System;
#endregion
namespace CarState;
internal class Program
{
private static void Main(string[] args)
{
var car = new Car();
string input;
bool keepRunning = true;
Console.WriteLine("Welcome to the Driving Simulater");
Console.WriteLine();
Console.WriteLine("Usage:");
Console.WriteLine(" turn-clockwise -Turns the car's key clockwise");
Console.WriteLine(
" turn-counter -Turns the car's key counter clockwise"
);
Console.WriteLine(" gas -Presses the gas pedal");
Console.WriteLine(" brake -Presses the brake pedal");
Console.WriteLine(" exit -Exits the simulator");
Console.WriteLine();
do
{
Console.Write("> ");
input = Console.ReadLine();
Console.WriteLine();
keepRunning = car.HandleInput(input);
} while (keepRunning);
Console.WriteLine();
Console.WriteLine("goodbye");
Console.WriteLine();
}
}

View File

@@ -0,0 +1,33 @@
#region
using System;
#endregion
namespace CarState.States;
public class Driving : State
{
public Driving(Car car)
: base(car) { }
public override void TurnKeyClockwise()
{
Console.WriteLine("You hear a grinding noise...");
Console.WriteLine();
}
public override void TurnKeyCounterClockwise()
{
Console.WriteLine("The engine turns off, and the car stops suddenly");
Console.WriteLine();
_car.ChangeState(new Off(_car));
}
public override void PressBrake()
{
Console.WriteLine("The car slows to a stop");
Console.WriteLine();
_car.ChangeState(new Stopped(_car));
}
}

View File

@@ -0,0 +1,20 @@
#region
using System;
#endregion
namespace CarState.States;
public class Off : State
{
public Off(Car car)
: base(car) { }
public override void TurnKeyClockwise()
{
Console.WriteLine("The engine has started");
Console.WriteLine();
_car.ChangeState(new Stopped(_car));
}
}

View File

@@ -0,0 +1,19 @@
namespace CarState.States;
public class State
{
protected Car _car;
public State(Car car)
{
_car = car;
}
public virtual void TurnKeyClockwise() { }
public virtual void TurnKeyCounterClockwise() { }
public virtual void PressGas() { }
public virtual void PressBrake() { }
}

View File

@@ -0,0 +1,33 @@
#region
using System;
#endregion
namespace CarState.States;
public class Stopped : State
{
public Stopped(Car car)
: base(car) { }
public override void PressGas()
{
Console.WriteLine("The car begins to drive");
Console.WriteLine();
_car.ChangeState(new Driving(_car));
}
public override void TurnKeyClockwise()
{
Console.WriteLine("You hear a grinding noise...");
Console.WriteLine();
}
public override void TurnKeyCounterClockwise()
{
Console.WriteLine("The engine has stopped");
Console.WriteLine();
_car.ChangeState(new Off(_car));
}
}

View File

@@ -0,0 +1,44 @@
#region
using WithStatePattern.States;
#endregion
namespace WithStatePattern;
public class Car
{
private State _state;
public Car()
{
ChangeState(new Off(this));
}
public bool HandleInput(string input)
{
switch (input)
{
case "turn-clockwise":
_state.TurnKeyClockwise();
break;
case "turn-counter":
_state.TurnKeyCounterClockwise();
break;
case "gas":
_state.PressGas();
break;
case "brake":
_state.PressBrake();
break;
case "exit":
return false;
}
return true;
}
public void ChangeState(State state)
{
_state = state;
}
}

View File

@@ -0,0 +1,35 @@
namespace WithStatePattern;
public class Program
{
private static void Main(string[] args)
{
var car = new Car();
string input;
bool keepRunning = true;
Console.WriteLine("Welcome to the Driving Simulater");
Console.WriteLine();
Console.WriteLine("Usage:");
Console.WriteLine(" turn-clockwise -Turns the car's key clockwise");
Console.WriteLine(
" turn-counter -Turns the car's key counter clockwise"
);
Console.WriteLine(" gas -Presses the gas pedal");
Console.WriteLine(" brake -Presses the brake pedal");
Console.WriteLine(" exit -Exits the simulator");
Console.WriteLine();
do
{
Console.Write("> ");
input = Console.ReadLine();
Console.WriteLine();
keepRunning = car.HandleInput(input);
} while (keepRunning);
Console.WriteLine();
Console.WriteLine("goodbye");
Console.WriteLine();
}
}

View File

@@ -0,0 +1,27 @@
namespace WithStatePattern.States;
public class Driving : State
{
public Driving(Car car)
: base(car) { }
public override void TurnKeyClockwise()
{
Console.WriteLine("You hear a grinding noise...");
Console.WriteLine();
}
public override void TurnKeyCounterClockwise()
{
Console.WriteLine("The engine turns off, and the car stops suddenly");
Console.WriteLine();
_car.ChangeState(new Off(_car));
}
public override void PressBrake()
{
Console.WriteLine("The car slows to a stop");
Console.WriteLine();
_car.ChangeState(new Stopped(_car));
}
}

View File

@@ -0,0 +1,14 @@
namespace WithStatePattern.States;
public class Off : State
{
public Off(Car car)
: base(car) { }
public override void TurnKeyClockwise()
{
Console.WriteLine("The engine has started");
Console.WriteLine();
_car.ChangeState(new Stopped(_car));
}
}

View File

@@ -0,0 +1,19 @@
namespace WithStatePattern.States;
public class State
{
protected Car _car;
public State(Car car)
{
_car = car;
}
public virtual void TurnKeyClockwise() { }
public virtual void TurnKeyCounterClockwise() { }
public virtual void PressGas() { }
public virtual void PressBrake() { }
}

View File

@@ -0,0 +1,27 @@
namespace WithStatePattern.States;
public class Stopped : State
{
public Stopped(Car car)
: base(car) { }
public override void PressGas()
{
Console.WriteLine("The car begins to drive");
Console.WriteLine();
_car.ChangeState(new Driving(_car));
}
public override void TurnKeyClockwise()
{
Console.WriteLine("You hear a grinding noise...");
Console.WriteLine();
}
public override void TurnKeyCounterClockwise()
{
Console.WriteLine("The engine has stopped");
Console.WriteLine();
_car.ChangeState(new Off(_car));
}
}

View File

@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,75 @@
namespace WithoutStatePattern;
public class Car
{
private State _state = State.Off;
public bool HandleInput(string input)
{
switch (input)
{
case "turn-clockwise":
switch (_state)
{
case State.Off:
Console.WriteLine("The engine has started");
Console.WriteLine();
_state = State.Stopped;
break;
case State.Stopped:
case State.Driving:
Console.WriteLine("You hear a grinding noise...");
Console.WriteLine();
break;
}
break;
case "turn-counter":
switch (_state)
{
case State.Stopped:
Console.WriteLine("The engine has stopped");
Console.WriteLine();
_state = State.Off;
break;
case State.Driving:
Console.WriteLine(
"The engine turns off, and the car stops suddenly"
);
Console.WriteLine();
_state = State.Off;
break;
}
break;
case "gas":
switch (_state)
{
case State.Stopped:
Console.WriteLine("The car begins to drive");
Console.WriteLine();
_state = State.Driving;
break;
}
break;
case "brake":
switch (_state)
{
case State.Driving:
Console.WriteLine("The car slows to a stop");
Console.WriteLine();
_state = State.Stopped;
break;
}
break;
case "exit":
return false;
}
return true;
}
private enum State
{
Off,
Stopped,
Driving,
}
}

View File

@@ -0,0 +1,35 @@
namespace WithoutStatePattern;
internal class Program
{
private static void Main(string[] args)
{
var car = new Car();
string input;
bool keepRunning = true;
Console.WriteLine("Welcome to the Driving Simulater");
Console.WriteLine();
Console.WriteLine("Usage:");
Console.WriteLine(" turn-clockwise -Turns the car's key clockwise");
Console.WriteLine(
" turn-counter -Turns the car's key counter clockwise"
);
Console.WriteLine(" gas -Presses the gas pedal");
Console.WriteLine(" brake -Presses the brake pedal");
Console.WriteLine(" exit -Exits the simulator");
Console.WriteLine();
do
{
Console.Write("> ");
input = Console.ReadLine();
Console.WriteLine();
keepRunning = car.HandleInput(input);
} while (keepRunning);
Console.WriteLine();
Console.WriteLine("goodbye");
Console.WriteLine();
}
}

View File

@@ -0,0 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>