C# — ООП в C#, помогите


Содержание

C# объектно-ориентированное программирование (ООП)

Опубликовано Константин Туйков в 13.07.2020 13.07.2020

Ранее мы изучили, что такое объекты и классы. Также, рассмотрели свойства, которыми объекты обладают. Кроме того, были затронуты действия, которые могут совершаться над объектами, называемые методами. Главной задачей объектно — ориентированного подхода является упрощение процесса разработки. Весь подход стоит на трех основных принципах: наследование, инкапсуляция и полиморфизм. Рассмотрим каждый из них.

Наследование

Используя наследование, мы может определить ряд дочерних классов. Они же будут наследовать свойства и методы базового. Таким образом, мы расширяем функциональность базового класса.

Вернемся к ранее рассмотренному примеру кода. Был описан класс «Персонаж», который является базовым. От него могут быть унаследованы более «узкие» классы персонажей, такие как «Воин», «Стрелок», «Маг» и другие. Следует заметить, что класс может наследоваться только от одного базового класса.

Инкапсуляция

Этот принцип гласит о том, что внутреннее устройство объекта должно быть скрыто от пользователя. Так, пользователю предоставляется доступ только к определенному набору методов, которые необходимы для взаимодействия с объектом. Под пользователем в данном случае понимается наследник или разработчик. По сути своей объект должен быть абсолютно автономным и иметь определенный набор инструментов, позволяющих управлять им. К примеру, стрелок не обязан иметь доступ к внутреннему устройству оружия. Однако ему необходимы методы для ведения огня и перезарядки, а также пополнению боезапаса. И, соответственно, доступ к определенным частям оружия.

Полиморфизм

Достаточно сложное в определении понятие. Если говорить упрощенно, мы можем использовать свойства и методы потомков. К примеру, мы объявили несколько потомков класса «Персонаж».

При подобной записи warrior будет являться объектом класса «Воин» несмотря на то, что типом мы указали базовый класс.

Наследование от Object

В C# любой класс является наследником класса Object. Благодаря этому свойству экземпляр любого класса обладает рядом полезных методов.

  • Equals() — сравнение переданного в качестве параметра объекта с текущим.
  • GetHashCode() — возвращает хеш-код текущего объекта в памяти.
  • GetType() — позволяет идентифицировать тип объекта.
  • ToString() — приводит класс к строке.
  • Finalize() — отвечает за уничтожение объекта (вызывается автоматически).
  • MemberwiseClone() — возвращает точную копию объекта.

Любой из этих методов может быть переопределен для изменения или дополнения функциональности.

Итак, это минимум, необходимый для понимания что такое объектно-ориентированное программирование. Переопределение методов мы рассмотрим далее. Удачных экспериментов, коллеги.

Введение в C# или что нужно знать о языке CSharp

И так… я наконец решил собрать свой багаж знаний в нечто единое для того, что бы помочь начинающим разработчикам ПО в нелегком деле изучения языка программирования C#. Я прекрасно помню, когда впервые познакомился с данным языком программирования и как впервые пытался написать программу. Я помню все трудности и не понятные моменты. Именно с ними я и хочу поделится со своими читателями.
Почему я начал писать о C#, а не о PHP или JavaScript? Ответ прост — C# самый читаемый раздел в моем блоге и именно по данному языку мне задают самое большое число вопросов.
Я буду очень признателен всем посетителям моего ресурса, которые будут помогать мне в написании данной методички (книги или что-бы из этого не получилось). Пишите свои отзывы, задавайте вопросы, указывайте не до конца раскрытые темы. Все это я буду учитывать и вносить необходимые правки.

Изучение языка программирования C# процесс сложный, если Вы не знакомы с объектно ориентированным программированием (ООП), но возможный. Так же Вам нужно иметь представление о том что такое компьютер и как он работает. Все, что я буду писать, будет ориентированно на людей — не знакомых с программированием, либо имеющим базовые навыки в данной области. Я не буду углубляться во все нюансы языка программирования CSharp, что бы не загружать Вас. А так же не буду описывать все типы данных, все ключевые слова и т.п. вещи. Моя задача донести базовые знания, отработав и запомнив которые, Вы сможете с легкостью изучать рассматриваемый язык более подробно самостоятельно.

Примечание: В качестве подготовительной работы Вам необходимо скачать Visual Studio C# с сайта Microsoft и установить его на свой компьютер. Именно в этой среде Вы можете создавать свои приложения.

И так! Начнем процесс обучения!

Язык программирования C# — ООП во всей красе. Даже самая примитивная программа будет реализована «сложно» в понятиях начинающего разработчика. Именно поэтому ключевым моментов изучения языка C# является понимание принципов ООП. Я не просто так выделил слово понимание — Вам необходимо именно понимать ООП, Вы можете выучить все принципы — но писать программы, а тем более дорабатывать сущесвующие, Вам будет сложно. И причина будет в том, что Вы не сможете пересказать принципы ООП своими словами, а значит не сможете понять то, как реализует эти принципы другой разработчик.
ООП конечно вещь хорошая, однако чтобы начать писать свои первые программы нужно знать еще некоторые вещи: типы данных, операции и конструкции языка. Именно о них я и расскажу сегодня. Вам нужно будет выучить эти вещи. Выучить так, что бы у Вас не было ни малейшего колебания в том какой тип данных Вам нужен, что Вам нужно писать чтобы объявить его или написать цикл, или условие.

Типы данных
Разрабатывая ПО, вы работаете с различной информацией, которая может быть выражена цифрами, предложениями, буквами, логическими следствиями и т.д. В связи с этим в C# были созданы следующие типы данных:

Int32 (или int) — тип данных для хранения целых чисел (1, 2, -100, 0, 23413123) в диапазоне от -2 147 483 648 до 2 147 483 647.
Int64 (или long) — тип данных для хранения целых чисел (1, 2, -100, 0, 23413123) в диапазоне от -9223372036854775808 до 9223372036854775807.
Double (или double) — тип данных для хранения десятичных чисел (1, 2.123, -100.11232345, 0, 23413123.1).
Boolean (или bool) — тип данных для хранения результата логического выражение. Принимает значение ИСТИНА (true) или ЛОЖЬ (false).
Char (или char) — тип данных для хранения одного символа (‘a’, ‘1’, ‘-‘, ‘ ‘). По своей сути данный тип — это число c кодом символа. Именно поэтому char может конвертироваться в int и наоборот.
String (или string) — тип данных для хранения строк. По своей сути данный тип — массив (поговорим о них позже) из символов char.

Важно: Выше указаны далеко не все типы данных языка C#. Однако в начале Вашего пути их будет вполне достаточно
Важно: Любой тип данных может быть использован в массивах. Что это такое и зачем они нужны мы рассмотрим позже

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

+ — сложение чисел, либо «склеивание» (конкатенация) строк. Не применяется при работе с типами bool, char.
— разница двух чисел.
* — умножение двух чисел.
/ — целая часть от деления двух чисел при использование типа int. Результат деления при использовании типа double.
% — остаток деления двух чисел. Именно остаток, а не дробная часть.


&& — логическое И. Применяется для типа bool.
|| — логическое ИЛИ. Применяется для типа bool.
! — логическое НЕ (отрицание). Применяется для типа bool.

Задачи по ооп для C#?

kafkiansky, Я считаю что принимать на веру какие-то догмы и устраивать за них священные войны не корректно. Это к слову о диссидентах.
Про «труъ» ООП тоже пока не было ничего, и как раз вот эти вот «делай так потому что ООП/MVC etc.», без разницы «тру» или нет больше вреда нанесут новичкам, я считаю, и при верно выстроенной стратегии обучения к ООП/ФП новички должны приходить осознавая для чего это нужно, какие решаются проблемы, и в чем в принципе заключаются идеи рассматриваемого подхода.

В программировании все очень туго и размыто с понятиями плохо/хорошо, и главное что меня беспокоит в данном случае, это подмена понятий и навязывание ложных идеалов

C# WindowsForms ООП (помогите с пунктами 4 и 5) [закрыт]

Задание: 1) Определить класс Student, который имеет:

  • закрытое поле типа string, в котором хранятся данные студента;
  • закрытое поле типа string для информации о форме обучения;
  • закрытое поле типа int для номера группы;
  • закрытое поле типа int [] для информации об оценках (5 оценок) на экзаменах, которые получил студент.

2) В классе Student определить конструкторы:

  • конструктор c параметрами типа string, int, int [] для инициализации полей класса;
  • конструктор без параметров, инициализирующий поля класса значениями по умолчанию.

3) В классе Student определить свойства c методами get и set:

  • свойство типа string для доступа к полю с данными студента;
  • свойство типа string для доступа к полю с формой обучения;
  • свойство типа int для доступа к полю с номером группы;
  • свойство типа int [] для доступа к полю со списком оценок экзаменов.

4) В классе Student определить:

  • свойство типа double (только с методом get), в котором вычисляется средний балл как среднее значение оценок в списке сданных экзаменов;
  • метод void Add () для добавления нового студента;
  • перегруженную версию виртуального метода string ToString() для формирования строки со значениями всех полей класса, включая список оценок;
  • метод string ToShortString(), который формирует строку со значениями всех полей класса без списка оценок, но со значением среднего балла.

5) В обработчике события загрузке формы:

  • Создать 4 объекта типа Student.
  • Преобразовать данные в текстовый вид с помощью метода ToShortString() и вывести данные.
  • Преобразовать данные в текстовый вид с помощью метода ToString() и вывести данные.
  • Интерфейс разработать по своему усмотрению.

Я сделал 1-3 пункты. Заранее спасибо!

Вопросы:

    Как сделать перегруженную версию виртуального метода string ToString()?

Я написал так, но не знаю, правильно ли?

Правильно ли я сделал пункт с методом ToShortString()?

Как именно нужно создать 4 объекта типа Student?

И как преобразовать данные в текстовый вид с помощью метода ToShortString() и ToString() и вывести данные?


Тест знаний ООП в C#

категория
C#
пройден
вопросов в тесте
требуется
сертификационный нет
в рейтинге да
время 25 минут
автор admin

Введение в ООП в C#

В языке программирования C# (C Sharp) очень мощная поддержка объектно-ориентированного подхода.

Это позволяет писать программные продукты, которые просты в плане поддержки и расширения функционала.

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

Подробнее о рассматриваемых вопросах смотрите в разделе «Структура теста C#».

Целевая аудитория теста по C#

Уровень вопросов теста C# варьируется от простого до сложного, хотя основная масса вопросов оцениваются как «средний уровень». Именно поэтому тест будет интересен большинству программистов не зависимо от опыта работы.

Перед прохождением теста необходимо иметь уверенные знания в синтаксисе языка C#, а так же знать основные термины ООП, такие как наследование, инкапсуляция, переопределение (override), перегрузка (overload), класс, объект, интерфейс и так далее.

Цукерберг рекомендует:  Создаем фотогалерею с помощью Bootstrap 4

Структура теста по ООП в C#

В тесте рассматриваются вопросы таких направлений:

  • Классы и объекты — рассматриваются вопросы описания классов, инстанциирования объектов, статические конструкторы классов и так далее.
  • Жизненный цикл объектов — рассматриваются конструкторы и деструкторы, финализация
  • Интерфейсы (interface) — рассматривается синтаксис интерфейсов, а также их реализация
  • Контроль доступа — рассматриваются модификаторы доступа к полям и методам классов
  • Наследование и полиморфизм — рассматриваются вопросы наследования классов, а так же выбор методов в runtime

Развитие теста по ООП в C#

Главное направление развития — это пополнение пула вопросов теста по ООП в C#. Надеемся, что сообщество поможет нам в этом.

Кроме этого, было принято решение о явном разбиении вопросов теста на тематики. Это позволит определить темы, которые требуют лучшего покрытия.

Ждем Ваших отзывов.

Важно: Ниже обсуждается только тест в целом: покрытие тематик, типы вопросов, пути улучшения теста и так далее.

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

Обучение C# (c sharp)

Данный видеокурс представлен для новичков в языке программирования C#. Если Вы решили, что готовы начать обучение программированию, то стартуйте вместе с нами! Курс программирования C# Стартовый поможет Вам начать Ваше знакомство с языком программирования C#. Узнайте основы современного программирования на Visual C # 2012 и приступите к созданию Вашего первого приложения на языке C#.

Этот видео урок помогает разобраться с двоичной и шестнадцатеричной системами счисления. Также Вы узнаете, какие простые типы данных есть в языке программирования C# и сможете правильно определять, какой тип данных следует использовать в конкретной ситуации.

Этот видео урок помогает разобраться с типами данных. Вы узнаете, какие простые типы данных есть в языке программирования C# и сможете правильно определять, какой тип данных следует использовать в конкретной ситуации.

На этом видео уроке Вы изучите условные операторы, позволяющие разрабатывать алгоритмы, в которых от выбора пользователя или от других условий будет зависеть результат. В этом уроке будут рассмотрены такие условные конструкции языка программирования C# — if/else, switch, тернарный оператор.

Данный видео урок рассматривает понятия логических и побитовые операции. На видеокурсе объясняется применение и использование операций конъюнкции, дизъюнкции, исключающего «или», логических операторов, операторов сдвига в языке программирования C#.

Видео урок полностью посвящен циклическим конструкциям — то, без чего не обойдется ни одна программа. В программировании часто встречаются действия, которые необходимо повторить несколько раз. Для решения подобных задач, в которых требуются неоднократное повторение операций, Вам необходимо разобраться с конструкциями, которые будут изучены в этом видео уроке.


Чтобы научится программировать на языке C#, мало изучить условные и циклические конструкции. Необходимо использовать еще и другие возможности языка C#. В этом видео уроке Вы рассмотрите важный элемент любого приложения — метод.

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

Главная задача для бoльшинствa приложeний cводится к aнализу дaнных и вычиcлений, производимых нaд бoльшими объeмами дaнных. Для тoго, чтoбы в Вaших прилoжениях пoявилась возможноcть хрaнить многo однoтипных знaчений, Вaм нужно cоздавать маcсив. Видeо урок обучит Вaс нe тoлько кaк сoздать мaссивы, но и произвoдить oсновные опeрации нaд ними. Вы узнаeте, какиe нужно использовaть циклы при рaботе с мaссивами и изучите такие типы массивов как одномерные, многомерные, зубчатые.

Практикум курса C# Стартовый на примерах из GTA 5

Роман Самчук подготовил новый необычный курс для желающих выучить C#. Чтобы знания усваивались необходима практика, а что может быть интереснее и практичнее, чем мод для GTA V? Именно на его примере мы разберем все основные синтаксические конструкции языка и их особенности употребления. Видео будет крайне полезно новичкам в программировании.

На практике рассматриваем, как в языке программирования C# создаются циклы и таймеры, для чего они существуют и какая их непосредственная польза.

На практике рассматриваем, как в языке программирования C# создаются циклы и таймеры, для чего они существуют и какая их непосредственная польза.

Встречайте новый урок от Романа Самчука. На предыдущих занятиях мы рассмотрели с вами, как создавать статические вещи в игре. В этот раз, мы добавим в игру невероятно удобного персонажа — киллера. Научим его ходить, выбирать цель и делать за нас работу — убивать персонажей в игре.

В этом уроке будем работать с native function, которые есть в игре. Будет показано, как их можно вызывать, как передавать им различные параметры. Также, создадим машину с четырьмя врагами и попробуем из перестрелять.

Видео курс C# Базовый.

На первом уроке видео курса C# Essential будет рассмотрено: Концепции объектно-ориентированного программирования (ООП). Классы в языке C#. Основы работы с конструктором. Назначение и использование свойств (get, set). Главных парадигмы ООП.

В видео уроке «Классы и объекты. Диаграммы классов» будет продолжена тема урока «Введение в OOП. Классы и объекты», а также будет раскрыта тема возможности языка программирования C# разделять определение класcа между двумя и/или более файлами, именуемая частичными или partial классами. После ознакомления с частичными классами в С#, будут рассмотрены диаграммы классов, связи отношений между классами такие как ассоциация, агрегация, композиция, реализация, самоассоциация зависимости и другие.

В ходе видео урока Вам будет представлена информация о двух основных парадигмах ООП — полиморфизме и наследовании, также Вы познакомитесь с модификаторами доступа и виртуальными членами.

В видео уроке будет продемонстрированы практические примеры создания и использования абстрактных классов и интерфейсов. Абстракция позволяет программисту рассматривать объект, не разбирая сумму сложных частей, из которых состоит данный объект. В ходе видео урока Вы получите необходимые знания, которые помогут Вам разобраться с понятием абстракции в С#.

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

В видео уроке будут рассмотрены статические классы, принципы создания и практического применения статических членов. Также, в ходе видео урока будет объяснена работа и использование расширяющих методов.Во второй части видео урока тренер рассмотрит понятие вложенных классов и шаблон проектирования «Одиночка» (Singleton).

Описание: В видео уроке будет представлена полная информация о структурах, рассмотрены отличия между классами и структурами, а также рассказаны практические советы по их применению. Структуры — фундаментальные типы данных в языке программирования C#.

В данном видео уроке будут рассмотрены такие понятия как упаковка (boxing) и распаковка (unboxing), структурный тип DateTime, а также работа с перечислениями(enum). В ходе занятия тренер ознакомит студентов с практическими примерами, которые позволят с легкостью использовать и применять полученные на уроке знания.

Видео урок позволяет студенту понять работу лямбда-выражений и делегатов. Начинающие программисты, продумывая интерфейс очередного класса, часто понимают, что очень полезной могла бы быть возможность передавать в качестве аргумента методов часть исполняемого кода. Делегаты позволяют Вам реализовать подобный подход.

В языке программирования C# существует два механизма для создания кода, который будет повторно использован через различные типы — уже рассмотренное ранее наследование и обобщения. Обобщения, в отличии от наследования, выражают повторное использование кода через использование универсальных шаблонов(generics), в которых применяются различные типы данных на этапе выполнения.

Описание: В видео уроке «Ограничения универсальных шаблонов» Вас ждет продолжение знакомства с универсальными шаблонами в C#. Вы узнаете, каким образом можно использовать ограничения для обобщенных типов данных. В ходе видео урока тренер остановит Ваше внимание на работе с Nullable типами, а также операциях поглощения, показав примеры практического их использования.

Весь видео урок будет всецело посвящен работе с событиями в C#. В деталях будет рассмотрено, каким образом создавать «издателей» и «подписчиков», а также обращаться к созданным событиям и вызывать их. Тренер уделит отдельное внимание делегату EventHandler и базовому классу EventArgs, а также работе с ними

В процессе просмотра видео урока Вы получите основные сведения, которые потребуются Вам для работы с многопоточностью в языке программирования C#. Многопоточность — важное средство многозадачного программирования среды .NET. Видео урок даст Вам основное понимание многопоточности в языке программирования С#. Также в ходе урока тренер расскажет Вам об использовании делегатов ThreadStart и ParameterizedThreadStart и объяснит работу с критическими секциями, как средствами синхронизации доступа потоков к различным разделяемым ресурсам.

В видео уроке будут объяснены коллекции, их назначение и примеры их практического применения. Также Вы детально изучите базовые интерфейсы IEnumerable, IEnumerator. Также в ходе видео урока тренер рассмотрит с Вами примеры создания и использования пользовательских коллекций, продемонстрирует наглядные примеры по работе оператора yield.

В этом видео уроке Вы узнаете какие системные исключения существуют в языке C# и как правильно обрабатывать исключительные ситуации с помощью конструкции try — catch — finally. Также вы научитесь создавать свои объекты исключения. При выполнение приложения может сложится ситуация, когда корректное выполнение приложения невозможно. Например, приложение читает файл на диске, которого нет.

В данном видео уроке тренером будет рассмотрен базовый класс object его применение и использование, а так же техника перегрузки операторов. В процессе объяснения будет затронута техника клонирования, а также будет рассмотрено назначение шаблона проектирования «Прототип» (Prototype) и интерфейса ICloneable.

Данный видео урок будет очень важен для понимания всех современных технологий. В ходе видео урока тренер познакомит Вас с основами LINQ, а также с анонимными и динамическими типами, которые активно используются при построении запросов. Язык LINQ — это набор функций, который позволяет значительно расширить возможности синтаксиса языка программирования C#.

В этом видеоуроке Вы узнаете, что такое пространства имен и как правильно организовывать проект используя пространства имен. Также Вы узнаете, как создавать библиотеки (DLL) в языке C#. Тренер рассмотрит тип проекта Class Library и на простом примере объяснить для чего используются библиотеки.


C# и концепция программирования ООП

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

  • Императивное программирование. Это классический метод создания программ, выполняемых на машине Тьюринга. Машиной Тьюринга, по факту, является любой современный компьютер, за исключением, разве что квантовых компьютеров, но там совсем другая концепция. Если говорить простыми словами, то императивное программирование – это просто создание программы из набора инструкций. Классический пример – машинные коды или язык ассемблер. Первые языки высокого уровня, такие как Basic и Pascal, а также язык C не далеко ушли от данной концепции.
  • Декларативное программирование. Если в случае императивного программирования мы описываем компьютеру, как он должен выполнить задачу (описываем алгоритм на определенном языке), то в декларативном программирование мы говорим компьютеру что надо сделать, а вот как он это будет делать, уже его проблемы. Идея хорошая, по сути, это первый шаг к созданию Искусственного Интеллекта. Только вот проблема, что компьютер – это «тупая машина», которая ничего не может делать самостоятельно, без детально описанного алгоритма. Поэтому дальше таких чисто декларативных языков, как Prolog (язык логического программирования), HTML и SQL дальше дело не зашло. Кроме того, такие языки не полны по Тьюрингу, и поэтому область их применения весьма ограничена.
  • Структурное программирование. Это по сути, то же самое императивное программирование, но с использованием определенных правил. В частности, нельзя использовать оператор GOTO. Вся программа состоит из набора подпрограмм, циклов и ветвлений. По сути, это первая попытка структурировать код и первый шаг к ООП.
  • Функциональное программирование. Здесь процесс вычислений функций в их математическом понимании. Суть в том, чтобы программу описывать исключительно языком математики. Что характерно, при функциональном программировании очень часто используется рекурсия и прочая «бяка». Пример подобных языков lisp и F#. Так как для написания программы при таком подходе приходиться буквально «выворачивать мозги наизнанку» данная концепция не нашла широкого распространения.

А теперь попробуем написать на языке C# что-нибудь, например, компьютерную игру. Ну например, игру «Мафия». Чтобы в нее могли играть как реальные игроки, так и виртуальные (компы). И еще чтобы ее потом не трудно было переделать в игру «Вторжение рептилоидов». В этом на как раз и поможет ООП.

И так, прежде чем приступить, я расскажу о правилах игры «Вторжение рептилоидов». Как и «Мафия», это пошаговая игра. В ней есть следующие персонажи:

  • Рептилоиды. Их цель чипировать всех землян.
  • Земляне. Цель – не дать себя чипировать и уничтожить рептилоидов и ZOG.
  • ZOG. Цель
    украсть технологию рептилоидов и всех чипировать (и тех и других).
  • Чипированный. Цель – не спалиться что он чипирован и быть лояльным тому, кто его чипировал. То есть, чипированный не может указать на того, кто его чипировал. При попытке нарушить это правило чип взрывается.

Дополнительно можно добавить такого персонажа как хакер, который может взламывать чипы. И да, надо учесть, что как в «Мафии», так и в игре «Вторжение рептилоидов» пользователи могут захотеть, чтобы программист добавил в игру новые персонажи или изменил их геймплей.

Подробно правила описывать не буду, они будут придуманы, когда дойдем до «Вторжения рептилоидов». А сейчас будет программировать «Мафию». Прежде чем откроем Visual Studio, сядем и немного подумаем. Во-первых, какие у нас тут есть абстракции? Давайте перечислим их:

  • Персонаж. Персонажи бывают разные, они могут находиться в разных состояниях (живой, мертвый, чипированный). Они могут совершать какие-то действия. Возможно, у каждого персонажа будет свой набор допустимых состояний и допустимых действий. Причем, персонажи могут управляться как человеком, так и программно (иметь некое подобие ИИ).
  • Интерфейс человек – персонаж. Должен позволять принимать команды управление персонажем с клавиатуры, от мышки и так далее. Следует учесть, что игра может быть сетевой. Сейчас мы не будет реализовывать сетевой вариант игры, но на будущее надо предусмотреть такую возможность. Кроме того, необходимо обеспечить соблюдение правил игры.
  • Контроллер правил. Если правила игры надо соблюдать, то логично выделить отдельный класс, который бы позволяя делать игрокам только то, что разрешают правила. Это не должен делать ни персонаж, ни интерфейс человек – персонаж, ни модуль ИИ, который будет управлять виртуальным игроком.
  • Блок управление персонажем. Должен уметь соблюдать правила игры и принимать решение о тех или иных действиях. Правила он будет получать, конечно, от контроллера правил, но должен держать их в «уме» чтобы принимать решения.
  • Ядро игры. Осуществляет взаимодействие между объектами, выполняет шаги игры.

Далее, как абстракции взаимодействуют? Это можно описать следующими шагами:

  1. Ядро игры выполняет шаг. Например «город спит, просыпается мафия». Выполнение шага заключается в том, чтобы изменить состояния персонажей. Тут сразу обращаем внимание, что кроме состояний «жив», «мертв», «чипирован», есть еще состояние «спит». Каждое состояние накалывает на персонаж определенные ограничения в плане того, какие действия он может совершать.
  2. Ядро передает управления персонажам (по очереди каждому). Персонаж, получив управление, выполняет некие действия, дозволенные его состоянием (или ничего не делает, если состояние не позволяет). В результате действий персонажей другие персонажи могут менять состояние. При том, стоит заметить, что изменение статуса должно произойти после завершения шага, так как может быть такое, что игроки убивает, например, друг друга. Но если они выполняют действия по очереди, то такое «не прокатит», так как убьет только тот, кто выполнит действие поровый. Второму не даст совершить действие его состояние «мертвый».
  3. Ядро посылает информацию для отображения (или позволяет пользовательскому интерфейсу отобразить новые состояния).

Теперь можно потихоньку начать программировать. Итак, заходим в Visual Studio и создаем новый проект:

Для простоты создадим пока игру на Windows Forms:

Не забудьте также нормально назвать проект и решение. Вот как у нас будет выглядеть Visual Studio после создания:

Важно отделить интерфейс от игровой логики, так как кто его знает, может, потом мы заходим сделать WEB-приложение и нам потребуется переписывать интерфейс Windows Forms на ASP. NET. Если мы все смешает в одну кучу, то это будет сделать ой как не просто. А если вовремя отделим интерфейс от логики, то нам надо будет просто переписать отображение для пользователя, и все.

Чтобы отделить интерфейс от логики, создадим еще один проект (который и будет отвечать за игровую логику. Для этого щелкнем правой кнопкой мыши по корню решения и выбрать «Добавить» -> «Создать проект»:

Проект назовем GameCore, а тип «Библиотека классов» (Class Library):

Образовавшиеся по умолчанию файл Class1 можно удалить, или переименовать в нужный класс, когда мы его будем создавать. А пока добавим ссылку в главном проекте на нашу библиотеку:

При этом откроется окно выбора ссылок, надо выбрать проект GameCore:

Создадим классы, пока это будут заготовки. Начнем с главного класса – Core. Добавляем (или переименовываем Class1.cs):

Начнем реализовывать наш игровой алгоритм. И сразу встает необходимость создать еще один класс создать абстрактный класс персонажа (назовем его AbstractUnit). Почему класс абстрактный? Потому, что мы еще не знаем, как будут реализованы действия каждого конкретного персонажа, но у них есть нечто общее:

Scripts

Реклама


Свежие записи

Архивы

Рубрики

Партнеры

Почему C# хуже C++?

ООП ради ООП

Программируя долгое время на C++, я не задумывался о минусах ОО подхода. Один мой знакомый постоянно спорил со мной, утверждая, что ООП — это зло. Тогда я не понимал истинных причин его выводов. Лишь начав программировать на C#, я осознал всю несостоятельность объектно-ориентированной парадигмы. Дело в том, что пока я писал на C++, я активно пользовался процедурной парадигмой и ООП лишь помогало там, где оно имело место. В C# (как впрочем и в Java) объектно-ориентированная парадигма вытеснила все другие. В итоге в C# мы имеем множество статических классов-Helper`ов и Utility. Гипертрофия ООП в C# приводит к тому, что классы содержат невероятно избыточное количество данных для настройки своего поведения и поведения своих потомков. Подробнее о недостатках ООП подхода можно почитать здесь. Приведу одну цитату:

Единственный способ сделать повторно используемые бизнес компоненты на этом уровне — сделать их сверх-настраиваемыми путём добавления таких штук как движки правил и встраиваемые языки. Такую модель я бы не стал называть моделью компонента. Скорее моделью очередного экземпляра bloatware. Обещание о повторном использовании ушло, люди либо покупали огромные bloatware системы(неудачники), или разрабатывали свои специальные бизнес объекты в своих собственных проектах.

Кроме того, Вы можете ознакомиться со знаменитой статьёй Ричарда Гэбриэла «Объектная парадигма провалилась» и её триумфальное возрождением «Почему объектно-ориентированное программирование провалилось?». Советую обратить внимание ещё и на эту статью. Подводя итог вышеперечисленным статьям, можно сказать, что концепция ООП не справилась с возложенными на неё ожиданиями, вместо этого она усложнила разработку и архитектуру приложений. C++ же не настаивает на использовании ООП и позволяет получить от него максимум выгоды, используя там, где это оправдано. Доклад Джека Дидриха довольно точно описывает моё отношение к ООП: не нужно писать класс, если можно написать функцию. Исходя из того, что C# ничего, кроме ООП не предлагает, в дальнейшем я буду рассматривать C# и C++ с точки зрения объектно-ориентированной парадигмы.

Наследование

Наследование в C++ — это одна из самых широких возможностей. C++ позволяет использовать один из нижеприведённых вариантов или любую их комбинацию:

  • Наследование интерфейса;
  • Наследование реализации;
  • Множественное наследование;
  • Виртуальное наследование.

C# изо всего этого поддерживает лишь наследование интерфейса, наследование интерфейса вместе с реализацией и множественное наследование интерфейсов без реализации. Вообще говоря, множественное наследование интерфейсов с реализациями используется довольно редко, а виртуальное ещё реже. Но при возникновении такой необходимости в C# приходится применять сложные обходные пути. К сожалению, реальные примеры слишком сложны, а книжные мало убедительны, тем не менее, я постараюсь показать полезность множественного наследования на небольшом примере. Предположим, что в программе имеется класс Clock (часы) и класс Phone (телефон).

Естественно, у методов должна быть реализация и методов может быть гораздо больше. Теперь Вам необходимо написать класс CellPhone (мобильный телефон). В C++ Вы могли бы использовать множественное наследование для получения функционала часов и телефона в одном устройстве.

Вместо одной строки кода, на C# придётся написать

При такой реализации клиенты этого класса будут вынуждены углубить связность с его внутренней реализацией, что противоречит закону Деметры. Чтобы избежать связности можно реализовать все методы классов Clock и Phone внутри класса CellPhone, но это имеет смысл только при условии, что указанные классы имеют интерфейсы и используются только через них. Теперь усложним задачу. Каждый класс, Clock и Phone, будут унаследованы от класса Device (устройство).

В этом коде есть одна, не слишком очевидная, проблема. Объекты класса CellPhone будут иметь два экземпляра класса Device: один от Clock, другой от Phone. Для таких случаев (которые получили название ромбовидное наследование) в C++ введён специальный тип наследования — виртуальное наследование.

Теперь объекты CellPhone будут иметь один экземпляр класса Device. C# не предоставляет подобной возможности. В агрегированных объектах у Вас всегда будут храниться два разных объекта класса Device, бездарно расходуя память. Подробно о пользе и вреде множественного наследования Вы можете прочитать в книге Скотта Майерса «Эффективное использование C++. 50 рекомендаций по улучшению Ваших программ и проектов» в правиле 42: «Продумывайте подход к использованию множественного наследования». Более реальный пример множественного наследования — реализация паттерна проектирования Observer (наблюдатель).

В данном подходе класс ObservableWorker является одновременно и Worker`ом и Observable`ом. Без множественного наследования пришлось бы выбирать между родителями, и выбор был бы в пользу Worker`а, а методы addObserver и removeObserver пришлось бы реализовавать в каждом классе. Кроме упомянутых методов, класс Observable мог бы содержать дополнительные методы работы с коллекцией наблюдателей, но для краткости я не стал раздувать код примера.

Ещё один вид наследования, который оказался за бортом C# — наследование реализации без интерфейса или, проще говоря, приватное наследование. Этот вид наследования не делает унаследованный класс потомком родителя и не может участвовать в его полиморфных операциях. По большому счёту, закрытое наследование мало отличается от реализации класса посредством агрегации объекта некоторого другого класса (того, от которого производится наследование). Но в закрытом наследовании есть один большой плюс: оно предоставляет доступ ко всем защищённым членам базового класса. Один из вариантов использования закрытого наследования приведён в книге Скотта Майерса «Эффективное использование C++. 50 рекомендаций по улучшению Ваших программ и проектов» в правиле 42: «Продумывайте подход к использованию закрытого наследования». Этот пример довольно интересен, но является специфичным для C++, поэтому тут я его приводить не буду.

Инкапсуляция

Один из самых любимых мною, да и всеми C++ программистами, паттерн Private Implementation (например, библиотека Qt очень активно использует этот паттерн) не применим в C# вообще. Причиной этому является открытость всех модулей. В C++, желая скрыть детали имплементации класса, мы можем предварительно объявить в заголовочном файле приватный внутренний класс и указатель на него, а сам интерфейс и реализацию перенести в *.cpp модуль. Тем самым мы скрываем все переменные и дополнительные, вспомогательные методы, которые мы используем, от посторонних глаз. Интерфейс остаётся чистым и понятным при реализации любой сложности. В описанной стратегии очень сложно достучаться до деталей приватной имплементации. В C# при помощи reflection можно вызвать любой приватный метод и изменить приватное состояние объекта всего в одну-две строки кода. Но этот соблазн ещё выше с учётом того, что все внутренности класса находятся в одном модуле.

Объявление синонимов типа

Создатели C# посчитали, что оператор typedef им не нужен. В C++ оператор typedef служит для объявления синонимов типов. Для чего это нужно? К примеру, Вы используете в качестве параметра метода такой тип

Вместо того, чтобы всякий раз писать эту длинную последовательность, оператор typedef позволяет сократить запись. В C# это могло бы выглядеть так

И далее, везде, где использовался изначальный длинный тип, можно было бы писать просто MyType. Кроме удобочитаемого имени, оператор typedef используется в C++ для получения типов из других классов или шаблонов. Приведу простой пример использования.

Класс Container получает из типа шаблона тип значения, которое хранится в некотором другом классе и которое доступно из переменной value. Далее класс Container может оперировать этим типом, в том числе и в параметрах методов. Typedef`ы типов могут быть вложены и тогда классы Number и Letter могут стать одним шаблоном. Работают такие конструкции во время компиляции, что обеспечивает почти полную защиту от ошибок. Более сложные примеры с большой вложенностью Вы сможете найти в заголовочных файлах контейнеров (std::vector, std::map итд) стандартной библиотеки шаблонов (STL) С++.


Обобщения

Одним из самых мощных инструментов в C++ являются шаблоны. Сразу приведу пример, с которым я недавно столкнулся. Представим, что у нас есть абстрактный класс Connection

И от него унаследованы два (или более) конкретных класса: TcpConnection и SshConnection

Для примера, я не стал загромождать реализацию. Теперь стоит задача написать адаптер для каждого из конкретных классов, перекрыв методы connect и diconnect. В C++ это очень просто, нужно лишь написать шаблонный класс и отнаследовать его от параметра этого шаблона.

Теперь объекты класса ConnectionAdapter можно использовать точно так же, как и объекты типа его параметра.

Вы не сможете сделать нечто подобное на C#. C# не позволяет наследоваться от параметра обобщения. Таким образом, единственное, что Вам оставляет этот язык — унаследовать базовый класс, Connection, реализовать все его абстрактные методы при помощи агрегированного объекта конкретного класса, и дописать в двух нужных методах по паре строк кода. И даже сделав это, Вы не сможете использовать объекты данного класса как объекты конкретного класса. Кроме приведённого примера, есть ещё одна очень удобная возможность использовать подобный механизм в купе с приватным наследованием. Передавая в шаблон некоторый тип Вы изменяете реализацию для шаблонного класса, хотя, как уже было сказано, можно заменить это простой агрегацией. Другим серьёзным недостатком обобщений C# является невозможность специализации. Если Вы точно знаете, что для определённого типа данных Ваш шаблон будет работать крайне не оптимально, то Вы можете создать для этого типа отдельную реализацию. C++ позволяет специализировать как все, так и любое количество аргументов шаблона.

Этот код даст на выходе такой результат

Как видно, компилятор выбирает наиболее подходящую реализацию исходя из параметров шаблона. К сожалению, для специализации шаблонов необходимо полностью повторить интерфейс и реализацию шаблона. Но, имея такой мощный инструмент, как препроцессор, в C++ это не является серьёзной проблемой. Справедливости ради, стоит отметить, что обобщения C# строго типизированы и поддерживают ковариантность (out) и контравариантность (in) аргументов, что обеспечивает поддержку наследования. Для того, чтобы C++ поддерживал эти механизмы необходимо вручную писать операторы преобразования типов.

Препроцессор

Препроцессор в C и C++ является одним из важнейших механизмов генерации кода. Роль препроцессора в C# ограничена лишь условной компиляцией и выдачей предупреждений и ошибок во время компиляции. C и C++ предлагают механизмы генерации кода с помощью препроцессора. Скажем, приложение использует пользовательский тип исключений

И вместо того, чтобы каждый раз, когда необходимо создать наследника этого класса, писать реализацию всех конструкторов, просто вызывающих базовый конструктор (думаю, что все сталкивались с этой задачей в C#), С++ позволяет написать один макрос.

Всё, что нужно написать для определения двух классов — две строки.

Современные IDE, включая Visual Studio, способны выдавать подсказки по сгенерированному таким образом коду.

Неизменяемость

C# ограничивает понятие константности только лишь статическими ссылками на примитивные типы (POD), дополнительно вводит ключевое слово readonly для того, чтобы ссылке нельзя было переприсвоить объект. Этих механизмов не достаточно, чтобы обеспечить безопасную манипуляцию объектами и избавиться от side-эффектов. C++ предлагает механизм неизменяемых объектов (равно как и переменных POD типов). Если Вы объявляете переменную или параметр функции с модификатором const, то в дальнейшем Вы не можете ни переприсвоить этой переменной значение, ни вызвать из такого объекта метод, который может изменить этот объект. Кроме того, модификатор const может быть применён к типу возвращаемого значения функции. Таким образом, можно реализовать безопасный возврат ссылки или указателя с ограничением только на чтение. Методы, которые не меняют состояние объекта помечаются модификатором const в конце сигнатуры. Внутри константных методов все члены-данные класса неявным образом становятся константами, за исключением тех, что помечены специальным модификатором mutable. Модификатор mutable говорит, что данная переменная не оказывает влияние на состояние объекта и может быть изменена в константных методах. Примером такой переменной может быть счётчик обращений к какому-либо методу. Следующий код вполне валиден для C#.

Этот пример демонстрирует изменение данных, которые, очевидно, не должны меняться. Следующий пример демонстрирует, как C++ легко обходит указанную проблему.

Строки, помеченные комментарием «Ошибка», к примеру в Visual Studio, приведут к такому сообщению компилятора:

. consoleapplication1.cpp(58): error C2662: ‘Person::setFirstName’ : cannot convert ‘this’ pointer from ‘const Person’ to ‘Person &’

На моей практике встречались случаи, когда getter`ы свойств меняли кучу переменных класса, создавая side-эффекты, которые приводили к длительной отладке. Если бы в C# поддерживались константные методы (и getter`ы свойств), то таких ситуаций практически не возникало.

Ссылки

В C++ существует два способа указывания на объект: классические указатели и ссылки. Указатели являются адресом переменной в памяти, а ссылки — это механизм, введённый в язык C++ с целью повышения удобства и безопасности. Между ссылками и указателями есть две принципиальных разницы:

  1. ссылке нельзя переприсвоить значение;
  2. ссылка не может быть нулевой.

Первое ограничение касается, скорее, только безопасности, а вот второе очень сильно помогает в работе. В C++ принято принимать в функцию указатель, если параметр может быть равным NULL, в противном случае (чаще всего) принимают ссылку. В C# ссылки могут быть равными null, что приводит к постоянной проверке всех аргументов и частому возникновению NullReferenceException`ов. Да, в C# параметр можно пометить ключевым словом ref, тогда нельзя будет передать null явно, но следующий код будет вполне валидным.

Кроме того, использование ссылок в C++ не ограничено только параметрами, их использование допустимо почти всюду, где допустимо использование переменных.

Копирование объектов

Паттерн проектирования prototype (прототип) предполагает наличие одного объекта (прототипа) и его копирования для создания новых объектов. Такой подход часто обусловлен дороговизной инициализации новых объектов. В языке C++ предусмотрены мощные средства для создания копий объектов — это конструкторы копирования и операторы присваивания. Конструкторы копирования создают новый объект по переданному образцу, а операторы присваивания заполняют существующий объект из образца. C++ никак не ограничивает программиста в реализации упомянутых методов. Если конструктор копирования или оператор присваивания не определены, то компилятор сгенерирует их автоматически. Копирование по умолчанию подразумевает полное побайтовое копирование объектов.


Из вывода программы видно, что данные действительно скопированы, а конструкторы и оператор присваивания вызваны так, как и ожидалось. Чаще всего, конструкторы копирования и операторы присваивания реализуются для копирования данных, которые хранятся в объекте по указателю, но существуют и другие полезные применения, среди которых:

  • Запрет копирования объектов класса. Реализуется путём объявления конструктора копирования и оператора присваивания в приватной секции. При этом реализацию можно опустить, тогда при попытке использования вы получите ошибку от линкера.
  • Модификация копий объектов или статических переменных. Таким образом, к примеру, реализуются «умные» указатели с подсчётом ссылок.

C# при применении оператора копирования копирует лишь ссылку на объект (за исключением значимых типов данных). Для копирования объектов предназначен интерфейс ICloneable. Этот интерфейс содержит лишь один метод Clone, который возвращает объект типа object. Из этого следует, что клонированный объект всегда нужно приводить к нужному типу (и надеяться на порядочность разработчиков класса).

Тем не менее, из примера видно, что подход C# справился с поставленной задачей. Но что будет, если необходимо унаследовать один из классов, к исходникам которого у Вас нет доступа и который не реализует ICloneable?

В итоге Вы получите частично скопированный объект. Благодаря тому, что C++ гарантирует наличие конструктора копирования и оператора присваивания (за исключением того, когда явно указывается их отсутствие), любой класс может вызвать родительскую реализацию.

Заключение

В этой статье были перечислены лишь самые основные недостатки языка C#. За пределами обзора остались такие темы, как перегрузка операторов, дружественные классы, определение и время жизни переменных и многие другие мелочи. Следует отметить, что C# обладает одной труднореализуемой в C++ возможностью, возможностью применять атрибуты к класам и методам.

ООП (OOP) в C# | Продвинутый C# | Шаг 1

    Сертификат об окончании

Отвечаю на важный вопрос «Что такое ООП?» и рассказываю чем займёмся в курсе.

Изучаете язык C#, но всё ещё не можете освоить ООП?

Этот курс идеально подойдёт для вас, если вы хотите не только прочитать про классы и объекты, но и узнать об важной теории которая лежит под этим всем, и самое главное научится грамотно использовать это в своих проектах. В курсе вы узнаете про то, как производить объектную композицию, какие отношения бывают между объектами и как строить полиморфный код.

Многие опытные разработчики признаются, что до определённого момента неправильно понимали ООП. У них всё сводилось к построению простых классов и работы с ними. И только спустя годы они поняли, что под этим всем лежит и научились делать код промышленного масштаба. Этот курс поможет вам не совершать эту ошибку и сразу начать использовать ООП на полную катушку в языке C# со всеми фишками синтаксиса.

#2 — Основные принципы ООП

Приветствуем вас снова! Наш видеокурс по изучению языка Си Шарп продолжается. На сегодняшнем видеоуроке мы немного отвлечемся от непосредственного познания языка и рассмотрим в общих чертах основные принципы объектно-ориентированного программирования, или основы ООП: наследование, инкапсуляцию и полиморфизм.

Первый принцип, входящий в основы ООП, — наследование

Наследование – это механизм, позволяющий использовать функционал родительского класса в дочернем. Разберем простой пример.

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

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

Вторая составляющая основ ООП — инкапсуляция

Данный принцип позволяет ограничить доступ одних компонентов программы к другим. Реализуется принцип с помощью специальных модификаторов доступа. Всего существует четыре модификатора: public, internal, protected и private.

  • public – полностью открытый модификатор доступа (доступ в любом месте проекта);
  • internal – частично закрытый модификатор (доступ только внутри данной программы);
  • protected – частично открытый модификатор (доступ только в том классе, где были объявлены объекты и в дочерних классах);
  • private – закрытый модификатор (доступ только в классе, где были объявлены объекты).

Третий принцип, составляющий основы ООП, — полиморфизм

Полиморфизм – (греч.) многообразие форм. По сути, это возможность функции обрабатывать разные типы аргументов. Данный принцип имеет несколько видов: параметрический и Ad hoc-полиморфизм.

Параметрический полиморфизм подразумевает выполнение одного и того же блока кода для разных типов аргументов. Ad hoс-полиморфизм для каждого типа аргументов выполняет разные блоки кода.

Таковы основы ООП. На следующих видеоуроках вы познакомитесь с каждым принципом основ ООП отдельно и напишете соответствующие примеры. До скорой встречи!

Приятного всем просмотра! Учитесь с удовольствием! Всегда ваш LoftBlog.

Цукерберг рекомендует:  Udp - Срочно! В чем ошибка перевода String в Int C++
Понравилась статья? Поделиться с друзьями:
Все языки программирования для начинающих