Окончание табл. 9.1
Все эти модификаторы могут показаться слишком запутанными, но вы все гда можете получить информацию о них в справочной системе С#. Чтобы увидеть модификаторы в действии, взгляните на приведенную далее демон страционную программу OutputFormatControls, позволяющую ввести не только число с плавающей точкой, но и модификатор формата, который будет использован при выводе введенного числа обратно на экран.
//OutputFormatControls - позволяет пользователю посмотреть , // как влияют модификаторы форматирования на вывод чисел . //Модификаторы вводятся в программу так ж е , как и числа — в // процессе работы программы
namespace OutputFormatControls
{
using System;
public class Program
{
public static void M a i n (string [] args)
{
// |
Бесконечный |
цикл для |
ввода чисел, пока пользователь |
// |
не введет вместо числа пустую строку, что является |
// |
сигналом к |
окончанию |
работы программы |
for(;;)
{
// Ввод числа и выход из цикла, если введена пустая]
//строка
Console . W r i t e L i n e ( "Введите число с плавающей точкой") string sNumber = C o n s o l e . R e a d L i n e О ;
if (sNumber.Length == 0)
{
b r e a k ;
}
double dNumber = D o u b l e . P a r s e ( s N u m b e r ) ;
//Ввод модификаторов форматирования, разделенных
//пробелами
Console . WriteLine("Введите модификаторы " +
|
|
"форматирования, разделенные " + , |
|
|
" п р о б е л а м и " ) ; |
chart] |
separator = |
{' |
' } ; |
string |
sFormatString |
= |
C o n s o l e . R e a d L i n e ( ) ; |
string[] sFormats |
= |
sFormatString . Split(separator) ; |
//Цикл по введенным модификаторам
foreach(string s in sFormats)
{
if (s.Length != 0)
{
//Создание управляющего элемента форматирования!
//из введенного модификатора
string sFormatCommand = " {0 : " + s + " } " ;
//Вывод числа с применением созданного
//управляющего элемента форматирования Console . Write(
|
"Модификатор |
{ о } |
дает ", sFormatCommand); |
|
try |
|
|
|
{ |
|
|
|
Console . WriteLine(sFormatCommand, d N u m b e r ) ; |
|
} |
|
|
|
catch(Exception) |
|
|
|
{ |
|
|
|
Console . WriteLine("<Неверный м о д и ф и к а т о р > " ) ; |
|
} |
|
|
|
C o n s o l e . W r i t e L i n e ( ) ; |
|
|
} |
|
|
} |
} |
|
|
|
|
|
// |
Ожидаем подтверждения |
пользователя |
Console . WriteLine("Нажмите <Enter> для " + |
|
"завершения п р о г р а м м ы . . . " ) ; |
C o n s o l e . R e a d ( ) ; |
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
220 |
Часть |
III. |
Объектно-основанное программировал |
Программа OutputFormatControls считывает вводимые пользователем числа сплавающей точкой в переменную dNumber до тех пор, пока не будет введена пустая прока — это является признаком окончания ввода. Обратите внимание, что программа не выполняет никаких тестов для проверки корректности введенного числа с плавающей точкой. Программа считает пользователя достаточно интеллектуальным и знающим, как выглядят числа с плавающей точкой (довольно смелое допущение!).
Затем программа считывает ряд модификаторов форматирования, разделенных про белами. Каждый из них далее комбинируется со строкой { 0 } в переменной sFormat Command. Например, если вы ввели N4, программа создаст управляющий элемент
{0: N4}. После чего введенное пользователем число выводится на экран с применением этого элемента:
Console.WriteLine (sFormatCommand, dNumber) ;
В рассмотренном только что случае модификатора N4 команда по сути превращается в tasole. WriteLine (" {О :N4 }" , dNumber) ;
жа ъытлядит типичный вывод программы на экран (полужирным шрифтом вы-
; делен ввод пользователя): |
|
|
.Введите число с плавающей точкой |
|
|
1234 5 . 6 7 8 9 |
|
|
|
Введите модификаторы форматирования, |
разделенные |
пробелами |
СЕ F1 N0 0000000 .00000 |
|
|
Кодификатор {0:С} дает $ 12,345 . 68 |
|
|
Кодификатор {0:Е} дает 1.234568Е+004 |
|
|
Кодификатор |
{ 0 : F1} дает 12345 . 7 |
|
|
Кодификатор |
{0:N0} дает 12,346 |
|
|
одификатор {0:0000000.00000} дает 0012345 . 67890 |
|
Введите число с плавающей точкой |
|
|
.12345 |
|
|
|
Заедите модификаторы форматирования, |
разделенные |
пробелами |
ео.о%
Кодификатор {0:00.0%} дает 1 2 . 3 % Идите число с плавающей точкой
Заште <Enter> для завершения программы ...
Будучи примененным к числу 12345.6789, модификатор N0 добавляет в нужное место пятую (часть N) и убирает все цифры после десятичной точки (часть 0), что дает стро ки, 346 (последняя цифра — результат округления, а не отбрасывания).
Аналогично, будучи примененным к числу 0.12345, модификатор 0 0.0% даст 12.31 Знак % приводит к умножению числа на 100 и добавлению символа % к выводи- иу числу. 00.0 указывает, что в выводимой строке должно быть по меньшей мере две фы слева от десятичной точки, и только одна — справа. Если тот же модификатор применить к числу 0.01, будет выведена строка 01.0%.
Непонятная конструкция try . . . catch предназначена для перехвата всех по тенциальных ошибок при вводе некорректных чисел. Однако об этом расска зывается совсем в другой главе.
[ и з 9. Работа со строками в С# |
221 |
Часть IV
Объектно-ориентированное программирование
Объектно-ориентированное программирование — термин, вызывающий у программистов наибольший выброс адреналина в кровь. Так, объ ектно-ориентированным языком программирования является С++ — и в этом его главное отличие от старого доброго С. К объектноориентированным языкам определенно относится и Java, как и еще добрая сотня языков, придуманных за последний десяток лет. Но что же это такое — объектно-ориентированный! Зачем это надо? и надо ли вообще? стоит ли использовать это в своих программах?
В этой части вы столкнетесь с возможностями С#, которые делают
его объектно-ориентированным языком программирования. Объект но-ориентированное программирование — это не просто работа с объектами; это — мощь и гибкость программ при меньших затра чиваемых усилиях, это элегантность проекта, словом — это все, из ложенное в данной части книги.
Глава 10
Что такое объектно-ориентированное программирование
>Основы объектно-ориентированного программирования
>Абстракция и классификация
>Важность объектно-ориентированного программирования
этой главе будут даны ответы на два основных вопроса — какие концепции ле жат в основе объектно-ориентированного программирования и чем они отлича
ются от уже рассмотренных концепций функционального программирования.
Когда мы с сыном смотрим футбол, я подчас испытываю непреодолимую тягу к вред ным для здоровья, но таким вкусным кулинарным изыскам, в частности, к мексиканским блюдам. Достаточно бросить на тарелку чипсы, бобы, сыр, приправы и пять минут зажа ривать эту массу в микроволновой печи.
Для того чтобы воспользоваться печью, следует открыть ее дверцу, поместить внутрь полуфабрикат и нажать несколько кнопок на передней панели. Через пару минут блюдо готово (только не стойте перед печью, а то ваши глаза начнут светиться в темноте).
Обратите внимание на то, чего не делалось при использовании микроволновой печи.
Ничего не переключалось и не изменялось внутри печи. Чтобы установить для нее рабочий режим, существует интерфейс — лицевая панель с кнопками и неболь шой индикатор времени; это все, что нужно.
Не перепрограммировался процессор внутри печи, даже если прошлый раз гото вилось абсолютно другое блюдо.
Не было необходимости смотреть внутрь печи.
При приготовлении блюд не надо было беспокоиться о внутреннем устройстве пе чи — даже если вы работаете главным инженером по производству таких печей.
Это не просто пространные рассуждения. В повседневной жизни нас постоянно преследуют стрессы. Чтобы уменьшить их число, мы начинаем обращать внима ние только на события определенного масштаба. В объектно-ориентированно) программировании уровень детализации, на котором вы работаете, называете уровнем абстракции. И объяснить этот термин можно на примере абстрагирот ния от подробностей внутреннего устройства микроволновой печи.
К счастью, ученые-кибернетики открыли объектную ориентированность и ряд других концепций, снижающих уровень сложности, с которым должен работать программно Использование абстракций делает программирование более простым и уменьшает коли чество возможных ошибок. Именно в этом направлении как минимум полстолетия да жется прогресс в программировании— работа со все более сложными концепциями а все меньшим количеством ошибок.
Во время приготовления блюда многие смотрят на микроволновую печь просто как на железный ящик. И пока ею можно управлять с помощью интерфейса, ее нельзя сло мать, "подвесить" или, что еще хуже, превратить готовящееся блюдо в угли.
Приготовление блюд с помощью функций
Представьте себе, что я попросил бы своего сына написать алгоритм приготовлен! мною закусок. Поняв наконец, чего я от него добиваюсь, он бы, наверное, написал что-то вроде "открыть банку бобов, натереть сыр, посыпать перцем" и т.д. Когда дело дошло бы непосредственно до приготовления в печи, он в лучшем случае написал бы нечто тип "готовить в микроволновой печи не более пяти минут".
Этот рецепт прост и верен. Но с помощью подобного алгоритма "функциональный" про граммист не сможет написать программу приготовления закусок. Программисты, работаю щие с функциями, живут в мире, лишенном таких объектов, как микроволновая печь и прочи удобства. Они заботятся о последовательности операций в функциях. В "функциональном" решении проблемы закусок управление будет передано от пальцев рук кнопкам передней па нели, а затем внутрь печи. После этого программе придется решать, какое время должна работать печь и когда следует включить звуковой сигнал готовности.
При таком подходе очень трудно отвлечься от сложностей внутреннего устройств! печи. В этом мире нет объектов, за которые можно спрятать всю присущую микроволно вой печи сложность.
Приготовление "объектно-ориентированных" блюд
Применяя объектно-ориентированный подход к приготовлению блюд, я первым де лом определяю объекты, используемые в задаче: сыр, бобы, чипсы и микроволновая печь. После этого я начинаю моделировать их в программе, не задумываясь над деталя ми их применения.
При этом я работаю (и думаю) на уровне базовых объектов. Главное, думать о том, что приготовить блюдо, не волнуясь о деталях работы микроволновой печи — над этим уже подумали ее создатели (которым абсолютно нет дела до ваших кулинарных пристрастий).
После создания и проверки всех необходимых объектов можно переключиться на следующий уровень абстракции, т.е. мыслить на уровне процесса приготовления закуски не отвлекаясь на отдельные куски сыра или банку бобов. При таком подходе я легко пе реведу рецепт моего сына на язык С#.
226 |
Часть |
IV. |
Объектно-ориентированное программировании] |
В концепции уровней абстракции очень важной частью является классификация. Опять-таки, если бы я спросил моего сына: "Что такое микроволновая печь?" — он бы наверняка ответил: "Это печь, которая...". Если бы затем последовал вопрос: "А что та кое печь?" — он бы ответил что-то вроде: "Ну, это кухонный прибор, который...". (При попытке выяснить у него, что же такое кухонный прибор, он наверняка бы спросил, сколько можно задавать дурацких вопросов.)
Из детских ответов становится ясно, что ими печь воспринимается как один из экзем пляров вещей, называемых микроволновыми печами. Кроме того, печь является подраз делом духовок, а духовки относятся к типу кухонных приборов.
В объектно-ориентированном программировании конкретная микроволновая печь является экземпляром класса микроволновых печей. Класс микроволно вых печей является подклассом печей, который, в свою очередь, является под классом кухонных приборов.
Люди склонны заниматься классификацией. Все вокруг увешано ярлыками. Мы дела ем все для того, чтобы уменьшить количество вещей, которые надо запомнить. Вспом ните, например, когда вы первый раз увидели "Пежо" или "Рено". Возможно, в рекламе и говорилось, что это суперавтомобиль, но мы-то с вами знаем, что это не так. Это ведь просто машина. Она имеет все свойства, которыми обладает автомобиль. У нее есть руль, колеса, сиденья, мотор, тормоза и т.д. И можно поспорить, что многие водили бы такую штуку без всяких инструкций.
Но не будем тратить место в книге на описание того, чем этот автомобиль похож на другие. Следует знать лишь то, что это "машина, которая...", и то, чем она отличается от других машин (например, ценой). Теперь можно двигаться дальше. Легковые автомоби ли являются таким же подклассом колесных транспортных средств, как грузовики и пи капы. При этом колесные транспортные средства входят в состав транспортных средств наравне с кораблями и самолетами.
Зачем вообще нужна эта классификация, это объектно-ориентированное программи рование? Ведь оно влечет за собой массу трудностей. Тем более, что уже имеется гото вый механизм функций. Зачем же что-то менять?
Иногда может показаться, что легче разработать и создать микроволновую печь спе циально для какого-то блюда и не строить универсальный прибор на все случаи жизни. Тогда на лицевую панель не нужно было бы помещать никаких кнопок, кроме кнопки
СТАРТ. Блюдо всегда готовилось бы одинаковое время, и можно было бы избавиться от всех этих бесполезных кнопок типа РАЗМОРОЗКА или Т Е М П Е Р А Т У Р А П Р И Г О Т О В ЛЕНИЯ. Все, что требовалось бы от такой печи, — это чтобы в нее помещалась одна та
релка с полуфабрикатом. Да, но что же тогда получится? Ведь при этом кубический фут пространства использовался бы для приготовления всего одной тарелки закуски!
Чтобы сэкономить место, можно освободиться от этой глупой концепции — "микрон] новая печь". Для приготовления закуски хватит и внутренностей печи. Тогда в инструкции достаточно написать примерно следующее: "Поместите полуфабрикат в ящик. Соедини красный и черный провод. Установите на трубе излучателя напряжение в 3000 вольт. Дол появиться негромкий гул. Постарайтесь не стоять близко к установке, если хотите иметь ц тей". Простая и понятная инструкция!
Но такой функциональный подход создает некоторые проблемы.
Слишком сложно. Нежелательно, чтобы фрагменты микроволновой печи па мешивались с фрагментами закуски при разработке программы. Но поскольку ц данном подходе нельзя создавать объекты и упрощать написание, работая с и цым из них в отдельности, приходится держать в голове все нюансы каждого of екта одновременно.
Не гибко. Когда-нибудь потребуется замена имеющейся микроволновой печщ печь другого типа. Это делается без проблем, если интерфейс печи можно буд оставить старым. Без четко очерченных областей действия, а также без разделен интерфейса и внутреннего содержимого становится крайне трудно убрать стар объект и поставить на его место новый.
Невозможно использовать повторно. Печи предназначены для приготовлен! разных блюд. Вряд ли кому-то захочется создавать новую печь всякий раз при а обходимости приготовить новое блюдо. Если задача уже решена, неплохо исши зовать ее решение и в других программах.
Объект должен быть способен спроектировать внешний интерфейс максимально прс стым при полной достаточности для корректного функционирования. Если интерфа" устройства будет недостаточен, все кончится битьем кулаком или чем-то более тяжела по верхней панели такого устройства или просто разборкой для того, чтобы добраться» его внутренностей (что наверняка окажется нарушением законодательства об интелла туальной собственности). С другой стороны, если интерфейс слишком сложен, весы сомнительно, что кто-то купит такое устройство (как минимум, вряд ли кто-то будет HI пользовать все предоставляемые интерфейсом возможности).
Люди постоянно жалуются на сложность видеомагнитофонов (впрочем, с переходо на управление с помощью экрана количество жалоб несколько уменьшилось). В эк устройствах слишком много кнопок с различными функциями. Зачастую одна и та i кнопка выполняет разные функции — в зависимости от того, в каком именно состояш находится в этот момент видеомагнитофон. Кроме того, похоже, невозможно найти я видеомагнитофона различных марок с одинаковым интерфейсом.
Теперь рассмотрим ситуацию с автомобилями. Вряд ли можно сказать (и доказать что автомобиль проще видеомагнитофона. Однако, похоже, люди не испытывают тан трудностей с его вождением, как с управлением видеомагнитофоном.
В каждом автомобиле в наличии примерно одни и те же элементы управления и гаи ти на одних и тех же местах. Если же управление отличается... Ну вот вам реальная ж тория из моей жизни — у моей сестры был французский автомобиль, в котором упращ
228 |
Часть |
IV. |
Объектно-ориентированное |
программирован |
ние фарами оказалось там, где у всех "нормальных" автомобилей находится управление сигналами поворота. Отличие вроде бы небольшое, но я так и не научился поворачивать на этом автомобиле влево, не выключив при этом фары...
Кроме того, при хорошо продуманном дизайне автомобиля один и тот же элемент управления никогда не будет использоваться для выполнения более одной операции в за висимости от состояния автомобиля.
Микроволновая печь должна быть сконструирована таким образом, чтобы никакая комбинация кнопок или рукояток не могла ее сломать или навредить вам. Конечно, оп ределенные комбинации не будут выполнять никаких функций, но главное, чтобы ни од на из них не привела к следующему.
Поломке устройства. Какие бы рукоятки ни крутил ваш ребенок и какие бы кнопки не нажимал — микроволновая печь не должна от этого сломаться. После того как вы вернете все элементы управления в корректное состояние, она должна нормально работать.
К пожару или прочей порче имущества или нанесению вреда здоровью по требителя. Мы живем в сутяжном мире, и если бы что-то похожее могло про изойти — компании пришлось бы продать все вплоть до автомобиля ее президен та, чтобы рассчитаться с подающими на нее в суд и адвокатами.
Однако чтобы эти два правила выполнялись, вы должны принять на себя определен ную ответственность. Вы ни в коем случае не должны вносить изменения в устройство, в частности, отключать блокировки.
Почти все кухонное оборудование любой степени сложности, включая микроволно вые печи, имеет пломбы, препятствующие проникновению пользователя внутрь. Если такая пломба повреждена, это указывает, что крышка устройства была снята, и вся от ветственность с производителя тем самым снимается. Если вы каким-либо образом из менили внутреннее устройство печи, вы сами несете ответственность за все последую щие неприятности, которые могут произойти.
Аналогично, класс должен иметь возможность контролировать доступ к своим членамданным. Никакая последовательность вызовов членов класса не должна приводить программу к аварийному завершению, однако класс не в состоянии гарантировать это, если внешние объекты имеют доступ к внутреннему состоянию класса. Класс должен иметь возможность прятать критические члены-данные и делать их недоступными для внешнего мира.
Итак, как же С# реализует объектно-ориентированное программирование? Впрочем, это не совсем корректный вопрос. С# является объектно-ориентированным языком про-
Глава 10. Что такое объектно-ориентированное программирование |
229 |