//Разбиваем входную строку с использованием указанных
//символов в качестве разделителей
string[] sSubStrings = s l n p u t . S p l i t ( c T a r g e t s ) ;
//В sOutput будет содержаться возвращаемая строка string sOutput = "";
//Цикл по всем подстрокам
foreach(string substring in sSubStrings)
{
sOutput = String . Concat(sOutput , s u b s t r i n g ) ;
}
return sOutput;
}
В этой версии для разбиения входной строки на множество подстрок использу функция Split () с удаляемыми символами в качестве символов-разделителей, скольку разделители не включаются в подстроки, создается эффект их удаления, логика гораздо проще и менее подвержена ошибкам при реализации.
Цикл f oreach в этой версии функции собирает части строки в единое целое. В программы остается неизменным.
Класс String предоставляет в распоряжение программиста метод Format О] форматирования вывода, в основном — чисел. В своей простейшей форме Forma позволяет вставлять строки, числа, логические значения в середину форматируа строки. Рассмотрим, например, следующий вызов:
string myString =
String . Format("{0} умножить на {l} равно { 2 } " , 2, 3, 2*3);
Первый аргумент Format () — форматная строка (строка формата). Элементы в ней указывают, что и-ый аргумент, следующий за форматной строкой, должен вставлен в этой точке. {0} означает первый аргумент (в данном случае — 2), {1 второй (3) и так далее.
Вприведенном фрагменте получившаяся строка присваивается переменной myStr
иимеет следующий вид:
2 умножить на 3 равно 6
Пока не указано иное, функция Format () использует формат по умолчанию для каж типа аргумента. Для указания формата вывода можно размещать в фигурных скобках к номера аргумента дополнительные модификаторы, которые показаны в табл. 9.1.
218 |
Часть III. |
Объектно-основанное программирови |
Окончание табл. 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. |
Объектно-ориентированное |
программирован |