Skip to content

Instantly share code, notes, and snippets.

@peterhoang
Forked from NMillard/Program.cs
Created July 2, 2020 16:12
Show Gist options
  • Save peterhoang/1cf52c0a09f59217cb26435120496ed7 to your computer and use it in GitHub Desktop.
Save peterhoang/1cf52c0a09f59217cb26435120496ed7 to your computer and use it in GitHub Desktop.
If-Else vs Dynamic Type Discovery
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.Json;
namespace DesignPatterns.DynamicStrategy {
class Program {
static void Main(string[] args) {
/*
* If-else method
*/
string json = PrintOrder(Order.CreateNew(10), "Json");
string plain = PrintOrder(Order.CreateNew(10), "PlainText");
Console.WriteLine(json);
Console.WriteLine(plain);
Console.WriteLine(Environment.NewLine);
/*
* Dynamic
*/
string json2 = PrintOrder2(Order.CreateNew(10), "Json");
string plain2 = PrintOrder2(Order.CreateNew(10), "PlainText");
Console.WriteLine(json2);
Console.WriteLine(plain2);
}
/*
* If-Else Example
*/
public static string PrintOrder(Order order, string formatType) {
// Guard clauses left out for brevity
string result = string.Empty;
if (formatType == "Json") {
result = JsonSerializer.Serialize(order);
} else if (formatType == "PlainText") {
result = $"Id: {order.Id}\nSum: {order.Sum}";
} else {
result = "Unknown format";
}
return result;
}
/*
* Dynamic type discovery example
*/
private static string PrintOrder2(Order order, string formatType) {
// Dynamic type discovery process that builds a dictionary
Dictionary<string, Type> formatterTypes = Assembly
.GetExecutingAssembly()
.GetExportedTypes()
.Where(type => type.GetInterfaces().Contains(typeof(IOrderOutputStrategy)))
.ToDictionary(type => type.GetCustomAttribute<OutputFormatterName>().DisplayName);
Type chosenFormatter = formatterTypes[formatType];
// Try instantiate the formatter -- could have utilized a DI framework here instead
IOrderOutputStrategy strategy = Activator.CreateInstance(chosenFormatter) as IOrderOutputStrategy;
if (strategy is null) throw new InvalidOperationException("No valid formatter selected");
// Execute strategy method
string result = strategy.ConvertOrderToString(order);
return result;
}
}
public class Order {
private readonly string id;
private Order() {
this.id = Guid.NewGuid().ToString("D");
}
public string Id => id;
public int Sum { get; private set; }
public string GenerateOutput(IOrderOutputStrategy strategy) =>
strategy.ConvertOrderToString(this);
public static Order CreateNew(int orderSum) {
if (orderSum <= 0) throw new ArgumentException("sum must be a positive number");
var order = new Order {
Sum = orderSum,
};
return order;
}
}
[AttributeUsage(AttributeTargets.Class)]
public class OutputFormatterName : Attribute {
public OutputFormatterName(string displayName) {
DisplayName = displayName;
}
public string DisplayName { get; }
}
public interface IOrderOutputStrategy {
public string ConvertOrderToString(Order order);
}
[OutputFormatterName("Json")]
public class OrderJsonOutput : IOrderOutputStrategy {
public string ConvertOrderToString(Order order) {
string json = JsonSerializer.Serialize(order);
return json;
}
}
[OutputFormatterName("PlainText")]
public class OrderPlainTextOutput : IOrderOutputStrategy {
public string ConvertOrderToString(Order order) {
return $"Id: {order.Id}{Environment.NewLine}Sum: {order.Sum}";
}
}
}
@peterhoang
Copy link
Author

Example of Strategy Pattern. Also, dynamically find class implementation via Reflection.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment