русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

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


Дата добавления: 2013-12-23; просмотров: 1187; Нарушение авторских прав


Класс ArrayList

Многомерные массивы

Рассмотрим только 2-х мерные массивы. Использование массивов большей размерности принципиально не отличается. Существуют два вида таких массивов – прямоугольные и «рваные» (ступенчатые).

У прямоугольного массива все строки имеют одинаковое количество элементов (также как и столбцы). Такая структура в математике называется двумерной матрицей.

Описание двумерного массива выглядит следующим образом:

int [ , ] matrix;

При создании такого массива, как обычно, используется операция new:

matrix = new int[3,4];

Здесь создается прямоугольный массив из 3-х строк и 4-х столбцов. Дальнейшее использование такого массива вполне традиционно. Например, можно заполнить весь массив содержимым следующим образом:

for(int i = 0; i<matrix.GetLength(0); i++)

for (int j = 0; j< matrix.GetLength(1); j++)

matrix[i, j]=i*j;

Обратим внимание, что для определения количества шагов в циклах перебора вместо свойства Length (общее количество элементов), нужно использовать метод GetLength с параметром – номером измерения.

Другой тип многомерных массивов – рваные массивы – следует представлять как одномерный массив, элементами которого являются в свою очередь, массивы. Описание такого массива несколько отличается:

int [][] jagArray;

Здесь используются две пары квадратных скобок. Создание «рваного» 2-х мерного массива состоит из двух этапов. Сначала создается главный массив:

jagArray = new int[5][];

Это можно понимать как создание 5-элементного массива, элементами которого будут являться пока не созданные объекты-массивы (пустая пара квадратных скобок). На следующем этапе нужно содать и эти массивы, например, следующим образом:

for (int i=0; i<jagArray.Length; i++)

jagArray[i]=new int[i+7];

При переборе ступенчатого массива следует учитывать, что не все элементы главного масива существуют:



int s=0;

for (i=0;i< jagArray.Length; i++)

if jagArray [i]!=null

for (j=0; j< jagArray [i].Length; j++)

s=s+ jagArray [i][j];

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

Если в Ваших задачах требуется динамическое изменение размера масива, можно использовать стандартный класс ArrayList из пространства имен System.Collections.

У класса ArrayList есть еще одно важное отличие от массивов – он способен хранить элементы совершенно произвольного типа.

Для использования ArrayList в программе нужно подключить пространство имен System.Collections.

Описание и создание объекта ArrayList происходит как обычно:

ArrayList persons=new ArrayList();

При этом используется конструктор по умолчанию, который создает объект ArrayList, не содержащий ни одного элемента.

Теперь с помощью метода Add мы можем добавлять в persons элементы:

Person p=new Person();

persons.Add(p);

persons.Add(new Person());

Здесь мы добавили в persons два объекта Person – один объект, на который ссылается переменная p, а второй объект – безымянный (для него не существует переменной). К первому объекту можно получать доступ через «его» переменную p и через объект persons, второй объект доступен только через persons.

Возникает вопрос – в каком порядке находятся элементы внутри persons. Ответ интуитивно ясен – в порядке их добавления. Теперь использовать содержимое persons можно так же как и для обычного массива, например:

for (int i=0;i<persons.Count;i++) persons[i].PersonAnalyze();

Обратите внимание на то, что для определения количества элементов в ArrayList используется не свойство Length как у массивов, а свойство Count.

Выполнение такого цикла приведет к ошибке компиляции:

'object' does not contain a definition for 'PersonAnalyze'

Компилятор «говорит», что в классе Object не определен метод PersonAnalyze. Откуда взялся класс Object? Дело в том, что ArrayList является универсальным контейнером, способным хранить объекты любого типа. Платой за это является потеря информации о действительном типе объекта, когда мы обращаемся к нему как к элементу ArrayList. Все, что известно о типе этого объекта – он является любым объектом, то есть объектом класса Object – общем предке всех классов .NET. И именно об отсутствии метода PersonAnalyze в классе Object сообщает компилятор.

На практике мы обычно знаем, какого типа объект находится в ArrayList. В этих случае вполне оправдан риск явного приведения к этому типу:

for (int i=0;i<persons.Count;i++)

((Person)persons[i]).PersonAnalyze();

Намного сложнее дело обстоит, если Вы хотите хранить в ArrayList разнотипные объекты и заранее не известен порядок их следования. Как решать такие задачи Вы узнаете позже.

Метод Remove позволяет удалить объект из ArrayList:

persons.Remove(p);

Если параметр-объект не содержится в ArrayList, то метод Remove не имеет никакого эффекта.

Отметим еще несколько полезных методов:

RemoveAt удаление объекта с указанной позицией

Insert вставка объекта в указанную позицию

Sort упорядочивает элементы в ArrayList

Clear удаление всех элементов из ArrayList

Contains определяет, содержится ли объект в ArrayList

IndexOf возвращает позицию объекта в ArrayList

 

Хотя элементы в ArrayList находятся в порядке возрастания их номеров (и обычно в порядке их добавления), во многих случаях этот порядок не имеет значения. Допустим, нужно определить суммарный вес объектов Person в ArrayList. Для этого нужно просмотреть все объекты в ArrayList в любом порядке. Для таких ситуаций очень удобна новая разновидность оператора цикла:

double s = 0;

foreach (Person pers in persons) s = s + pers.Weight;

В заголовке цикла описывается переменная, которая будет использоваться для перебора (Person p) и указывается место, где осуществляется перебор (in persons). Всю остальную работу по организации перебора цикл foreach выполняет автоматически. Заметьте, что явное приведение к типу Person здесь выполнено путем описания переменной цикла p как Person.

Цикл foreach можно использовать и для обычных массивов.

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

Класс List<>

Класс List<> является аналогом ArrayList, но позволяет хранить только объекты заданного типа. Тип хранимых объектов указывается при описании в угловых скобках <>:

List<int> integers = new List<int>(); //множество целых чисел

List<Person> persons; //множество людей

persons= new List<Person>();

Теперь у Вас нет возможности нарушить строгую типизацию:

integers.Add(new Person()); //ошибка компиляции

Для использования класса List<> нужно подключить пространство имен System.Collections.Generic.

До сих пор переменные и методы наших классов описывались с модификатором доступа public. Это позволяло использовать их за пределами класса. Например, для увеличения роста человека, на которого ссылается переменная p можно написать оператор:

p.Height++;

Однако в современном объектно-ориентированном программировании действует правило инкапсуляции, согласно которому все переменные класса делаются закрытыми (private), то есть недоступными за пределами класса. Доступ к этим переменным осуществляется через открытый интерфейс – открытые методы класса.

В связи с этим внесем изменения в класс Person:

class Person

{ private string name;

private double height;

private double weight;

public Person(string Name, double Height, double Weight)

{ name=Name; height=Height; weight=Weight; }

public Person( ){ name=”noname”; height=50; weight=4; }

public void PersonAnalyze()

{ if (height-weight>100.0)

Console.WriteLine(name+" полный");

else

Console.WriteLine(name + " худой");

}

}

Отметим два вида изменений:

· все переменные класса описаны с использованием модификатора доступа private;

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

Теперь за пределами класса уже нельзя осуществить непосредственное использование переменных. Однако выход есть (и даже несколько). Например, можно создать в классе два открытых метода для доступа к каждой переменной (их еще называют методами-аксессорами или get- и set- методами):

public double GetHeight() {return height; }

public void SetHeight(double newHeight) { height=newHeight; }

Теперь для увеличения роста человека на единицу потребуется два вызова методов:

p.SetHeight(p.GetHeight()+1);

Главный вопрос здесь – зачем нужно такое ограничение? Ведь последняя строка не только «ужасно» выглядит, но и замедляет выполнение программы. Дело в том, что преимущества инкапсуляции намного важнее, чем упомянутые здесь недостатки.

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

Если оператор

p.Height++;

еще может соответствовать реальному процессу (увеличение роста человека), то как можно содержательно трактовать оператор

p.Height--;

или

p.Height=-10;

Таким образом, непосредственное использование переменных не способствует поддержке правил и ограничений предметной области (так называемых бизнес-правил). Эту проблему можно решить несколькими способами.

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

public void Grow(int days) { . . . }

Реализация такого метода может быть достаточно реалистичной, учитывая возраст человека.

2. Реализацией ограничений в методах доступа:

public void SetHeight (double newHeight)

{ if ((newHeight>0)&&( newHeight<230)&& (newHeight>height))

height=newHeight;

}

3. Реализацией методов-свойств. О свойствах подробнее будет рассказано ниже.

Обратим внимание на важные следствия такого подхода. Класс с его методами и переменными становится в достаточной степени черным ящиком. Пользователю класса не известны ни особенности реализации методов класса, ни даже информационная структура класса. Это позволяет разделить программный проект на разные по роли фрагменты, которые часто взаимодействуют по принципу клиент-сервер. Клиент использует класс, зная его открытый интерфейс. Примером клиента является метод Main, использующий встроенные и пользовательские классы для решения конкретной задачи. Сервер – это класс, предоставляющий свои услуги. Разработчик серверного класса может изменять (совершенствовать) детали его устройства и функционирования, пока это не влияет на открытый интерфейс класса.



<== предыдущая лекция | следующая лекция ==>
Генерация случайных чисел | Обработка ошибок


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.007 сек.