1.3 Разработка класса и реализация консольной программы на основе разрабатываемого класса.

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

Создадим новый класс, назовем его Man (человек).

Наш класс будет схематично описывать человека следующим образом:

Описание класса. Имя, возраст, здоровье и состояние жив / мертв будут описывать каждый конкретный экземпляр нашего класса - на основе этих параметров так же будет основываться работа функций Talk, Go, Kill и IsAlive.

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





 
Создадим новое консольное приложение и назовем его ClassTesting.

После сгенерированного программой класса Program мы создадим свой класс, назвав его Man и снабдив его необходимыми свойствами и методами:

/*http://esate.ru, Anvi*/

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ClassTesting 
{

	class Program 
	{ 
		static void Main(string[] args) 
		{ 

		}
	} 

	public class Man 
	{ 
		// конструктор класса (данная функция вызывается 
		// при создании нового экземпляра класса 
		public Man(string _name) 
		{ 
			Name = _name; 
			isLife = true; 
		} 

		// закрытые члены, которые нельзя изменить 
		// извне класса

		// строка, содержащая имя 
		private string Name;

		// беззнаковое целое число, содержащая возраст 
		private uint Age;

		// беззнаковое целое число, отражающее уровень здоровья 
		private uint Health;

		// булево, означающее жив ли данный человек 
		private bool isLife;

		// заготовква функции "говорить" 
		public void Talk() 
		{

		}

		// заготовка функции "идти" 
		public void Go() 
		{

		}

		// функция, возвращающая показатель - жив ли данный человек. 
		public bool IsAlive() 
		{ 
		// возращаем значение, к которому мы не можем 
		// обратиться напрямую из вне класса, 
		// так как оно имеет статус private 
		return isLife; 
		}

	}

}




Вот такая вот заготовка нашей программы. Как видите, мы добавили еще одну функцию, о которой забыли в схеме нашего класса IsAlive.

Данная функция будет возвращать значение переменной isLife, к которой мы не можем получить доступ извне класса, так как она является закрытой (Private).

Теперь более тщательно займемся реализацией наших классов.

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

Random в C#. Генерация случайного числа в C#


Хорошее знание языков программирования никогда не обходится без знания того, как выполняется генерация случайных чисел. Сейчас мы рассмотрим то, как выполняется генерация случайного числа в С#.

Для выполнения данной задачи сначала создадим новый экземпляр класса Random:

Random rnd = new Random();

Теперь для того чтобы получить случайное число, достаточно использовать созданный экземпляр класса, вызывая метод Next();

Например:

Age = rnd.Next();

При желании (а нам этого очень хочется), можно генерировать число в заданном диапазоне, указав начальное и конечное значение.

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

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

/*http://esate.ru, Anvi*/

// конструктор класса (данная функция вызывается 
// при создании нового экземпляра класса 

public Man(string _name) 
{ 
	// получаем имя человека из входного параметра 
	// конструктора класса 
	Name = _name; 
	// экземпляр жив 
	isLife = true; 

	// генерируем возраст от 15 до 50 
	Age = (uint)rnd.Next(15,51); 
	// и здоровье, от 10 до 100% 
	Health = (uint)rnd.Next(10, 101);
} 




uint перед экземпляром класса rnd означает, что значение случайного числа, которое вернет функция Next будет приведено к типу uint (unsigned – т.е. беззнаковое int). Просто функция rnd возвращает значение с типом int, и данное значение не может быть неявно преобразовано, поэтому необходимо сообщить компилятору о преобразовании.

После конструктора класса, добавим объявление нашего экземпляра класса Random:

/*http://esate.ru, Anvi*/

// экземпляр класса Random 
// для генерации случайных чисел 

private Random rnd = new Random(); 




Остается только модернизировать наши функции, предназначенные для перемещения и разговора.

Сначала рассмотрим функцию разговора. Начало кода функции будит таким:

/*http://esate.ru, Anvi*/

// заготовка функции "говорить" 
public void Talk() 
{ 
	// генерируем случайное число от 1 до 3 
	int random_talk = rnd.Next(1, 4); 

	// объявляем переменную, в которой мы будем хранить 
	// строку 

	string tmp_str = "";




Как видите, здесь мы объявляем переменную random_talk, и сразу при объявлении она получает значение – результат выполнения функции rnd.Next, в диапазоне от 1 до 3.

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

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

Генерация строки будет выполняться с помощью оператора выбора switch:

/*http://esate.ru, Anvi*/

// в зависимости от случ значения random_talk 
switch (random_talk) 
{ 

	case 1: // если 1 - называем свое имя 
	{ // генерируем текст сообщения 
		tmp_str = "Привет, меня зовут " + Name + ", рад познакомиться"; 
		// завершаем оператор выбора 
		break;
	} 

	case 2: // возраст 
	{ 
		// генерируем текст сообщения 
		tmp_str = "Мне " + Age + ". А тебе?"; 
		// завершаем оператор выбора 
		break;
	} 

	case 3: // говорим о своем здоровье 
	{ 

		// в зависимости от параметра здоровья 
		if (Health > 50) 
			tmp_str = "Да я здоров как бык!"; 
		else 
			tmp_str = "Со здоровьем у меня хреново, дожить бы до " + (Age + 10).ToString(); 

		// завершаем оператор выбора 
		break; 
	}

} 




Как видно из кода, в зависимости от значения переменной random_talk выполняется ветвление кода и выбирается одна из веток для значения: random_talk = 1 (case 1), random_talk = 2 (case 2) или random_talk = 3 (case 3).

И, собственно, завершение функции:

/*http://esate.ru, Anvi*/

// выводим в консоль сгенерированное сообщение 
	System.Console.WriteLine(tmp_str); 
}




Теперь рассмотрим код функции Go.

Здесь все проще: сначала мы определяем, жив ли объект, если нет, то мы сгенерируем строку с сообщением о том, что данный человек умер и не может идти.

Мы проверим уровень здоровья данного человека и в зависимости от результата сгенерируем строку.

Код данной функции с подробными комментариями вы можете видеть ниже:

/*http://esate.ru, Anvi*/

// заготовка функции "идти" 
public void Go() 
{ 

	// если объект жив 
	if (isLife == true) 
	{ 
		// если показатель более 40 
		// считаем объект здоровым 
		if (Health > 40) 
		{ 
			// генерируем строку текста 
			string outString = Name + " мирно прогуливается по городу"; 
			// выводим в консоль 
			System.Console.WriteLine(outString);
		} 
		else 
		{
			// генерируем строку текста 
			string outString = Name + " болен и не может гулять по городу"; 
			// выводим в консоль 
			System.Console.WriteLine(outString);
		}

	} 
	else 
	{ 
		// генерируем строку текста 
		string outString = Name + " не может идти, он умер"; 
		System.Console.WriteLine(outString);
	} 

}




Да, напоследок добавим функцию, которая убивает нашего человека.

Код ее будет выглядеть следующим образом, в нем нет ничего сложного.

/*http://esate.ru, Anvi*/

public void Kill() 
{ 
	// устанавливаем значение isLife (жив) 
	// в false... 
	isLife = false;
} 




Вот и все. Если вы набрали весь код верно, то при компиляции (клавиша F5) не должно возникнуть никаких проблем.

Теперь вернемся к коду главного класса (Program).

Нам необходимо сделать так, чтобы консоль ожидала команды пользователя: в зависимости от этих команд будут выполняться различные действия: создание новых экземпляров класса Man (так сказать, создание новых людей) и выполнение функций, которые реализованы в классе Man.

Для этого мы создадим бесконечный цикл: в нем программа будет запрашивать пользователя ввести строку. Затем строка будет сверяться с заданным набором команд при помощи оператора выбора (switch).

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

Первым делом объявим переменную user_command, в которой мы будем хранить команду, введенную пользователем, далее мы объявим переменную Infinity. До тех пор пока значение Infinity будет равно true, цикл будет выполняться. Изменение этой переменной произойдет, только если пользователь введет команду exit.

/*http://esate.ru, Anvi*/

static void Main(string[] args) 
{ 

	// переменная, которая будет хранить команду пользователя 
	string user_command = ""; 

	// бесконечный цикл 
	bool Infinity = true; 

	while (Infinity) // пока Infinity равно true 
	{ 
		// приглашение ввести команду 
		System.Console.WriteLine("Пожалуйста, введите команду");

		// получение строки (команды) от пользователя 
		user_command = System.Console.ReadLine();



Далее, из кода видно, что мы начинаем наш цикл while.

При старте выполнения кода из тела цикла, в консоль сначала выводиться строка с приглашением ввести команду. Далее мы ожидаем ввода строки пользователем. Введенная строка после нажатия клавиши Enter будет записана в переменную user_command.

Теперь с помощью операции ветвления, мы создадим обработку стандартных команд: exit и help.

Ветвление default будет выполняться в том случае, если введенная строка не будет соответствовать ни одной введенной команде.

/*http://esate.ru, Anvi*/

// обработка команды с помощью оператора ветвления 
switch (user_command) 
{ 

	// если user_command содержит строку exit 
	case "exit": 
	{ 
		Infinity = false; 
		// теперь цикл завершиться, и программа завершит свое выполнение 
		break;
	} 

	// если user_command содержит строку help 
	case "help": 
	{
		System.Console.WriteLine("Список команд:"); 
		System.Console.WriteLine("---"); 

		System.Console.WriteLine("create_man : команда создает человека, (экземпляр класса Man)"); 
		System.Console.WriteLine("kill_man : команда убивает человека"); 
		System.Console.WriteLine("talk : команда заставляет человека говорить (если создан экземпляр класса)"); 
		System.Console.WriteLine("go : команда заставляет человека идти (если создан экземпляр класса)"); 

		System.Console.WriteLine("---"); 
		System.Console.WriteLine("---");

		break;
	} // если команду определить не удалось 

	default: 
	{
		System.Console.WriteLine("Ваша команда не определена, пожалуйста, повторите снова"); 
		System.Console.WriteLine("Для вывода списка команд введите команду help"); 
		System.Console.WriteLine("Для завершения программы введите команду exit"); 
		break;
	} 

}




Не забудьте закрыть все фигурные скобки ( } ) после операции ветвления.

Таким образом, теперь, если мы откомпилируем проект (клавиша F5), то мы увидим окно консоли с приглашение ввести команду.
Уроки OpenGL + C#: Пример выполнения команд из консоли Рисунок 1. Пример выполнения команд из консоли.
Теперь нам осталось лишь реализовать обработку команд create_man, kill_man, talk и go.

После строки объявления переменной и перед началом цикла while добавьте объявления экземпляра класса Man.

/*http://esate.ru, Anvi*/

// пустой (раный null) экземпляр класса Man 
Man SomeMan = null; 




Теперь рассмотрим код обработки команды crete_man в теле оператора ветвления (switch)

 

/*http://esate.ru, Anvi*/

case "create_man": 
{ 
	// проверяем, создан ли уже какой либо человек 
	if (SomeMan != null) 
	{ 
		// человек уже существует. 
		// убиваем его 
		// (это не обязательная операция синтаксиса языка 
		// а всего лишь каприз автора кода :), вы можете пропустить эту строку) 

		SomeMan.Kill(); 

	} // просим ввести имя человека 

	System.Console.WriteLine("Пожалуйста, введите имя создаваемого человека ");

	// получаем строку введенную пользователем 
	user_command = System.Console.ReadLine();

	// создаем новый объект в памяти, в качестве параметра 
	// передаем имя человека 
	SomeMan = new Man(user_command);

	// сообщаем о создании 
	System.Console.WriteLine("Человек успешно создан "); 

	break;

} 




Как видно из кода, с помощью оператора new мы создаем новый объект в памяти.

Теперь он имеет имя и ряд параметров, и мы можем выполнять другие команды, осуществляющие работу с классом.

/*http://esate.ru, Anvi*/

case "kill_man": 
{ 
	// проверяем, что объект существует в памяти 
	if (SomeMan != null) 
	{ 
		// вызываем фукнцию сметри 
		SomeMan.Kill(); 
	} 
	break;
} 




Это код функции смерти.

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

Мы делаем это, проверяя, не равен ли наш объект (к примеру, SomeMan) null. Если не выполнить такую проверку, а потом в ходе работы программы окажется, что SomeMan = null, а мы попытаемся вызвать любой из его методов (кроме конструктора класса – он как раз и создает объект в памяти), то в программе произойдет ошибка и обработка исключения.

Для того чтобы выполнить функцию kill( );, компилятор сначала получает адрес памяти, где сейчас хранится экземпляр нашего класса. SomeMan как раз должен хранить этот адрес, а он будет равен null. Следовательно, компилятор по сути получит команду по адресу null определить адрес функции Kill и выполнить ее. У него это, конечно, не получится.
Собственно, остались команды talk и go.

Они будут реализованы так же, как и команда kill: нам достаточно проверить, что объект существует в памяти. Если он существует, выполнить метод. Если нет – сообщить об этом.

/*http://esate.ru, Anvi*/

case "talk": 
{ 
	// проверяем, что объект существует в памяти 
	if (SomeMan != null) 
	{ 
		// вызываем функцию разговора 
		SomeMan.Talk();
	} 
	else // иначе 
	{ 
		System.Console.WriteLine("Человек не создан. Команда не может быть выполнена");
	} 

	break;
} 

case "go": 
{

	// проверяем, что объект существует в памяти 
	if (SomeMan != null) 
	{ 
		// вызываем функцию передвижения 
		SomeMan.Go(); 
	} 
	else 
	{ 
		System.Console.WriteLine("Человек не создан. Команда не может быть выполнена"); 
	} 

	break;

} 




Пример работы откомпилированной программы:
Уроки OpenGL + C#: Пример работы написанной программы Рисунок 2. Пример работы написанной программы.

Примечания:

1. Метод random.next(int32, int32).
Обратите внимание на то, что метод random.next принимает 2 входящих параметра:

minValue - включенный нижний предел возвращаемого случайного числа.
maxValue - исключенный верхний предел возвращаемого случайного числа. Значение свойства maxValue должно быть больше или равно значению свойства minValue.
Прикрепленные файлы для скачивания:
Добавить комментарий
Расширенный режим добавления комментариев доступен на форуме: загрузка изображений, цитирование, форматирование текста, и т.д.
Ваше имя:
Текст сообщения:
Комментарии (3):
releyshic
releyshic,  
Цитата
Мы делаем это, проверяя, не равен ли наш объект (к примеру, SomeMan) null. Если не выполнить такую проверку, а потом в ходе работы программы окажется, что SomeMan = null, а мы попытаемся вызвать лубой из его методов (кроме конструктора класса – он как раз и создает объект в памяти), то в программе произойдет ошибка и обработка исключения.
"лубой " очепятка ))

Цитата
// пустой (раный null) экземпляр класса Man
что значит пустой? те сам экземпляр класса есть но просто все его свойства и поля не заполнены - равны 0
а зачем вообще тогда его создавать?
releyshic
releyshic,  
эта функциЯ нигде не вызывается
Код
 // функция, возвращающая показатель - жив ли данный человек.
        public bool IsAlive()
Гость
Гость,  
Я, написав код  также, как у вас удивился, почему мне после команды kill команда go выдаёт Nikita мёртв, а команда talk выдаёт Я здоров как бык!?
^