Организация закрытого и открытого доступа 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Организация закрытого и открытого доступа



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

- Члены, используемые только в классе, должны быть закрытыми.

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

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

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

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

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

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

 

8.1.3 Практический пример организации управления доступом

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

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

Для стека определены две основные операции: поместить данные в стек и извлечь их оттуда. Первая операция помещает значение на вершину стека, а вторая - извле­кает значение из вершины стека. Следовательно, операция извлечения является без­возвратной: как только значение извлекается из стека, оно удаляется и уже недоступно в стеке.

В рассматриваемом здесь примере создается класс Stack, реализующий функции стека. В качестве базовых средств для хранения данных в стеке служит закрытый мас­сив. А операции размещения и извлечения данных из стека доступны с помощью от­крытых методов класса Stack. Таким образом, открытые методы действуют по упо­мянутому выше"принципу "последним пришел - первым обслужен". Как следует из приведенного ниже кода, в классе Stack сохраняются символы, но тот же самый меха­низм может быть использован и для хранения данных любого другого типа.

Листинг 8.2

// Класс для хранения символов в стеке.

 

using System;

 

class Stack

{

// Эти члены класса являются закрытыми.

char[] stck; // массив, содержащий стек

int tos; // индекс вершины стека

 

// Построить пустой класс Stack для реализации стека

// заданного размера.

public Stack(int size)

{

stck = new char[size]; // распределить память для стека

tos = 0;

}

 

// Поместить символы в стек.

public void Push(char ch)

{

if(tos==stck.Length) {

Console.WriteLine(" – Стек заполнен.");

return;

}

 

stck[tos] = ch;

tos++;

}

 

// Извлечь символ из стека.

public char Pop()

{

if(tos==0)

{

Console.WriteLine(" -- Stack is empty.");

return (char) 0;

}

 

tos--;

return stck[tos];

}

 

// Возвратить значение true, если стек заполнен.

public bool IsFull()

{

return tos==stck.Length;

}

 

// Возвратить значение true, если стек пуст.

public bool IsEmpty()

{

return tos==0;

}

 

// Возвратить общую емкость стека.

public int Capacity()

{

return stck.Length;

}

 

// Возвратить количество объектов, находящихся

// в данный момент в стеке.

public int GetNum()

{

return tos;

}

}

Рассмотрим класс Stack более подробно. В начале этого класса объявляются две следующие переменные экземпляра.

// Эти члены класса являются закрытыми.

char[] stck; // массив, содержащий стек

int tos; // индекс вершины стека

Массив stck предоставляет базовые средства для хранения данных в стеке (в дан­ном случае - символов). Обратите внимание на то, что память для этого массива не распределяется. Это делается в конструкторе класса Stack. А член tos данного класса содержит индекс вершины стека.

Оба члена, tos и stck, являются закрытыми, и благодаря этому соблюдается прин­цип "последним пришел - первым обслужен. Если же разрешить открытый доступ к члену stck, то элементы стека окажутся доступными не по порядку. Кроме того, член tos содержит индекс вершины стека, где находится первый обслуживаемый в стеке элемент, и поэтому манипулирование членом tos в коде, находящемся за преде­лами класса Stack, следует исключить, чтобы не допустить разрушение самого стека. Но в то же время члены stck и tos доступны пользователю класса Stack косвенным образом с помощью различных отрытых методов, описываемых ниже.

Рассмотрим далее конструктор класса Stack.

// Построить пустой класс Stack для реализации стека

// заданного размера.

public Stack(int size)

{

stck = new char[size]; // распределить память для стека

tos = 0;

}

Этому конструктору передается требуемый размер стека. Он распределяет память для базового массива и устанавливает значение переменной tos в нуль. Следователь­но, нулевое значение переменной tos указывает на то, что стек пуст.

Открытый метод Push() помещает конкретный элемент в стек, как показано ниже.

// Поместить символы в стек.

public void Push(char ch)

{

if (tos==stck.Length)

{

Console.WriteLine(" - Стек заполнен.");

return;

}

 

stck[tos] = ch;

tos++;

}

Элемент, помещаемый в стек, передается данному методу в качестве параметра ch. Перед тем как поместить элемент в стек, выполняется проверка на наличие свободного места в базовом массиве, а именно: не превышает ли значение переменной tos длину массива stck. Если свободное место в массиве stck есть, то элемент сохраняется в нем по индексу, хранящемуся в переменной tos, после чего значение этой переменной инкрементируется. Таким образом, в переменной tos всегда хранится индекс следую­щего свободного элемента массива stck.

Для извлечения элемента из стека вызывается открытый метод Pop(), приведен­ный ниже.

// Извлечь символ из стека.

public char Рор()

{

if(tos==0)

{

Console.WriteLine(" - Стек пуст.");

return (char) 0;

}

tos--;

return stck[tos];

}

В этом методе сначала проверяется значение переменной tos. Если оно равно нулю, значит, стек пуст. В противном случае значение переменной tos декрементируется, и затем из стека возвращается элемент по указанному индексу.

Несмотря на то что для реализации стека достаточно методов Push() и Pop(), по­лезными могут оказаться и другие методы. Поэтому в классе Stack определены еще четыре метода: IsFull(), IsEmpty(), Capacity() и GetNum(). Эти методы предо­ставляют всю необходимую информацию о состоянии стека и приведены ниже.

// Возвратить значение true, если стек заполнен.

public bool IsFull()

{

return tos == stck.Length;

}

 

// Возвратить значение true, если стек пуст.

public bool IsEmpty()

{

return tos==0;

}

 

// Возвратить общую емкость стека.

public int Capacity()

{

return stck.Length;

}

 

// Возвратить количество объектов, находящихся

// в данный момент в стеке.

public int GetNum()

{

return tos;

}

Метод IsFull() возвращает логическое значение true, если стек заполнен, а ина­че - логическое значение false. Метод IsEmpty() возвращает логическое значение true, если стек пуст, а иначе - логическое значение false. Для получения общей ем­кости стека (т.е. общего числа элементов, которые могут в нем храниться) достаточно вызвать метод Capacity(), а для получения количества элементов, хранящихся в на­стоящий момент в стеке, - метод GetNum(). Польза этих методов состоит в том, что для получения информации, которую они предоставляют, требуется доступ к закры­той переменной tos. Кроме того, они служат наглядными примерами организации безопасного доступа к закрытым членам класса с помощью открытых методов.

Конкретное применение класса Stack для реализации стека демонстрируется в приведенной ниже программе.

Листинг 8.3

// Продемонстрировать применение класса Stack.

 

using System;

 

// Класс для хранения символов в стеке.

class Stack

{

// Эти члены класса являются закрытыми.

char[] stck; // массив, содержащий стек

int tos; // индекс вершины стека

 

// Построить пустой класс Stack для реализации стека

// заданного размера.

public Stack(int size)

{

stck = new char[size]; // распределить память для стека

tos = 0;

}

 

// Поместить символы в стек.

public void Push(char ch)

{

if(tos==stck.Length) {

Console.WriteLine(" – Стек заполнен.");

return;

}

 

stck[tos] = ch;

tos++;

}

 

// Извлечь символ из стека.

public char Pop()

{

if(tos==0)

{

Console.WriteLine(" -- Stack is empty.");

return (char) 0;

}

 

tos--;

return stck[tos];

}

 

// Возвратить значение true, если стек заполнен.

public bool IsFull()

{

return tos==stck.Length;

}

 

// Возвратить значение true, если стек пуст.

public bool IsEmpty()

{

return tos==0;

}

 

// Возвратить общую емкость стека.

public int Capacity()

{

return stck.Length;

}

 

// Возвратить количество объектов, находящихся

// в данный момент в стеке.

public int GetNum()

{

return tos;

}

}

 

class StackDemo

{

static void Main()

{

Stack stk1 = new Stack(10);

Stack stk2 = new Stack(10);

Stack stk3 = new Stack(10);

char ch;

int i;

 

// Поместить ряд символов в стек stk1.

Console.WriteLine("Поместить символы A-J в стек stk1.");

for(i=0;!stk1.IsFull(); i++)

stk1.Push((char) ('A' + i));

 

if(stk1.IsFull()) Console.WriteLine("Стек stk1 заполнен.");

 

// Вывести содержимое стека stk1.

Console.Write("Содержимое стека stk1: ");

while(!stk1.IsEmpty()) {

ch = stk1.Pop();

Console.Write(ch);

}

 

Console.WriteLine();

 

if(stk1.IsEmpty()) Console.WriteLine("Стек stk1 пуст.\n");

 

// Поместить дополнительные символы в стек stk1.

Console.WriteLine("Вновь поместить символы A-J в стек stk1.");

for(i=0;!stk1.IsFull(); i++)

stk1.Push((char) ('A' + i));

 

// А теперь извлечь элементы из стека stk1 и поместить их в стек stk2.

// В итоге элементы сохраняются в стеке stk2 в обратном порядке.

Console.WriteLine("А теперь извлечь символы из стека stk1\n" +

"и поместить их в стек stk2.");

while(!stk1.IsEmpty()) {

ch = stk1.Pop();

stk2.Push(ch);

}

 

Console.Write("Содержимое стека stk2: ");

while(!stk2.IsEmpty()) {

ch = stk2.Pop();

Console.Write(ch);

}

 

Console.WriteLine("\n");

 

// Поместить 5 символов в стек.

Console.WriteLine("Поместить 5 символов в стек stk3.");

for(i=0; i < 5; i++)

stk3.Push((char) ('A' + i));

 

Console.WriteLine("Емкость стека stk3: " + stk3.Capacity());

Console.WriteLine("Количество объектов в стеке stk3: " +

stk3.GetNum());

}

}

При выполнении этой программы получается следующий результат.

Поместить символы A-J в стек stkl.

Стек stkl заполнен.

Содержимое стека stkl: JIHGFEDCBA

Стек stkl пуст.

 

Вновь поместить символы A-J в стек stkl.

А теперь извлечь символы из стека stkl

и поместить их в стек stk2.

Содержимое стека stk2: ABCDEFGHIJ

 

Поместить 5 символов в стек stk3.

Емкость стека stk3: 10

Количество объектов в стеке stk3: 5



Поделиться:


Последнее изменение этой страницы: 2016-12-30; просмотров: 130; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.207.126.53 (0.078 с.)