Постройте создайте проект, в котором содержатся (рис.1):
1. Абстрактный класс с именем HotDrink, у которого имеются
- методы типа stringDrink() (выпить), AddMilk() (добавить молоко), AddSugar() (добавить сахар);
- защищенные поля sugar, milk (значения по умолчанию);
- свойства для этих полейMilk и Sugar.
2. Интерфейс с именем ICup, у которого имеются
- методы Refill() (наполнить повторно), Wash() (вымыть),
- свойства Type (тип) и Capacity (Объем).
3. Класс с именем CupOfCoffee, который является наследником класса HotDrink, поддерживает интерфейс ICup и обладает дополнительным свойством BeanType (тип зерен).
4. Класс с именем CupOfTea, который является производным от класса HotDrink, поддерживает интерфейс ICup и обладает дополнительным свойством LeafType (тип чая).
5. Класс с функцией Main(), а также с функциейProcessCup, которая получает в качестве параметра объект одного из классов CupOfCoffee или CupOfTea, по выбору пользователя (чай или кофе). Далее функция должна вызывать все методы и свойстваабстрактного класса и интерфейса для любого объекта, переданного ей в качестве параметра (т.е. в качестве формального параметра используется абстрактный тип).
Запускаем Visual Studio и создаем консольное приложение(.Net Framework):
Добавляем класс HotDrink(правый клик по проекту -> Добавить -> Создать элемент…). Это будет наш абстрактный класс.
Код класса HotDrink:
abstract class HotDrink
{
protected int sugar = 3;
public int Sugar
{
get { return sugar; }
set
{
if (value < 0) sugar = 0;
if (value > 10) sugar = 10;
if (value >= 0 && value <= 10) sugar = value;
}
}
protected int milk = 3;
public int Milk
{
get { return milk; }
set
{
if (value < 0) milk = 0;
if (value > 5) milk = 5;
if (value >= 0 && value <= 5) milk = value;
}
}
public abstract void Drink();
public void AddMilk(int milk)
{
Milk += milk;
}
public void AddSugar(int sugar)
{
Sugar += sugar;
}
}
Зачем нужны абстрактные классы? Допустим, в нашей программе требуется определить две основных сущности: чашка чая и чашка кофе. Каждая из этих сущностей будет отличаться, например, для кофе надо определить тип зерен, а для чая - тип чая. Т. е. будут созданы отдельные классы CupOfCoffee и CupOfTea. В то же время обе этих сущности могут иметь что-то общее, например, объем добавленного молока и количество кубиков сахара, какую-то другую общую функциональность. И эту общую функциональность лучше вынести в какой-то отдельный класс, например, HotDrink, который описывает некоторый горячий напиток. То есть классы CupOfCoffee и CupOfTea будут производными от класса HotDrink. И так как все объекты в нашей системе будут представлять либо чай, либо кофе, то напрямую экземпляры объекта HotDrink создаваться не будут. Поэтому имеет смысл сделать его абстрактным. Стоит отметить, что метод Drink() в классе HotDrink помечен ключевым словом abstract. Это значит, что во всех классах наследниках потребуется описать свою реализацию метода Drink(). Пример будет приведен ниже в классах CupOfCoffee и CupOfTea. В классе HotDrink также Определены методы AddSugar(), AddMilk() и свойства Milk и Sugar. Свойства обеспечивают простой доступ к полям классов и структур, позволяют узнать их значение или выполнить их установку.
Добавляем в проект интерфейс ICup со следующим кодом(правый клик по проекту -> Добавить -> Создать элемент…):
interface ICup
{
void Refill();
void Wash();
string Type { get; set; }
double Capacity { get; set; }
}
Интерфейс ICup определяет некоторый функционал - набор методов и свойств без реализации. Этот функционал реализуют классы и структуры, в нашем случае CupOfCoffee и CupOfTea.
Добавляем класс CupOfTea:
class CupOfTea: HotDrink, ICup
{
protected string leafType = "черный";
public string LeafType
{
get { return leafType; }
set
{
if (value.Equals("зеленый"))
leafType = value;
}
}
protected string type = "пластик";
public string Type
{
get { return type; }
set
{
if (value == "стекло")
type = value;
}
}
protected double capacity = 0.2;
public double Capacity
{
get { return capacity; }
set
{
if (value <= 0.2) capacity = 0.2;
if (value > 0.2) capacity = 0.3;
}
}
public override void Drink()
{
Console.WriteLine("Какой вкусный чай!");
}
public void Refill()
{
Console.WriteLine("Повторить чай {4} объемом {0}\n" +
"Молоко: {1}\n" +
"Сахар: {2}\n" +
"Тип стакана: {3}\n", Capacity, Milk, Sugar, Type, leafType);
}
public void Wash()
{
Console.WriteLine("Вымыть {0} чашку с чаем\n", Type);
}
}
В классе CupOfTea мы добавили свойство «тип зерна» LeafType и соответствующее защищенное поле leafType. leafType с модификатором доступа protected будут иметь доступ все классы наследники от класса CupOfTea (возможно в будущем потребуется добавить еще несколько типов чая). В классе CupOfTea переопределен метод Drink():
public override void Drink(){ Console.WriteLine("Какой вкусный чай!"); }
Если динамическим типом объекта будет CupOfTea, то будет вызвана версия из данного класса(CupOfTea). Например
HotDrink c = new CupOfTea();
c.Drink();// будет вызвана версия CupOfTea(динамический тип переменной с – CupOfTea, статический - HotDrink)
c = new CupOfCoffee();
c.Drink();// будет вызвана версия CupOfCoffee(динамический тип переменной с – CupOfCoffee, статический – HotDrink)
Добавляем класс CupOfCoffee со следующим кодом(весь код аналогичен предыдущему):
class CupOfCoffee: HotDrink, ICup
{
protected string beanType = "арабика";
public string BeanType
{
get { return beanType; }
set
{
if (value.Equals("робуса"))
beanType = value;
}
}
protected string type = "пластик";
public string Type { get { return type; }
set {
if (value is string)
if (value == "стекло")
type = value;
}
}
protected double capacity = 0.2;
public double Capacity { get { return capacity; }
set {
if (value <= 0.2) capacity = 0.2;
if (value > 0.2) capacity = 0.3;
}
}
public override void Drink()
{
Console.WriteLine("Какое вкусное кофе!");
}
public void Refill()
{
Console.WriteLine("Повторить кофе {4} объемом {0}\n" +
"Молоко: {1}\n" +
"Сахар: {2}\n" +
"Тип стакана: {3}\n", Capacity, Milk, Sugar, Type, BeanType);
}
public void Wash()
{
Console.WriteLine("Вымыть {0} чашку с кофе\n", Type);
}
}
Используем приведенные выше классы для создания требуемого напитка(в классе Program)
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Выберите напиток: кофе <1> или чай <2>: ");
switch (int.Parse(Console.ReadLine()))
{
case 1:
ProcessCup(new CupOfCoffee());
break;
case 2:
ProcessCup(new CupOfTea());
break;
default:
Console.WriteLine("Такого нет");
break;
}
Console.ReadLine();
}
static void ProcessCup(CupOfCoffee cup)
{
Console.WriteLine("Тип зерна: арабика или робуса <по умолчанию арабика>;\n" +
"Сахар: 0...10 <по умолчанию 2>;\n" +
"Молоко: 0...5 <по умолчанию 2>;\n" +
"Тип стакана: пластик или стекло <по умолчанию пластик>;\n" +
"Объем 0,2 или 0,3 <по умолчанию 0,2>;\n");
Console.WriteLine("Тип зерна: ");
cup.BeanType = Console.ReadLine();
Console.WriteLine("Молоко: ");
cup.Milk = int.Parse(Console.ReadLine());
Console.WriteLine("Сахар: ");
cup.Sugar = int.Parse(Console.ReadLine());
Console.WriteLine("Тип стакана: ");
cup.Type = Console.ReadLine();
Console.WriteLine("Объем <мл>: ");
cup.Capacity = double.Parse(Console.ReadLine());
Console.WriteLine("--------------\n" +
"В кофе добавлен сахар: {0}\n" +
"В кофе добавлено молоко: {1}\n" +
"Получите кофе: {2}\n", cup.Sugar, cup.Milk, cup.BeanType);
cup.Drink();
cup.Wash();
cup.Refill();
}
static void ProcessCup(CupOfTea cup)
{
Console.WriteLine("Тип чая: зеленый или черный <по умолчанию черный>;\n" +
"Сахар: 0...10 <по умолчанию 2>\n" +
"Молоко: 0...5 <по умолчанию 2>\n" +
"Тип стакана: пластик или стекло <по умолчанию пластик>\n" +
"Объем 0,2 или 0,3 <по умолчанию 0,2>\n");
Console.WriteLine("Тип чая: ");
cup.LeafType = Console.ReadLine();
Console.WriteLine("Молоко: ");
cup.Milk = int.Parse(Console.ReadLine());
Console.WriteLine("Сахар: ");
cup.Sugar = int.Parse(Console.ReadLine());
Console.WriteLine("Тип стакана: ");
cup.Type = Console.ReadLine();
Console.WriteLine("Объем <мл>: ");
cup.Capacity = double.Parse(Console.ReadLine());
Console.WriteLine("--------------\n" +
"В чай добавлен сахар: {0}\n" +
"В чай добавлено молоко: {1}\n" +
"Получите чай: {2}\n", cup.Sugar, cup.Milk, cup.LeafType);
cup.Drink();
cup.Wash();
cup.Refill();
}
}
УПРАЖНЕНИЕ
Мы написали версию программы с двумя методами ProccessCup. Один из них принимает в качестве аргумента класс CupOfTea, а другой принимает в качестве аргумента класс CupOfCoffee. Требуется объединить приведенные выше две версии метода ProccessCup в одну. Подсказка: метод ProccessCup в качестве аргумента должен принимать HotDrink и внутри можно использовать конструкции RTTI из С#, например операторы is и as.