WIP creational patterns

This commit is contained in:
Claudiu Farcas
2021-04-17 10:05:04 +03:00
parent 4c94eb10ac
commit 0268776110
6 changed files with 661 additions and 2 deletions
+109
View File
@@ -0,0 +1,109 @@
using System;
using System.Threading.Tasks;
namespace design_patterns.creational.facadebuilder
{
/// <summary>
/// this sample covers the case when we have multiple builders
/// for the same class, that we want to chain
/// </summary>
public class FacadeBuilderSample
{
public static async Task Run() {
Console.WriteLine("Creational - Facade Builder");
var product = new ProductBuilder()
.Info
.WithName("New Product")
.WithDetails("product details")
.Price
.WithPrice(67.12m)
.WithDiscountLevel1(4)
.WithDiscountLevel2(12)
.Build();
Console.WriteLine("product: " + product.ToString());
// sample with implicit operator casting
Product product2 = new ProductBuilder()
.Info
.WithName("New Product 2")
.WithDetails("product details 2")
.Price
.WithPrice(23.11m)
.WithDiscountLevel1(5)
.WithDiscountLevel2(10);
Console.WriteLine("product: " + product2.ToString());
}
}
public class Product {
// first section handled by a builder
public string Name { get; set; }
public string Details { get; set; }
// second section handled by another builder
public decimal Price { get; set; }
public int DiscountPercentLevel1 { get; set; }
public int DiscountPercentLevel2 { get; set; }
public override string ToString()
{
return $"{Name} : {Details} : {Price} : {DiscountPercentLevel1} : {DiscountPercentLevel2}";
}
}
// this acts as a facade
public class ProductBuilder
{
protected Product instance = new Product();
public ProductInfoBuilder Info => new ProductInfoBuilder(instance);
public ProductPriceBuilder Price => new ProductPriceBuilder(instance);
public Product Build() {
return instance;
}
public static implicit operator Product(ProductBuilder pb) => pb.instance;
}
public class ProductInfoBuilder : ProductBuilder {
public ProductInfoBuilder(Product instance) {
this.instance = instance;
}
public ProductInfoBuilder WithName(string name) {
this.instance.Name = name;
return this;
}
public ProductInfoBuilder WithDetails(string details) {
this.instance.Details = details;
return this;
}
}
public class ProductPriceBuilder : ProductBuilder {
public ProductPriceBuilder(Product instance) {
this.instance = instance;
}
public ProductPriceBuilder WithPrice(decimal price) {
this.instance.Price = price;
return this;
}
public ProductPriceBuilder WithDiscountLevel1(int discount) {
this.instance.DiscountPercentLevel1 = discount;
return this;
}
public ProductPriceBuilder WithDiscountLevel2(int discount) {
this.instance.DiscountPercentLevel2 = discount;
return this;
}
}
}
+125
View File
@@ -0,0 +1,125 @@
using System;
using System.Threading.Tasks;
namespace design_patterns.creational.fluentbuilder
{
/// <summary>
/// Builder is a creational design pattern that
/// lets you construct complex objects step by step.
/// The pattern allows you to produce different types
/// and representations of an object using the same construction code.
///
/// Fluent builder - limited as it cannot be extended via inheritance
/// </summary>
public class FluentBuilderSample
{
public static async Task Run() {
Console.WriteLine("Creational - Fluent Builder");
var product = ProductBuilder
.CreateProduct()
.WithName("New Product")
.WithCategory("Best category")
.WithAge(30)
.WithPrice(45.22m)
.Build();
Console.WriteLine("product: " + product.ToString());
}
}
public class Product {
public int Age { get; set; }
public decimal Price { get; set; }
public string ProductName { get; set; }
public string Category { get; set; }
public string Info { get; internal set; }
public override string ToString()
{
return $"{ProductName} : {Category} : {Age} : {Price}";
}
}
public interface IProductBuilder :
IProductName,
IProductAge,
IProductPrice,
IProductCategory {
Product Build();
}
public interface IProductName {
IProductBuilder WithName(string productName);
}
public interface IProductAge {
IProductBuilder WithAge(int productAge);
}
public interface IProductPrice {
IProductBuilder WithPrice(decimal productPrice);
}
public interface IProductCategory {
IProductBuilder WithCategory(string productCategory);
}
public class ProductBuilderWithInfo : ProductBuilder {
IProductBuilder WithInfo(string info){
this.instance.Info = info;
return this;
}
}
public abstract class ProductBuilderBase {
}
public class ProductBuilder :
IProductBuilder
{
// set as protected to favor inheritance for extensibility of builder class
protected Product instance;
protected ProductBuilder() {}
public static ProductBuilder CreateProduct()
{
var pb = new ProductBuilder() {
instance = new Product()
};
return pb;
}
public Product Build()
{
return instance;
}
public IProductBuilder WithAge(int productAge)
{
this.instance.Age = productAge;
return this;
}
public IProductBuilder WithCategory(string productCategory)
{
this.instance.Category = productCategory;
return this;
}
public IProductBuilder WithName(string productName)
{
this.instance.ProductName = productName;
return this;
}
public IProductBuilder WithPrice(decimal productPrice)
{
this.instance.Price = productPrice;
return this;
}
}
}
@@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace design_patterns.creational.functionalbuilder
{
/// <summary>
/// Builder is a creational design pattern that
/// lets you construct complex objects step by step.
/// The pattern allows you to produce different types
/// and representations of an object using the same construction code.
///
/// Functional builder - allow builder extension via extended methods
/// </summary>
public class FunctionalBuilderSample
{
public static async Task Run() {
Console.WriteLine("Creational - Functional Builder");
var product = new ProductBuilder()
.WithName("New Product")
.WithCategory("Best category")
.WithAge(30)
.WithPrice(45.22m)
.Build();
Console.WriteLine("product: " + product.ToString());
}
}
public abstract class FunctionalBuilderBase<T, SELF>
where SELF : FunctionalBuilderBase<T, SELF>
where T : new()
{
private readonly List<Func<T, T>> actions = new List<Func<T, T>>();
public SELF Apply(Action<T> action) {
actions.Add(t => {
action(t);
return t;
});
return this as SELF;
}
public T Build() {
return actions.Aggregate(new T(), (t, f) => f(t));
}
}
public sealed class ProductBuilder : FunctionalBuilderBase<Product, ProductBuilder> {
public ProductBuilder WithName(string name) =>
Apply(p => p.ProductName = name);
}
/// <summary>
/// allow extending the builder
/// </summary>
public static class ProductBuilderExtensions {
public static ProductBuilder WithAge(this ProductBuilder builder, int age) =>
builder.Apply(p => p.Age = age);
public static ProductBuilder WithCategory(this ProductBuilder builder, string category) =>
builder.Apply(p => p.Category = category);
public static ProductBuilder WithPrice(this ProductBuilder builder, decimal price) =>
builder.Apply(p => p.Price = price);
}
public class Product {
public int Age { get; set; }
public decimal Price { get; set; }
public string ProductName { get; set; }
public string Category { get; set; }
public string Info { get; internal set; }
public override string ToString()
{
return $"{ProductName} : {Category} : {Age} : {Price}";
}
}
}