Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Абстрактные классы, виртуальные методы и SOLID, применение SOLID  
V
    Опции темы
DarkinRal
Дата 2.9.2015, 03:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


This_IS_300



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 27.11.2013
Где: Ukraine/Kremenchu k

Репутация: нет
Всего: нет



Здраствуйте, пишу калькулятор с применением принципов SOLID, возникла такая трудность:

Есть абстрактный класс Операции и его наследник класс MathOperators
Код

public abstract class Operations
    {

        public double FirstValue { get; set; }
        public double SecondValue { get; set; }

        public virtual double DoOperation(double operationName)
        {

            return operationName;
        }


        public double x
        {
            set { FirstValue = value; }
            get { return FirstValue; }
        }
        public double y
        {
            set { SecondValue = value; }
            get { return SecondValue; }
        }




Код

public class MathOperators : Operations
    {
        public override double DoOperation(double operationName)
        {
           

          
           
        }


        private double Sum()
        {
            return x + y;
        }

        private double Subtract()
        {
            return x - y;
        }
        private double Multiply()
        {
            return x * y;
        }
        private double Divide()
        {
            if (y == 0)
                throw new System.DivideByZeroException();
            return x / y;
        }

есть также класс ActionMathOperation который использует в качестве поля экземпляр класса Operations 
Код


public class ActionMathOperations
    {   
        char MathAction = '\0';

        private readonly Operations _operationName;

        public ActionMathOperations(Operations operationName)
        {
            _operationName = operationName;
        }


        public void ActionMathOperation()
        {
            try
                {
                    Console.Write("Введите первое число = ");
                    _operationName.x = Convert.ToDouble(Console.ReadLine());
                    Console.WriteLine("Выберите одну из операций: +, -, *, /");
                    MathAction = char.Parse(Console.ReadLine());

                    Console.Write("Введите второе число = ");
                    _operationName.y = Convert.ToDouble(Console.ReadLine());
                    switch (MathAction)
                    {
                        case '+': Console.WriteLine("Сумма чисел составляет: " +_operationName._______); break;
                        case '-': Console.WriteLine("Разность чисел состовляет: " +_operationName._____); break;
                        case '*': Console.WriteLine("Произведение чисел составляет: " + operations.____); break;
                        case '/': Console.WriteLine("Отношение чисел составляет: " + operations.____); break;
                        
                        default:
                            {
                                Console.WriteLine(" Не верная операция");
                            }
                            break;
                    }
                    
                        }
                    catch (FormatException)
                    {
                        Console.WriteLine("Это не число, введите число");
                    }
                    catch (DivideByZeroException)
                    {
                        Console.WriteLine("Деление на ноль запрещенно!!");
                    }
                    

        }


Что нужно прописать в переопределённом методе DoOperation, что бы в методе ActionMathOperation класса ActionMathOperations можно было вызвать математические методы(Sum/Divide/Subtract/Multiply)??
класс Operations не должен содержать перечень допустимых методов, по скольку если потребуется внести изменения , то изменения должны вносится только в класс MathOperators!!(фото прикреплю там схема классов Operations and MathOperators)

Присоединённый файл ( Кол-во скачиваний: 0 )
Присоединённый файл  class.PNG 92,07 Kb
PM MAIL WWW Skype   Вверх
chupachups
Дата 3.9.2015, 11:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 0
Регистрация: 15.10.2008

Репутация: нет
Всего: 1



1) У метода DoOperation параметр поставь строковый
2) В ActionMathOperation при вызове DoOperation подставляй в параметр переменную MathAction
3) В самом метода DoOperation так же через switch...case сравнивай значение параметра и вызывай нужную функцию

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
jsharp36
Дата 6.9.2015, 00:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.10.2011

Репутация: нет
Всего: 1



Я бы сказал, что это ад. Вы ступили на зыбкую почву астронавта архитектуры ))
И с наследованием не лады.
Но и, а нужно ли вообще городить огород?

Поясню такую не всем понятную тонкую вещь, что такое ООП и почему оно популярно и где его хорошо использовать, где не очень.
ООП не потому круто, что оно МОДЕЛИРУЕТ явления. Оно круто, потому что оно подстраивается под наш язык. Не все могут думать математически, во многих случаях люди, особенно потупее, думают предложениями и языком. В языке есть подлежащие и сказуемые. Поэтому человеку КАЖЕТСЯ, что мир состоит из объектов и их поведения. У нас даже ВЕТЕР ДУЕТ. Это бессмыслица, но язык требует жертв. Поэтому в нашем языке появляется объект "ветер", который умеет выполнять действие "дуть". Хотя представление о процессе говорит, что нет отдельного объекта и действия.

Поэтому, вот следите за мыслью: ООП лучше делать там, где подлежащие и сказуемые мы хорошо представляем. А вот с операцией и с оперированием происходит какая-то ерунда. Мы умеем называть операцией вычитание, да. Но вычитание - это то же что "вычитать". И строя на ООП такую архитектуру, вы все время упираетесь в вопрос, класс это или его поведение?
Сишарп отлично работает с двумя парадигами, с функциональной тоже. Поэтому советую взглянуть в таких случаях на предтавление задачи иначе.
Вот с ходу решение вашей задачи. (Просто набираю не проверяя. Надеюсь, логику поймете, а возможные ошибки простите).

Код

Dictionary<string, Func<double, double, double>> operations = new Dictionary<string, Func<double, double, double>> {
    { "+", (d1, d2) => d1 + d2 },
    { "-", (d1, d2) => d1 - d2 },
    { "*", (d1, d2) => d1 * d2 },
    { "/", (d1, d2) => d1 / d2 },
}
public double DoOperation(double d1, double d2, string operation)
{
   return operations[operation](d1, d2);
}


Никаких наследований, никаких сложностей, код очень простой и понятный. Только ловите эксепшины вызывая метод и выводите в случае ошибки понятнее сообщение.

Теперь если поняли суть, то можно к ООП перейти. На самом деле в плюсах например, виртуальные функции - это по сути словарь, который я выше показал. Т.е. там таблица виртуальных функций. И сама иерархия объектов по сути реализовывает словарь, когда подменяются указатели на функции. Если хотите с помощью ООП это реализовать, то логика должны быть похожей. Виртуальная функция должна быть одна в базовом объекте, а наследники переопределяют. Т.е.:

Код

public abstract class Operations
{
    public double X { get; set; }
    public double Y { get; set; }

    public abstract double DoOperation();
}


А наследники - конкретные операции:
Код

public class Sum: Operation
{
     public override double DoOperation()
     {
         return X + Y;
     }
}
public class Substraction: Operation
{
     public override double DoOperation()
     {
         return X - Y;
     }
}
public class Product: Operation
{
     public override double DoOperation()
     {
         return X * Y;
     }
}
public class Division: Operation
{
     public override double DoOperation()
     {
         return X / Y;
     }
}


Далее делаете что-то вроде фабричного метода, в котором как угодно делаете порождение объектов. Можете switch использовать или опять же словарь. Но допустим switch:

Код

public Operation CreateOperation(double x, double y, string operation)
{
   switch (operation)
   {
      case "+": return new Sum { X = x, Y = y };
      case "-": return new Substraction{ X = x, Y = y };
      case "*": return new Product { X = x, Y = y };
      case "/": return new Sum { X = x, Y = y };
      default: throw new Exception(string.Format("Operation {0} is not supported", operation));
   }
}


И далее просто делать вызов после получения операции:
Код

Console.WriteLine("Выберите одну из операций: +, -, *, /");
var operation = CreateOperation(Console.ReadLine());
....
operation.X = ...
....
operation.Y = ....
....
Console.WriteLine("Результат: " + operation.DoOperation());


Заметили насколько больше плясок с ООП, чем просто со словарем? Потому что не подходящее средство, а механизм работы в принципе тот же.
Хотите, чтобы каждый наследник возвращал и словами что он делает ("Сумма чисел составляет: " и т.д.), переоределяйте еще методы, ToString() или что-то другое свое.  

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
chupachups
Дата 6.9.2015, 15:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 0
Регистрация: 15.10.2008

Репутация: нет
Всего: 1



все вышесказанное верно и замечательно, НО...
100 пудов автору поста задали задачу в технаре или универе или т.п., и тогда препод ожидает, что задача будет решаться изучаемыми в настоящее время методами и средствами, а значит "умничать" - равносильно списать из инета и схлопотать "незачет".
это я сужу по себе, с одной лишь поправкой - в мою студенческую бытность инета не было и все работали мозгом, так вот мои преподы никак не могли усвоить истину, что мой мозг не хуже их, а в чем-то и лучше, в итоге постоянно страдал за "умничество"

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
jsharp36
Дата 6.9.2015, 16:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.10.2011

Репутация: нет
Всего: 1



Может быть. Но если не выходить за рамки ООП, то я показал как с помощью ООП решать задачу. Даже в этом случае у автора ошибка.

Объектно-ориентированное проектирование - простая на самом деле вещь. Вообще, я бы советовал научиться для начала хорошо проектировать реляционные базы данных, а после них учится проектировать классы. Там многое аналогично.

В ООП надо всего лишь определять общее и частности. Общее в базовый класс, частности в наследники. И при этом представлять смысл, а не коробочки и контейнеры с алгоритмами. Смысл - это то, что формулируется. Если люди начинают себе представлять код как механизм, получаются казусы в проектировании.

Когда автор думал о наследовании, он начинал видим одумать так: есть операции, есть более конкретные - математические операции. Но при этом думал множествами операций. Когда как если предположить ось наследования в математических операциях, то надо рассуждать так: есть НЕКИЕ операции. Каждая из которых выполняется ПО СВОЕМУ. Т.е. класс операций должен представлять одну операцию, в которой будет виртуальный (абстрактный) метод, который будет выполнять по своему каждая операция.

А он классы сделал множествами операций. В результате в MathOperations наделал отдельными методами то, что делать должна каждая отдельная операция. Т.е. никакого смысла и толка он наследования не осталось. И далее у него случилась несостыковка, как же эти методы взять и вызывать красиво при наследовании.
Никак. Сшить франкенштейна можно, делая пару раз дерево из if-ов или switch. К ООП это не имеет отношения.

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
chupachups
Дата 6.9.2015, 18:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 0
Регистрация: 15.10.2008

Репутация: нет
Всего: 1



не факт, может быть он мыслил математическими, логическими и черт-знает-еще-какими операциями, и хотя каждая из групп тоже в принципе состоит из множества операций - делать их отдельными классами не всегда целесообразно.
у меня в практике был такой пример - составление блок-схемы некоего бизнес-процесса, так я тоже не стал делать отдельные блоки на каждый чих, а сделал (например) один блок "функция" и в нем уже указывалась нужная функция и выбирались аргументы.

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
jsharp36
Дата 6.9.2015, 18:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.10.2011

Репутация: нет
Всего: 1



В смысле не факт? Сам механизм виртуальных функций по сути всего лишь заменяет ифы и позволяет однообразно вызывать разные функции.

Тут вопрос не в том, что надо на каждый чих разбивать на блоки. А в том, что нет никакой выгоды от наследования. Если он уже написал на каждую операцию свои методы, то в общем он мог и в одном классе написать, мог сделать такой же словарь с делегатами.

Смотрите. Если от множества наследуется множество, Operations -> MathOperations - то вы "не пробъете" через иерархию наследования никакие полезные методы. Я по крайней мере таких не представляю.
Да я вообще слабо понимаю код у автора, потому что Operations только по названию множество, а по телу - одна операция.

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
jsharp36
Дата 6.9.2015, 19:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 4
Регистрация: 8.10.2011

Репутация: нет
Всего: 1



Ладно, ок. Соглашусь, что я просто не понимаю код автора. Может у него не стояла задача, использовать наследование.
Но тогда Operations - лишний класс. Два поля типа double намекают, что это математическая операция. В MathOperations вставить работу со словарем как у меня первый пример с делегатами на уже созданные методы. Или хотя бы switch. В методе DoOperation. И, конечно, передавать текстовое имя, не double.

Что написано в ActionMathOperations даже комментировать сложно. Выкинуть всё. Передать в объект MathOperations значения и вызвать DoOperation передав имя операции.

Но если тем более это для студента задачка, то лучше использовать мой вариант с наследованем. Скорее это преподаватели и ожидают

Этот ответ добавлен с нового Винграда - http://vingrad.com
PM MAIL   Вверх
DarkinRal
Дата 6.9.2015, 20:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


This_IS_300



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 27.11.2013
Где: Ukraine/Kremenchu k

Репутация: нет
Всего: нет



1. По поводу double в DoOperations, то я в тот момент экспериментировал, что из этого получится...
2. По поводу названия класса Operations, до этого там был не один метод, а перечисление абстракт. матем. методов...а в классе MathOperations их переопределял,и в классе ActionMathOperations создавал экземпляр класса и спокойно через switch использовал, но препод, сказал что так не должно быть, и что надо использовать принцип Dependency inversion principle..
3. jsharp36 и chupachups, спасибо за разъяснения и примеры, когда я только получил это задание, у меня тоже возникало желание сделать каждую мат. операцию отдельным классом, но потом решил пойти как написано в п.2, но увы это оказалось не верным решением.
PM MAIL WWW Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.1168 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.