Skip to content

Instantly share code, notes, and snippets.

@pkuderov
Created October 10, 2017 10:56
Show Gist options
  • Save pkuderov/9e2f5f8e8559b6b8b25f99fcbd837623 to your computer and use it in GitHub Desktop.
Save pkuderov/9e2f5f8e8559b6b8b25f99fcbd837623 to your computer and use it in GitHub Desktop.
Slightly refactored calculator (to Shishkin)
using System;
namespace Calculator
{
internal interface IMathProvider<T>
{
T Divide(T a, T b);
T Multiply(T a, T b);
T Add(T a, T b);
T Subtract(T a, T b);
}
internal class IntMathProvider : IMathProvider<int>
{
public int Divide(int a, int b) => a / b;
public int Multiply(int a, int b) => a * b;
public int Add(int a, int b) => a + b;
public int Subtract(int a, int b) => a - b;
}
internal class UncheckedIntMathProvider : IMathProvider<int>
{
public int Divide(int a, int b) => a / b;
public int Multiply(int a, int b) => unchecked(a * b);
public int Add(int a, int b) => unchecked(a + b);
public int Subtract(int a, int b) => unchecked(a - b);
}
internal class CheckedIntMathProvider : IMathProvider<int>
{
public int Divide(int a, int b) => a / b;
public int Multiply(int a, int b) => checked(a * b);
public int Add(int a, int b) => checked(a + b);
public int Subtract(int a, int b) => checked(a - b);
}
internal class FloatMathProvider : IMathProvider<float>
{
public float Divide(float a, float b) => a / b;
public float Multiply(float a, float b) => a * b;
public float Add(float a, float b) => a + b;
public float Subtract(float a, float b) => a - b;
}
public enum OperationMode
{
Add = '+',
Subtract = '-',
Multiply = '*',
Divide = '/'
}
public enum CheckMode
{
Default = '#',
Checked = 'c',
Unhecked = 'u',
}
internal class Calculator<T> where T : struct
{
private readonly IMathProvider<T> _math;
private T _result;
public Calculator(IMathProvider<T> math)
{
_math = math;
_result = default(T);
}
public T Calculate(OperationMode operation, T secondOperand)
{
switch (operation)
{
case OperationMode.Add:
_result = _math.Add(_result, secondOperand);
break;
case OperationMode.Subtract:
_result = _math.Subtract(_result, secondOperand);
break;
case OperationMode.Multiply:
_result = _math.Multiply(_result, secondOperand);
break;
case OperationMode.Divide:
_result = _math.Divide(_result, secondOperand);
break;
default:
throw new ArgumentOutOfRangeException();
}
return _result;
}
}
internal class Calсulator
{
bool _isIntMode;
CheckMode _checkMode;
OperationMode _currentOperation;
Calculator<float> _floatCalculator;
Calculator<int> _intCalculator;
public Calсulator()
{
_isIntMode = true;
_checkMode = CheckMode.Default;
_currentOperation = OperationMode.Add;
_floatCalculator = CreateFloatCalc();
_intCalculator = CreateIntCalc(_checkMode);
}
public void Repl()
{
while (true)
{
var s = Console.ReadLine();
if (string.IsNullOrEmpty(s))
{
break;
}
if (s.Length == 1)
{
if (TryParseControlOperator(s[0]) || TryParseArithmeticOperator(s[0]))
{
continue;
}
}
TryCalculate(s);
}
}
private void TryCalculate(string s)
{
if (_isIntMode && int.TryParse(s, out var intResult))
{
try
{
Console.WriteLine(_intCalculator.Calculate(_currentOperation, intResult));
}
catch (OverflowException)
{
Console.WriteLine("Overflow");
}
}
else if (!_isIntMode && float.TryParse(s, out var floatResult))
{
try
{
Console.WriteLine(_floatCalculator.Calculate(_currentOperation, floatResult));
}
catch (OverflowException)
{
Console.WriteLine("Overflow");
}
}
}
private bool TryParseArithmeticOperator(char c)
{
switch (c)
{
case '+':
_currentOperation = OperationMode.Add;
break;
case '-':
_currentOperation = OperationMode.Subtract;
break;
case '*':
_currentOperation = OperationMode.Multiply;
break;
case '/':
_currentOperation = OperationMode.Divide;
break;
default:
return false;
}
return true;
}
private bool TryParseControlOperator(char c)
{
var isParsed = true;
switch (c)
{
case 'i':
_isIntMode = true;
break;
case 'f':
_isIntMode = false;
break;
case '#':
_checkMode = CheckMode.Default;
break;
case 'c':
_checkMode = CheckMode.Checked;
break;
case 'u':
_checkMode = CheckMode.Unhecked;
break;
default:
isParsed = false;
break;
}
if (isParsed)
{
_intCalculator = CreateIntCalc(_checkMode);
_floatCalculator = CreateFloatCalc();
}
return isParsed;
}
private static Calculator<int> CreateIntCalc(CheckMode checkMode)
{
switch (checkMode)
{
case CheckMode.Default:
return new Calculator<int>(new IntMathProvider());
case CheckMode.Checked:
return new Calculator<int>(new CheckedIntMathProvider());
case CheckMode.Unhecked:
return new Calculator<int>(new UncheckedIntMathProvider());
default:
throw new ArgumentOutOfRangeException(nameof(checkMode), checkMode, null);
}
}
private static Calculator<float> CreateFloatCalc() => new Calculator<float>(new FloatMathProvider());
}
internal class Program
{
private static void Main()
{
var calc = new Calсulator();
calc.Repl();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment