Last active
October 27, 2022 15:36
-
-
Save konstantint/f8c45b64342c56a6f86a77f945ac8b67 to your computer and use it in GitHub Desktop.
A program for adding ten numbers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Source code for the post: | |
// https://www.quora.com/Can-you-write-a-program-for-adding-10-numbers/answer/Konstantin-Tretyakov | |
// http://fouryears.eu/2018/03/17/a-program-for-adding-10-numbers/ | |
// | |
// Runs with the following config.xml: | |
// <Config> | |
// <InputProvider class="Enterprise.NumberSequenceProvider"/> | |
// <OutputConsumer class="Enterprise.PeanoNumberPrinter"/> | |
// <Solution class="Enterprise.TenNumberAddingSolution"> | |
// <Strategy class="Enterprise.AdditionStrategy"/> | |
// </Solution> | |
// </Config> | |
using System; | |
using System.Linq; | |
using System.Xml.Linq; | |
using System.IO; | |
using System.Collections.Generic; | |
using System.Threading; | |
namespace Enterprise | |
{ | |
interface IInputProvider {} | |
interface IOutput {} | |
interface ISolution { | |
IOutput add10(IInputProvider input); | |
} | |
interface IOutputConsumer { | |
void consumeOutput(IOutput output); | |
} | |
class SolutionFactory { | |
private XDocument cfg; | |
public SolutionFactory(string configFile) { | |
cfg = XDocument.Load(configFile); | |
} | |
public IInputProvider GetInputProvider() { | |
return Instantiate<IInputProvider>("InputProvider"); | |
} | |
public IOutputConsumer GetOutputConsumer() { | |
return Instantiate<IOutputConsumer>("OutputConsumer"); | |
} | |
public ISolution GetSolution() { | |
return Instantiate<ISolution>("Solution"); | |
} | |
private T Instantiate<T>(string elementName) { | |
var typeName = cfg.Root.Element(elementName).Attribute("class").Value; | |
return (T)Activator.CreateInstance(Type.GetType(typeName)); | |
} | |
} | |
interface INumber: IOutput { | |
INumber add(INumber other); | |
} | |
enum NumberOfANumber { | |
ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN | |
} | |
interface ITenNumbersProvider { | |
INumber GetNumber(NumberOfANumber noan); | |
} | |
delegate void NumberHandler(NumberOfANumber id, INumber n); | |
interface IAsynchronousInputProvider: IInputProvider { | |
void AddNumberListener(NumberHandler handler); | |
} | |
class SynchronizationAdapter: ITenNumbersProvider { | |
private Dictionary<NumberOfANumber, INumber> nums; | |
private ManualResetEvent allDataAvailableEvent; | |
public SynchronizationAdapter(IAsynchronousInputProvider ainput) { | |
nums = new Dictionary<NumberOfANumber, INumber>(); | |
allDataAvailableEvent = new ManualResetEvent(false); | |
ainput.AddNumberListener(this.HandleIncomingNumber); | |
} | |
private void HandleIncomingNumber(NumberOfANumber id, INumber n) { | |
nums[id] = n; | |
if (Enum.GetValues(typeof(NumberOfANumber)).Cast<NumberOfANumber>() | |
.All(k => nums.ContainsKey(k))) allDataAvailableEvent.Set(); | |
} | |
public INumber GetNumber(NumberOfANumber noan) { | |
allDataAvailableEvent.WaitOne(); | |
return nums[noan]; | |
} | |
} | |
interface IAdditionStrategy { | |
INumber fold(Func<NumberOfANumber, INumber> elements, Func<INumber, INumber, INumber> op); | |
} | |
class TenNumbersAddingSolution: ISolution { | |
private IAdditionStrategy strategy; | |
public TenNumbersAddingSolution() { | |
var cfg = XDocument.Load("config.xml"); | |
var typeName = cfg.Root.Element("Solution").Element("Strategy").Attribute("class").Value; | |
strategy = (IAdditionStrategy)Activator.CreateInstance(Type.GetType(typeName)); | |
} | |
public IOutput add10(IInputProvider input) { | |
var tenNumbers = new SynchronizationAdapter((IAsynchronousInputProvider)input); | |
return strategy.fold(i => tenNumbers.GetNumber(i), (x,y) => x.add(y)); | |
} | |
} | |
class PeanoInteger: INumber { | |
public PeanoInteger Prev { get; private set; } | |
public PeanoInteger(PeanoInteger prev) { Prev = prev; } | |
public INumber add(INumber b) { | |
if (b == null) return this; | |
else return new PeanoInteger(this).add(((PeanoInteger)b).Prev); | |
} | |
} | |
class PeanoNumberPrinter: IOutputConsumer { | |
public void consumeOutput(IOutput p) { | |
for (var x = (PeanoInteger)p; x != null; x = x.Prev) Console.Write("1"); | |
Console.WriteLine(); | |
} | |
} | |
class NumberSequenceProvider: IAsynchronousInputProvider { | |
private event NumberHandler handler; | |
private ManualResetEvent handlerAvailable; | |
public NumberSequenceProvider() { | |
handlerAvailable = new ManualResetEvent(false); | |
new Thread(ProduceNumbers).Start(); | |
} | |
public void AddNumberListener(NumberHandler nh) { | |
handler += nh; | |
handlerAvailable.Set(); | |
} | |
private void ProduceNumbers() { | |
handlerAvailable.WaitOne(); | |
PeanoInteger pi = null; | |
foreach (var v in Enum.GetValues(typeof(NumberOfANumber)).Cast<NumberOfANumber>()) { | |
pi = new PeanoInteger(pi); | |
handler(v, pi); | |
} | |
} | |
} | |
class AdditionStrategy: IAdditionStrategy { | |
public INumber fold(Func<NumberOfANumber, INumber> elements, Func<INumber, INumber, INumber> op) { | |
return Enum.GetValues(typeof(NumberOfANumber)) | |
.Cast<NumberOfANumber>() | |
.Select(elements).Aggregate(op); | |
} | |
} | |
class Solution: ISolution { | |
public IOutput add10(IInputProvider input) { | |
return (IOutput)input; | |
} | |
} | |
class Program { | |
static void Main(string[] args) { | |
var sf = new SolutionFactory("config.xml"); | |
var ip = sf.GetInputProvider(); | |
var oc = sf.GetOutputConsumer(); | |
var sol = sf.GetSolution(); | |
var op = sol.add10(ip); | |
oc.consumeOutput(op); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment