Created
October 10, 2017 10:56
-
-
Save pkuderov/9e2f5f8e8559b6b8b25f99fcbd837623 to your computer and use it in GitHub Desktop.
Slightly refactored calculator (to Shishkin)
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
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