Пятница, 26.04.2024, 02:24
Приветствую Вас Гость | RSS

Лекции

Меню сайта
Форма входа
Категории раздела
ТАУ (Теория автоматического управления) [31]
лекции по ТАУ
Экология [151]
учебник
Бухгалтерский учет и налогообложение в строительстве [56]
Дементьев А.Ю. - Практическое пособие
Психология [104]
Пип
информатика [80]
с# Карли Ватсон
современные стулья [0]
новинки
Поиск

Главная » 2010 » Февраль » 11 » Практический пример 1 - web-сайт для проведения опросов
00:56
Практический пример 1 - web-сайт для проведения опросов
Практический пример 1 -
web-сайт для проведения опросов
На протяжении книги вы знакомились со всем спектром технологий .NET, ко-
торые можно использовать, программируя на С#. В этом разделе мы собираемся
отойти от теории и заняться в качестве практического упражнения приложением,
в котором будут использоваться самые разнообразные технологии из имеющихся
в .NET.
Сначала мы создадим базовое приложение, а затем расширим его и создадим
вторую версию, в которую будут включены дополнительные возможности. В реаль-
ной жизни от любого приложения всегда требуется постоянно соответствовать из-
меняющимся требованиям, и совершенно очевидно, что познакомиться с процессом
изменения приложения в практическом примере такой книги, как эта, оказывается
очень полезным. Использование двух различных версий также предоставит воз-
можность узнать, каким образом .NET позволяет упростить процедуру расширения
приложений, это означает что можно акцентировать внимание на меньших частях
приложения в процессе его разработки и создания.
Приложение, в первую очередь, предназначается для работы с web-сайтом. Од-
нако, как вы сможете увидеть по мере изучения этого примера, оно будет работать
с любым типом интерфейсов. Важно помнить, что, хотя мы будем заниматься со-
зданием приложения как функциональной возможности web-сайта, лежащая в его
основе объектная модель будет работать не менее эффективно и для консольного
приложения, и для desktop-приложения, и даже для web-службы. Мы также узнаем,
каким образом трехзвенная модель приложения (в которой уровни данных, бизнес-
логики и представления отделены друг от друга) позволяет упрощать процесс мо-
дернизации программного обеспечения на всем протяжении его жизненного цикла.
Web-сайт для проведения опросов
Многие web-сайты предусматривают вывод на экран вопроса с возможными
вариантами ответов. Посетителям web-сайтов таким образом дается подсказка для
ответа в соответствии с их точкой зрения, после чего они получают возможность
просмотреть общие результаты текущего опроса. Рассмотрим пример:
Какой язык программирования вы, в основном, используете?
С#
с++
. • '• • • . ' J a v a ' • •' . • . • . ' ...-..•• • • ••• . :• •• '• .*.'.'
J a v a S c r i p t •• •. • • . . ... • • . : • - : . : • • • • :•••••• :••••••:•••• :••:•••;: . А : . - . у , - • ; . , .,.:•••
748 Практический пример
Результат, который увидит посетитель, может быть представлен примерно сле-
дующим образом:
10% С#
2% C++
34% Java
12% JavaScript
42% Visual Basic
Практическим примером, которому посвящен этот раздел, будет реализация
системы проведения опросов, подобных приведенному выше, и после того, как мы
создадим две версии системы, мы включим в них новые возможности. Основным
будет интерфейс, использующий web и построенный с помощью ASP.NET. Мы
также создадим уровни представления для консольного приложения, desktop-при-
ложения Windows и web-службы.
Версия 1
В первой версии web-сайта для проведения опросов будет реализован простой
вывод вопроса на web-страницу и сбор ответов. Прежде чем двигаться дальше,
ясно и четко сформулируем требования к этому web-сайту.
Требования
Наш не очень интенсивно посещаемый web-сайт должен включать в себя
опрос, который состоит из вопроса и нескольких возможных вариантов ответа
(обычно не более десяти). При проведении опроса посетитель выбирает один из
предложенных ответов. После того как
посетитель проголосовал, он получает воз-
можность увидеть число голосов, отданных
за каждый из вариантов.
Все детали, касающиеся вопроса, отве-
тов и подсчета голосов, хранятся в XML-
файле на web-сервере, поскольку бюджет
на БД не выделен, а возможность должна
быть реализована в срочном порядке. Ког-
да администратору требуется внести какие-
либо изменения в проведение опроса, он
вручную редактирует XML-файл. Прило-
жение должно выводить простой HTML
так, чтобы он был корректно представлен
в двух основных типах браузеров (Netscape
и Internet Explorer).
Разработка объектной подели (Business Logig Tier)
Для данного примера будет использоваться трехзвенная модель — мы собира-
емся провести четкую границу между всеми тремя уровнями приложения:
• Уровень представления. Этот уровень представляет собой
пользовательский интерфейс и для .NET может состоять
из приложения ASP.NET (Интернет, интранет, цифровое телевидение,
мобильный телефон, электронная записная книжка и т. д.),
консольного приложения, приложения Windows Forms или web-службы.
1 File М View F&vorites
v^Back * => • -Ц l£j f j j
Address J4Q http;//lQCelhosfc/polto
Tools Help
\ Ш Personal Bar ^J
l Какой язык программирования вы, в основном»
i Голосую за С#
Голосую за О+
Голосую за Java
Голосую за JavaScript
1 Голосую за Visual Basic
i
/Search
~ 3 *><*
используете?
: Local intranet
О
1
:| Links->?|i
-!
Практический пример 1 — web-caum для проведения опросов 749
В данном примере мы планируем рассмотреть создание уровня представления
с использованием приложения ASP.NET, приложения Windows Forms,
web-службы и консольного приложения с командной строки.
Уровень бизнес-логики. Это сердцевина приложения. Именно здесь
мы будем применять принципы объектно-ориентированной разработки
в чистом виде, и именно здесь будет располагаться большая часть
создаваемого кода.
Уровень представления
Windows Forms, ASP.NET,
консольное приложение,
web-службы и т. д.
Уровень бизнес-логики
Класс(ы)
Уровень данных
XML, SQL Server, Oracle,
Microsoft Access, классы и т. д.
• Уровень данных. Это уровень, на котором
будут храниться данные, будь это XML-файл,
обычный файл на диске либо БД SQL Server,
Microsoft Access, MSDE или Oracle, либо
какое-либо другое средство хранения данных.
Во многих приложениях — кроме собственно
среды хранения данных — на этом же уровне
располагаются и классы, которые позволяют
осуществлять доступ к данным (см. рис. справа).
Необходимо помнить о том, что в .NET имеется
целый спектр мощных и гибких инструментов, однако
для создания высококачественного продукта прежде
всего играют роль методы, которые используются при разработке приложений,
а не инструменты сами по себе. Вполне возможно создать такой сайт для проведе-
ния опросов, используя только .aspx-файлы, которые непосредственно привязаны
к хранилищу данных. Однако в данном примере используется более структуриро-
ванный подход, который приводит" к созданию приложения, разбитого на три логи-
ческие составные части; такое приложение гораздо проще совершенствовать
и расширять. Время, затрачиваемое на создание программного обеспечения, на-
много меньше времени на сопровождение этого программного обеспечения; имен-
но поэтому структурированный подход представляет особую ценность.
Для трехзвенной структуры приложения представляется благоразумным учи-
тывать предъявляемые к нему требования с самого начала разработки объектной
модели. Это означает сначала построение связной умозрительной модели того, из
каких "вещей" должно состоять приложение, а затем создание на основании этой
модели уровня бизнес-логики приложения. Именно на этом этапе создаются объ-
екты, моделирующие отдельные составные части проблемы из той области знаний,
в которой мы работаем, и мы строим эти объекты так, чтобы соответствовать тре-
бованиям уровня представления и разумно использовать уровень данных. Зачастую
возникают ситуации, когда по мере разработки объектов, находящихся в среднем
звене, нам приходится принимать во внимание особенности физической среды
выполнения (например, быстродействие), однако в данном конкретном случае мы
разрабатываем очень простую систему, поэтому физические особенности среды не
играют существенной роли, и можно сосредоточить основное внимание на разра-
ботке объектов уровня бизнес-логики. Это дает возможность создать умозритель-
ную модель в чистом виде и впоследствии расширять ее по мере изменения
требований.
Возможные классы
При создании объектной модели зачастую используется смесь интуиции и прак-
тического опыта, хотя для этого обычно существует теоретическое обоснование,
которое вырабатывается с течением времени. Начнем с того, что еще раз просмотрим
750 Практический пример
все требования и перечислим все имена существительные, которые мы обнаружим
в описании классов/объектов нашего приложения.
• Web-сайт
• Опрос
• Вопрос
• Ответ
• Посетитель сайта
• Голосование
В этом списке наиболее заслуживающими внимания представляются следующие
пункты: опрос, вопрос, ответ, голосование. Оставшиеся два (web-сайт и посети-
тель сайта) не являются специфичными именно для сайта, предназначенного для
сбора голосов, хотя они могут понадобиться позднее.
Класс Poll (опрос)
Когда мы обсуждаем понятие опроса, мы говорим о весьма специфическом на-
боре данных:
• Единственный вопрос
• Множество ответов
• Подсчет голосов для каждого из возможных ответов
Не следует забывать, что в XML-файле может находиться несколько различных
вариантов опроса, и нужно быть в состоянии создавать объект Poll для каждого из
вариантов.
Когда мы представляем себе, какие данные придется хранить в объектах Poll,
рассмотрим какие функциональные возможности потребуются от такого объекта:
• Голосование — кажется логичным предусмотреть метод vote ()
(голосование), который будет регистрировать выбор одного из ответов
при проведении опроса.
• Получение вопроса — необходимо предусмотреть возможность
доступа к вопросу, чтобы вывести его на web-странице.
• Получение ответа — необходимо считывать список возможных
при проведении опроса ответов, которые будут выводиться на странице
для выбора посетителями сайта.
• Получение числа голосов для данного варианта ответа — необходимо
предусмотреть способ выявления проголосовавших за данный вариант.
Это будет использоваться для вывода количества голосов по каждому
варианту после голосования очередного посетителя.
В классе Poll содержится большая часть необходимых возможностей, однако
следует рассмотреть и другие классы, чтобы выяснить, какие возможности они
могут предложить.
Класс Question (вопрос)
Что представляет из себя вопрос? Насколько известно из наших требований,
это просто строка типа "Какую платформу вы используете?". Поскольку это так
просто, то можно не утруждать себя реализацией вопроса в качестве объекта,
Практический пример 1 — юеЪ-сайт для проведения опросов 751
а вместо этого представить его в качестве поля какого-либо другого класса. Окон-
чательное решение мы примем, когда будем рассматривать отношения между
классами.
Класс Answer (ответ)
Как и вопрос, ответ представляет из себя просто строку; однако не забывайте,
что, хотя для каждого опроса существует только один вопрос, для него — и для
каждого опроса— имеется несколько вариантов ответа. Следует также принять во
внимание то, что каждый вариант ответа предполагает сохранение числа поданных
за него голосов. Если бы мы пришли к выводу о необходимости реализации ответа
в качестве класса, то нам следовало бы предусмотреть свойства для текста самого
вопроса и для хранения числа поданных голосов, а также включить метод vote ().
Окончательно решение будет принято нами в следующем разделе.
Класс Vote (голосование)
Что такое голос? Это либо да, либо нет. Существует другой вариант, при кото-
ром можно говорить о голосовании как о классе "Votes"; в этом случае он мог бы
содержать счетчики числа голосов для каждого из имеющихся ответов. При таком
варианте сценария класс votes представлял бы собой нечто большее, чем просто
некий массив. В этом случае представляется бессмысленным создавать класс, ко-
торый будет представлять из себя всего лишь простой массив.
Отношения между классами
Представляется совершенно очевидным, что в качестве центрального компо-
нента приложения используется класс Poll. В нем будут содержаться собственно
вопрос, набор возможных ответов и счетчики числа голосов. Кроме того, в нем
предусмотрен метод vote о , который будет регистрировать голоса, отдаваемые по-
сетителями.
Едва ли имеет смысл создавать для вопроса отдельный класс, поскольку вопрос
представляет собой простую строку, поэтому мы разместим его в поле, имеющем
тип строки, внутри какого-либо другого класса. Поскольку у каждого объекта Poll
имеется только один вопрос, то кажется логичным прийти к заключению, что поле,
в котором содержится вопрос, должно находится внутри класса Poll.
Возникает вопрос, каким образом следует реализовать ответы и подсчет голо-
сов, поскольку в данном случае есть выбор — создавать ли нам специальный
класс "Answer" (ответ), в котором будут содержаться строка (с текстом ответа)
и счетчик голосов, или просто включить соответствующую функциональную воз-
можность в класс Poll, предусмотрев поле, где будет храниться семейство ответов,
и параллельно еще одно поле, в котором будет храниться число голосов для каж-
дого ответа (другими словами, второй элемент семейства поля, где находится счет-
чик голосов, будет содержать количество голосов, которое было подано за вариант
ответа, описываемый вторым элементом в семействе ответов). В результате такого
подхода с точки зрения объектной модели необходимо регистрировать голоса сле-
дующим образом:
myAnswerText = myPoll.Answrers[3];
myPoll.Vote(3);
В данном случае для регистрации голоса используется метод vote о на объекте
poll. Также имеется свойство с именем Answers (ответы), которое обеспечивает
доступ к семейству строк (возможно, хранящемуся в виде некоторого массива).
752 Практический пример
Если бы мы приняли решение создать класс Answer внутри класса Poll, то код,
позволяющий выполнять те же самые действия, принял бы приблизительно следу-
ющий вид:
myAnswerText•••= myPoll. Answrers [3] .Text; : I
myPoll.Answrers[3].Vote();
При желании можно записать его следующим образом:
myAnswer -myPoll.Answrers[3];
myAnswerText=myAnswer,Text;
myAnswer.Vote();
Отличие между двумя последними примерами заключается в том, что теперь
семейство представляет собой семейство объектов Answer, каждый из которых
обладает свойством Text (в котором содержится текст ответа) и методом vote().
С практической точки зрения совершено очевидно, что первый вариант является
более аккуратным; он позволит не тратить силы и время на создание класса Answer.
Дополнительным преимуществом является то, что позднее, когда встанет задача
расширения приложения, нам придется работать с меньшим количеством классов,
и в такой редакции приложение, скорее всего, окажется более просто сопровож-
дать. В силу этих причин мы реализуем ответы и счетчики голосов в виде се-
мейств, являющихся полями класса Poll, а не в виде отдельного класса Answer. На
самом деле, если впоследствии возникнет необходимость в таком длассе, то нам
ничего не сможет помешать создать его, но на данном этапе мы оставим все про-
стым и понятным.
Объектная модель
Объектная модель приложения для проведения опросов пока состоит из един-
ственного класса — Poll, который может быть представлен следующим образом:
Q Метод — vote ()
/ '
• СВОЙСТВО — Question
• Свойство — Answers [] (семейство)
• Свойство — votes [] (семейство)
Примем, что ответы для данного опроса будут храниться в свойстве, возвраща-
ющем семейство строк, которое может просматриваться в цикле. Со счетчиками
голосов работа будет вестись аналогичным образом, и они будут возвращать зна-
чения целого типа.
На данный момент имеется объект, который позволяет с успехом хранить сайт
для проведения опросов, однако каким образом можно такие объекты создавать?
Необходимо предусмотреть метод, позволяющий создавать объект Poll, который
соответствовал бы активному в настоящий момент опросу. Воспользуемся для этой
цели статическим методом, например, таким:
CurrentlyActivePoll = Poll.Current();
Это приведет нас к объектной модели, которая может быть представлена следую-
щим образом:
• Метод — vote о
• Метод — Current о (статический)
Практический пример 1 — и>еЪ-сайт для проведения опросов 753
• СВОЙСТВО — Question
О Свойство — Answers [] (семейство)
• Свойство — votes [] (семейство)
Свойства и методы класса Poll
Рассмотрим сигнатуры каждого из методов и свойств более внимательно, чтобы
четко представлять, как они должны быть реализованы. В следующем разделе мы
рассмотрим, каким образом класс может быть использован в типичной ситуации.
Метод Vote()
Метод vote о может получать целое значение в диапазоне от 1 до п, где п —
это число ответов в данном опросе. Этот метод не возвращает значение:
public void Vote(int answer)
Статический метод CurrentQ
Метод Current о является статическим, поэтому доступ к нему осуществляется
в помощью ссылки на имя класса, а не на имя экземпляра данного класса. Пара-
метры у него отсутствуют, и он возвращает значение типа Poll, которое представ-
ляет опрос, активный в настоящий момент:
public static Poll Current ()
Свойство Question
Свойство Question возвращает строку, которая может быть использована для
вывода вопроса посетителям web-сайта, например: "Какую платформу вы исполь-
зуете в работе?".
public string Question
В первой версии мы редактируем вопрос через XML-файл. Это означает, что
данное свойство может использоваться в режиме "только чтение", поэтому необ-
ходимо реализовать предложение get, а не set.
Свойство Answers
Свойство Answers обеспечивает доступ к объекту, в котором содержится семей-
ство ответов для опроса; при опросе по использованию операционных систем это
могут быть ответы типа "Windows 2000", "Linux", "M&cOS" и т. д. Поскольку нам
известен размер семейства, а все входящие в него элементы имеют один и тот же
тип, то представляется логичным воспользоваться типом стандартного массива
и хранить ответы в виде массива строк:
public string [] Answers
Как и для свойства Question, все изменения в данные вносятся вручную по-
средством редактирования XML-файла, поэтому требуется реализовать только
предложение get — это свойство также будет использоваться в режиме "только
чтение".
Свойство Votes
Свойство votes содержит в себе единственное целое значение для каждого из
ответов проводимого опроса. Названное свойство возвращает массив целого типа,
существующий параллельно с массивом Answers; между этими двумя массивами
754 _ - Практический пример
устанавливается взаимно однозначное соответствие, которое должно поддерживать-
ся нашей реализацией:
public int[] Votes
Значения, хранящиеся в свойстве votes, могут изменяться только с помощью
метода Vote (), ПОЭТОМУ данное СВОЙСТВО, так же как И СВОЙСТВа Question И Answers,
будет использоваться в режиме "только чтение", и для него необходимо реализо-
вать только предложение get.
В классах, подобных данному, использование одного массива должно быть
синхронизировано с использованием другого. Возможно, в приложении, предпо-
лагающем коммерческое использование, будет более предпочтительным создать
отдельный класс Answer, в котором текст ответа и счетчик голосов будут более
тесно привязаны друг к другу; не исключено также, что вы сможете отыскать какое-
либо иное решение. Чтобы не усложнять пример, мы продолжим использовать два
параллельных массива, что в данном случае нас вполне устраивает, поскольку мы
очень аккуратно будем относиться к тому коду, который производит изменения
в семействах.
Типичное использование
Будем считать, что теперь есть объектная модель, но как ее можно использо-
вать? Достаточно часто мы будем обнаруживать пробелы в нашей разработке при
рассмотрении вопроса о том, каким образом используются методы и свойства, по-
скольку это может приводить к возникновению очевидных проблем, в частности,
к концептуальной путанице относительно того, каким образом работает сама мо-
дель (возможно, вам приходилось слышать о таких проблемах, как варианты ис-
пользования, которые являются важным элементом объектно-ориентированного
программирования). Рассмотрим простое консольное приложение, которое берет
текущий опрос, выводит его и регистрирует голосование. Это позволит понять,
работает ли модель с концептуальной точки зрения:
Poll myPo]I = Poll.Current {) ;
Console.WriteLine (myPoll.Question);
for(int i=l; i<myPoll.Answers.Length; i++)
i
Console.Write {myPoll.Answers [i] + *: ");
Console,WriteLine (myPoll.Votes [i] + " voted");
} :- ; •
MyPoll.Vote (2);
Console.WriteLine ("Vote registered against " + myPoll.Answers [2]);
Console.WriteLine (Poll.Votes [2] ) ;
Все выглядит просто замечательно; у нас есть простой и ясный путь, позволяю-
щий считывать текущий опрос, выводить его и регистрировать процедуру голосо-
вания. Здесь используется туРО 11. Awnswers. Length для определения количества
ответов. Это выглядит довольно запутанным, поскольку совершенно неясно, исполь-
зуется ЛИ В данном Случае СВОЙСТВО Length, принадлежащее Votes ИЛИ Answers,
поэтому следует избавиться от этой путаницы и ввести свойство AnswerCount,
которое будет возвращать число ответов для данного варианта опроса:
public int AnswerCount // Общее свойство класса Poll
Это приводит к некоторым изменениям в использовании класса Poll и позволяет
сделать интерфейс более аккуратным:
Практический пример 1 — web-сайт для проведения опросов 755
Poll inyPoll = Poll.Current ();
Console.WriteLine (myPoll.Question) ;
for (int i=l; i<myPoll.AnswersCount; ++i;
{
Console.Write (myPoll.Answers [i] + •:
Console.WriteLine (myPoll.Votes [i] +
');
votes");
MyPoll.Vote (2)
Console.WriteLine (*Vote registered against • = myPoll.Answer [2]);
ConsoleWriteLine (poll.Votes [2]);
Тестирование
Прежде чем двигаться дальше, создадим небольшое консольное приложение,
которое будет тестировать класс Poll. У такого подхода есть два существенных
преимущества. Во-первых, в процессе создания класса Poll всегда можно убедить-
ся в том, что он работает. Во-вторых, можно понять, каким образом класс Poll
допускает свое использование из консольного
приложения с учетом того, что оно создается
прежде всего для использования в приложе-
нии ASP.NET.
Сначала мы создаем новое консольное
приложение С# в Visual Studio.NET с именем
Poiic (сокращение от Poll Command Line)
(см. рис. слева).
Visual Studio.NET создаст проект консоль-
ного приложения и сгенерирует файл с име-
нем ciassi.cs, где находится статический
метод MainO, который начнет выполняться
в момент запуска файла данного консольного
приложения с расширением .ехе.
using System;
namespace PollC
- •/•// <summary> . . • • '. .. ;
/// Общее описание для класса!
..///• </summary>.
class Classl
static void Main (string [] (args) •
//Действие: добавить код для запуска приложения
}
Теперь добавим в консольное приложение требуемый код, который позволит
считывать активный в настоящий момент опрос, выводить его вместе со счетчика-
ми голосов, регистрировать процесс голосования и выводить всю информацию
снова. Для этого потребуется внести в метод Main о следующие изменения:
static void Main (string) [] args)
Poll myPoll = P011.Current ();
756 Практический пример
••DisplayPoll (myPoll);
myPoll.Vote (2);
Console.WriteLine {"Vote registered against
•DisplayPoll (myPoll);
myPoll.Answers [2] j
Приведенный код очень напоминает тот код, который нам встретился в тот мо-
мент, когда мы рассматривали типичное использование класса Poll. В первую оче-
редь мы создаем объект с именем myPoll, затем используем метод DispiayPoiio
для вывода опроса на экран (мы будем рассматривать этот метод немного позже),
затем регистрируем поданный голос посредством метода vote о класса Poll и, на-
конец, повторно обращаемся к методу DispiayPoiio для вывода состояния опро-
са. Если мы все сделали правильно, то счетчик голосов для второго ответа после
этого должен увеличиться.
DispiayPoiio —это простой частный метод, который получает объект Poll
и выводит его в выходной поток консоли. Он показывает собственно вопрос, а так-
же все возможные ответы вместе с числом голосов, которые были поданы за каж-
дый из них:
: private static viodOisplayPoll (Poll aPoll) : v;
Console.WriteLine (Л==Ро11++<!г) ;
Console.WriteLine (aPoll.Question);
for (int i-=l; i<= (aPoll. AnswerCount) ; i++)
Console.Write (aPoll.Answers [i] + * : " ) ;
Console.WriteLine (aPoll.Votes [i] + "votes])
}
Console.WriteLine (*==========»);
Метод DispiayPoiio использует свойство
Question для вывода текста вопроса, после
чего он проходит по всем элементам в свой-
ствах Answers и votes и выводит текст ответа
и число голосов для всех возможных вариан-
тов ответа на данный вопрос.
Создав класс Poll, мы вправе ожидать,
что выходной поток консольного приложения
будет иметь вид, представленный на рисунке
слева.
Структуры данных (уровень данных)
У нас имеется тестирующая программа, с помощью которой можно убедиться
в правильности работы нашего кода. Теперь рассмотрим вопрос о том, каким об-
разом мы собираемся хранить данные в XML-файле. Следует иметь в виду, что по-
скольку между классом Poll и данными опроса существует взаимно однозначное
соответствие, то, в зависимости от используемого для взаимодействия с классом
Poll интерфейса (будь то консольное приложение, Web Forms или Windows
Forms), есть возможность ддя перехода впоследствии к другой архитектуре хране-
ния данных. При таком использовании XML существует целый ряд ограничений,
о которых мы поговорим несколько позже.
Каждый опрос состоит из нескольких видов данных:
• Question (строка)
Практический пример 1 — web-сайт для проведения опросов 757
• Множество Answers (строки)
• Множество счетчиков Votes (целые)
Отсюда следует возможность создать простой XML-файл (polls.xml) в корне-
вой директории диска С:\. Файл будет выглядеть следующим образом:

<Poll Question="What. development language do you primarily use?">
<Answer Text=-C#" Votes="10" />
<Answer Text="C++" Votes-"2If /> • . •
<Answer Text="Java" Votes="34" •/>
<Answer Text55"JavaScript" Votes="1211 />
<Answer Text55"Visual Basic" Votes="42" />
Обратите внимание на то, каким образом используется тег Poll, в котором со-
держится вся информация об опросе и хранится атрибут, представляющий вопрос
данного опроса. В тег Poll вложена последовательность, состоящая из нескольких
тегов Answer, в каждом из которых содержится текст ответа и счетчик голосов.
XML-формат обладает достаточно простой структурой, позволяющей выпол-
нять редактирование вручную, но еще более ценным оказывается тот факт, что,
сохранение данных в XML-формате предоставляет целый ряд возможностей для
считывания данных и выполнения над ними манипуляций. Теги в XML-файле, где
хранятся ответы на опрос, обладают точно такой же структурой, как если бы они
хранились в базе данных — по одной строке на каждый ответ со столбцами Text
и votes. Как вы сможете увидеть впоследствии, мы будем осуществлять доступ
к XML посредством набора данных точно таким же образом, как если бы мы осу-
ществляли доступ к таблице, хранящейся в базе данных.
Реализация объекта
На уровне бизнес-логики используется единственный класс — класс Poll.
Ниже перечислены методы и свойства, которые необходимо написать.
Методы
Q public static Poll Current()
• public void Vote(int answer)
Ш *l5i Local Project Ке.'л
User Confcrd Data Form
Wizard
i Щ Й
% F f e XML Schema Cede Fto
i l :
I An empty cbr.^ ded»--at*3fk
Свойства
• public int AnswerCount
• public string Question
• public string[] Answers
• public int13 Votes
Приступим к созданию класса. Преж-
де всего создадим пустой файл для клас-
са Poll. Для этого в Visual Studio.NET
нужно выбрать пункт Add Class меню
Project и ввести имя файла Poii.cs, как
показано на рисунке слева.
758 Практический пример
Visual Studio.NET создаст файл Poii.cs и сгенерирует обитую схему класса, ко-
торая выглядит следующим образом:
namespace Poll
••/// <sumraary>
/// Общее описание для Poll.
///</summary>
public class Poll .
с • • • • •
public Poll {)
.,// Действие: добавить здесь логически конструктор
Обратите внимание на то, как используется пустой конструктор (метод Poll о );
его использование отличается от файла Pollc.cs, в котором вместо конструктора
использовался метод Maino. Теперь следует пройти по всем методам и посмот-
реть, каким образом их можно реализовать.
Прежде чем переходить к рассмотрению методов и свойств класса Poll, необ-
ходимо определить некоторые поля. Более подробно эти поля будет рассматривать-
ся для каждого конкретного метода. В полях будут храниться число голосов, ответы,
вопрос, количество ответов (myAnswer-count) и полное имя XML-файла с данными
об опросе:
namespace Polling
{
public class Poll
{.
private int [] my Votes;
private string [[] myAnswers;
private string myQuestions;
private int myAnswerCount;
private string myFilename;
Заметьте также, что мы изменили пространство имен на Polling.
Метод public static Poll CurrentQ
Этот метод — единственный статический метод, он используется для получения
экземпляра класса Poll с данными активного опроса, которые этот класс должен
извлечь из XML-файла. Данный метод извлекает текст вопроса из тега <Question>
в XML-файле и записывает его в свойство myQuestion. После этого он проходит
В ЦИКЛе ПО всем тегам <Answer> И переписывает значение Text В массив myAnswers,
а Значения Votes — В массив myVotes.
Поскольку метод предназначается для создания нового экземпляра класса Poll,
то автор предпочел использовать для создания объекта Poll на основе XML-файла
частный конструктор, в результате чего метод Current о становится очень про-
стым — выполнение всей работы берет на себя конструктор:
public static Poll Current ()
: (
Poll myPoll = new Poll(@ИС:\polls.xml");
, :••••• • . •'• . r e t U C T l М Ш
Практический пример 1 — web-caum для проведения опросов 759
Здесь происходит только создание нового экземпляра Poll при помощи ключевого
слова new и передача конструктору строки с именем файла. Обратите внимание на
то, что мы добавляем символ '@' в начало строки, что позволяет использовать
в названии файла символ обратного слэша (в противном случае пришлось бы ис-
пользовать следующую запись "crWpoiis.xml"; применение двойного обратного
слэша может оказаться очень громоздким). После создания нового объекта мы
просто возвращаем его из метода. Теперь приступим к рассмотрению нового кон-
структора.
Метод private Poll(string filename)
Конструктор, который принимает имя файла-в качестве своего единственного
параметра, используется при создании объекта Poll и конфигурировании его по-
средством данных в XML-файле. Есть несколько возможностей извлечению дан-
ных из XML-файла. Можно либо последовательно каждый узел и извлекать
необходимые данные, либо считывать только определенные участки данных, кото-
рые требуЮТСЯ (например, Сначала Строку Question, Затем все СТрОКИ Answer И Т. Д.).
Есть и другая возможность — сериализовать объект Poll на диск, а затем десе-
риализовать его и тем самым воссоздать объект в памяти. Существует и четвертая
возможность: считать XML-файл в объект DataSet, что позволит обращаться с ним
так же, как и с любым другим источником данных. Для нашего примера мы вы-
бираем последний путь — считываем XML-файл в объект DataSet с помощью
ADO.NET.
На приведенной ниже диаграмме видно, что при загрузке XML-файла в набор
данных ADO.NET создаются две таблицы (что в объектах DataSet может хранить-
ся сразу несколько связанных таблиц). Таблица с номером ноль представляет тег
<Poii> и содержит всего одну строку и один столбец; в клетке этой таблицы содер-
жится вопрос текущего опроса. Таблица с номером один содержит в себе данные
тега <Answer>; в ней хранятся все ответы опроса в виде двух столбцов, по одной
строке на каждый ответ:
<?xml version "="encoding="utf-8"?
Строка О
Таблица О
Вопрос
"What development...?" Строка 0
Строка 1
Строка 2
Строка 3
Строка 4
Таблица 1
Текст
С#
C++
Java
JavaScript
VisualBasic
Votes
10
2
34
12
42
<Poll Quest ion= "What development . . . ? "> k ЫШ/ТОец U
<Answer Text="C#" Votes="10"/>
<Answer Text="O+" Votes="2"/>
<Answer Text="Java" Votes="34"/>
<Answer Text="JavaScript" Votes="12"/>
<Answer Text="Visual Basic" Votes="42"/> Столбец О Столбец 1
Пройдем последовательно по всему методу шаг за шагом, создавая код для за-
грузки XML-файла в набор данных. Нам придется написать здесь еще несколько
строе кода по сравнению с тем, что написали до сих пор. Сначала мы определяем
сигнатуру конструктора, в которую входит строка с именем XML-файла с данными
опроса:
private Poll(string filename)
{
inyFilename = filename;
Затем создаем объект DataSet, в котором будут храниться считываемые дан-
ные. Объекты DataSet обсуждались в главе 19. Мы создаем экземпляр объекта
Filestream с помощью конструктора, которому передается как имя файла, так
760 Практический пример
и значение перечислимого типа FileMode.open, следовательно, требуется открыть
данный файл для чтения:
DataSet myDataSet = new DataSet{);
FileStream fsReadXml = newFileStream(filename, FileMode.Open);
Чтобы оба этих объекта могли быть использованы, следует убедиться в том,
/ что в самом начале файла присутствуют ссылки на соответствующие пространства
имен:
using System.Data; // Требуется для объекта DataSet
using System.10; // Требуется для объекта FileStream
Теперь переходим к созданию объекта xmiTextReader, который будем использо-
вать для считывания данных из XML-файла. Для этого просто передаем созданный
нами объект типа FileStream — fsReadXml:
XmlTextReader myXmlReader = new System.Xml.XmlTextReader (fsReadXml) ;
He забудьте сослаться на следующее пространство имен:
using System.Xml; // Для объекта XmlTextReader
Следующая строка кода выполняет за нас очень большой объем работы —
в ней осуществляется вызов метода Readxmio на объект DataSet. Этот метод счи-
тывает весь XML-файл в объект DataSet, а также создает таблицы и строки, не-
обходимые для точного отображения не только самих данных, но и их структуры.
ADO.NET формирует две таблицы; первая из них (таблица 0) состоит всего из
одной строки и из одного столбца и содержит вопрос для опроса. Вторая таблица
содержит по одной строке на каждый возможный ответ и два столбца — один для
текста ответа, а второй для числа голосов, которые этот ответ получил:
.myDataSet.ReadXml(myXmlReader);
Следующая строка выполняет закрытие файла:
m y X m l R e a d e r . C l o s e ( ) ;
Остальная часть метода используется для извлечения данных, находящихся
внутри набора данных, и переноса их в частные поля класса Poll. Прежде всего
необходимо определить количество строк в таблице 1 (помните, что таблицы
в наборах данных индексируются с нуля), чтобы узнать, какое количество ответов
допускается при данном опросе, а затем сохранить это значение в поле my Answercount
класса Poll:
myAnswerCount = myDataSet.Tables[1].Rows - Count;
Чтобы присвоить значение полю myQuestion (доступ к которому осуществляет-
ся через свойство Question класса Poll), мы обращаемся к нулевой таблице и вы-
бираем первый элемент в первой и единственной содержащейся в ней строке.
Свойство itemArray возвращает объект типа object, поэтому необходимо восполь-
зоваться методом TostringO (который предусмотрен в типе object), чтобы преоб-
разовать объект в строку перед присваиванием полю myQuestion:
myQuestion = myDataSet.Tables[0].Rows[0].ItemArray[1].ToStringO;
В следующем блоке кода инициализируется массив my Answers, предназначен-
ный для хранения возможных ответов, а он наполняется проходом в цикле по всем
строкам таблицы 1, в которой содержатся эти ответы. Поскольку мы используем
массив с индексом, отсчет которого начинается с единицы (а не с нуля), то при
Практический пример 1 — web-caum для проведения опросов 761
указании размера массива используется выражение myAnswerCount+i. Свойства
votes и Answers, описанные в классе Poll, также индексируются, начиная с едини-
цы, поскольку такой интерфейс оказывается более понятным для уровня представ-
ления, ибо позволяет называть "вопросом 1" первый вопрос, а не второй (как это
было бы при отсчете индекса с нуля). Это субъективное решение автора — вы
можете внести изменения в код и сделать индекс массива, изменяющимся с нуля.
Обратите внимание на то, как мы осуществляем доступ к каждому ответу в таб-
лице 1 с перечнем возможных ответов, с помощью прохода в цикле по всем стро-
кам и извлечения каждый раз текста в нулевом столбце:
.v••••;•./.,• myAnswers = new string[myAnswerCount+1 ];
s t r i n g a n s w e r ; ••• .• •• • • • \ • : ; :'-^7^k''T^y-\',^' ' '
for(int i=0;i<myAnswerCount;i
answer = myDataSet.Tables[1].Rows[i].ItemArray[0].ToStringO;
myAnswers[i+1] = answer;
Следующий блок кода практически идентичен предшествующему за исключени-
ем того, что на этот раз мы наполняем массив myvotes и используем для этого пер-
вый столбец таблицы. Поскольку данный массив содержит в себе значения целого
типа, то приходится для объекта типа int использовать метод ParseO, который
преобразует строку XML-файла в значение целого типа, прежде чем присвоить ее
элементу массива myvotes:
myVotes •= new int[myAnswerCount+1];
// прибавляем 1, поскольку индекс отсчитывается с 1
•••• S t Г i n g V O t e S ; • • • : • • '• • : •••••• • • • . • , . • ; . . . / • . • • • . . • • • • • : • : : • . • , . • • . . : : , . , . . • • . • • • • . : • • . . • . ^ у
for(int i=0;i< myAnswerCount;i
votes = myDataSet.Tables[1].Rows[iJ.ItemArray[1].ToStringO;
myVotes[i+l] = int.Parse(votes);
}
В ЭТОМ КОНСТруКТОре Объект Инициализирован таким обраЗОМ, ЧТО ПОЛЯМ myQuestion,
myAnswerCount, myAnswers и myvotes присвоены соответствующие значения, и до-
ступ к этим значениям может быть осуществлен использованием следующих
СВОЙСТВ Объекта: Question, Count, Answers И Votes. После СОЗДанИЯ объект Poll
остается единственная (на данный момент) возможность вносить изменения в хра-
нящиеся в нем данные, и она заключается в методе vote о , к рассмотрению кото-
рого мы переходим.
Очень важно понимать, что при использовании свойства класса Poll мы, на
самом деле, считываем данные не непосредственно из XML-файла, а из полей,
находящихся внутри класса. Причина, по которой программа устроена и
Категория: информатика | Просмотров: 2917 | Добавил: basic | Рейтинг: 0.0/0
Всего комментариев: 0
Имя *:
Email *:
Код *:
Календарь
«  Февраль 2010  »
ПнВтСрЧтПтСбВс
1234567
891011121314
15161718192021
22232425262728
Статистика

Онлайн всего: 1
Гостей: 1
Пользователей: 0

krutoto.ucoz.ru
Бесплатный конструктор сайтов - uCoz