#c_sharp
Привет всем! В продолжение темы Ссылка на класс или делегат, где уважаемый @Alex Krass пытался мне объяснить, какая польза от применения интерфейса. Для меня все так же остается загадкой. Я все так же считаю, что это лишняя писанина кода. За это время я почитал немало статей про интерфейс и просмотрел видеокурс. Но так и не разобрался. Честно сказать, я не знаю, почему я зациклился на нем, ведь не знал бы о его существовании, давно бы закончил писать свой проект. Вот, к примеру, Алекс объясняет, что в его примере он с легкостью может добавить еще 100 классов useConnect, но, на мой взгляд, ему также нужно 100 раз вызывать connect = new UseConnect(ссылка на класс());, причем в его конкретном случае ему придется плодить switch, чтобы вызвать все классы. Причем я так и не понял, как в таком случае можно добраться до метода из какого-либо класса, в том примере их можно вызвать только все кучей. Причем если в главном классе мне нужно будет еще раз использовать какой-нибудь метод, то мне опять придется переписывать connect = new UseConnect(ссылка на класс());. В моем же случае, где я просто пишу ссылку на класс и через переменную вызываю метод, так я эту переменную могу использовать где захочу и когда захочу, причем могу вызвать любой из методов. Да и вообще мне не придется писать класс UseConnect, я могу вызывать методы сразу, в данном примере из класса MySQL, к примеру. Вот реальный пример, который мне нужно реализовать в своем примере. Опять же повторюсь, с помощью ссылки на классы я уже эту задачу решал. Просто хочу посмотреть, как решают такую задачу профи, с помощью интерфейсов. Вот пример. У меня есть форма, в которой пользователь может сохранять записи в базе данных. В моем случае MySQL. Он может внести запись, после вызвать ее и сделать изменения. У меня есть пять классов. Главный, который вызывает форму, класс инсерт, класс упдата, класс селест и класс подключения к базе. Класс инсерт упдата и селект наследуют класс подключения к базе. Ну это я так решил сделать, чтобы не использовать интерфейс. Вот и сама задача: как мне эти четыре класса с помощью интефейса(ов) подключить к главному классу с формой. Ну, я это так для моего примера взял. Лучше, конечно, приведите, явный пример, где интерфейс облегчает жизнь программисту. Прошу не заводить тему моей грамотности и знания русского языка. Эту тему мы уже обсуждали и я не раз говорил о причине моей безграмотности русского языка. И так же не посылайте меня за книжкой, ну если только посоветуете хорошую.
Ответы
Ответ 1
Сейчас Вам, скорее всего, это не надо, Вы столкнетесь с этим когда-нибудь позже, когда будете готовы. Не заморачивайтесь и идите дальше, очень часто программисты вынуждены пропускать темы и возвращаться к ним. Главное, что Вы знаете, что есть такая вещь, как интерфейс, и она позволяет скрывать реальные реализации классов. С помощью интерфейсов Вы: не завязываете логику своего приложения с конкретными классами и можете легко вносить изменения в одни классы, не трогая другие, добавлять функциональность или заменить один класс абсолютно другим, не трогая все приложение. То есть реализуется абстракция от реализации; можете проектировать логику приложений на интерфейсах, оставив реализацию на потом и применяя заглушки; применять так называемое множественное наследование; если будете начальником, сможете легко донести свои мысли до подчиненных (реализуй мне функциональность вот этого интерфейса). Я дам несколько примеров, в которых применяется интерфейс, но сразу оговорюсь, они не являются лучшими представителями. Ведь я тоже учусь. ) Проектирование недозоопарка Давайте запроектируем небольшую программу зоопарка, при этом зоопарк у нас бужет пошаговым. 1. В первую очередь его стоит населить животными, которые умеют ходить по нему, приступим. Для описания жизненного цикла зоопарка я использую класс ZooLivecycle: class ZooLivecycle { public void allPetWalk() { } } Итак, у нас есть животные, которые умеют ходить, давайте определим их возможности через интерфейсы и реализуем. interface IWalk { void walk(); } class Cat : IWalk { public void walk() { Console.WriteLine("cat walk"); } } class Dog : IWalk { public void walk() { Console.WriteLine("dog walk"); } } class Fish : IWalk { public void walk() { Console.WriteLine("fish cant walk"); } } class Bird : IWalk { public void walk() { Console.WriteLine("bird can fly"); } } Для того чтобы все животные ходили, проще их передать в класс зоопарка всем массивом и пройтись по ним циклом. class ZooLivecycle { public void allPetWalk(IWalk[] arr) { for (int i = 0; i < arr.Count(); i++) arr[i].walk(); } } Итак, теперь можно вызывать нашу реализацию. class Program { static void Main(string[] args) { ZooLivecycle zoo = new ZooLivecycle(); IWalk[] walks = new IWalk[]{new Cat(), new Dog(), new Fish(), new Bird()}; Console.WriteLine("\n*Pet Walk*"); zoo.allPetWalk(walks); Console.Read(); } } А теперь попробуйте реализовать это без интерфейсов, главным образом функцию allPetWalk, хотя есть способ - это общий класс родитель. Можно также попробовать передавать ссылку как public void allPetWalk(Object[] arr) и потом приводить типы, но это является очень плохой практикой, так как вы теряете контроль над типами и вынуждены добавлять проверки, что не является лучшим решением. 2. Идем дальше, мы решили добавить систему наблюдения, а именно видеокамеры, которая сможет передавать информацию. interface IObservation { void analyze(); } class Videocamera : IObservation { public void analyze() { Console.WriteLine("In zoo all ok"); } } Реализуем получение информации в классе зоопарка: class ZooLivecycle { public void allPetWalk(IWalk[] arr) { for (int i = 0; i < arr.Count(); i++) arr[i].walk(); } public void zooAnalyze(IObservation[] arr) { for (int i = 0; i < arr.Count(); i++) arr[i].analyze(); } } Ну и вызов. class Program { static void Main(string[] args) { ZooLivecycle zoo = new ZooLivecycle(); IWalk[] walks = new IWalk[]{new Cat(), new Dog(), new Fish(), new Bird()}; IObservation[] analyze = new IObservation[] { new Videocamera() }; Console.WriteLine("\n*Pet Walk*"); zoo.allPetWalk(walks); Console.WriteLine("\n*Analyze zoo*"); zoo.zooAnalyze(analyze); Console.Read(); } } 3. А теперь давайте подложим свинью, если кто-то все еще использовал класс родитель, вместо интерфейсов. Реализуем помошника, который может как ходить по зоопарку, так и передавать информацию. В языке C# нет перекрестного наследования, но зато можно наследовать несколько интерфейсов вместо этого. class HelperPet : IWalk, IObservation { public void walk() { Console.WriteLine("helppet walk"); } public void analyze() { Console.WriteLine("helppet analyze"); } } Это все, что пришлось добавить. Можно дальше пользоваться нашим зоопарком, ничего не переписывая. class Program { static void Main(string[] args) { ZooLivecycle zoo = new ZooLivecycle(); IWalk[] walks = new IWalk[]{new Cat(), new Dog(), new Fish(), new Bird(), new HelperPet()}; IObservation[] analyze = new IObservation[] { new Videocamera(), new HelperPet() }; Console.WriteLine("\n*Pet Walk*"); zoo.allPetWalk(walks); Console.WriteLine("\n*Analyze zoo*"); zoo.zooAnalyze(analyze); Console.Read(); } } Теперь давайте рассмотрим реальные примеры, которые очень часто используются. Очень часто интерфейсы используются как описательные модели, наследование от которых дает возможность работать с тем, для чего они созданы. Тем самым вы не привязываетесь к конкретным классам. В самом языке очень C# даже есть интерфейсы, которые реализуют то или иное поведение. Вы очень часто будете с этим сталкиваться, если перейдете на WPF или ASP.NET MVC приложения. Использование foreach с собственными классами Давайте улучшим наш зоопарк и добавим класс для хранения животных. Несмотря на то, что он довольно объемный, я просто взял с MSDN пример и просто подставил свои значения. public interface IWalk { void walk(); } public class Animals : IEnumerable{ private IWalk[] _pets; public Animals(IWalk[] pArray) { _pets = new IWalk[pArray.Length]; for (int i = 0; i < pArray.Length; i++) { _pets[i] = pArray[i]; } } IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)GetEnumerator(); } public PetsEnum GetEnumerator() { return new PetsEnum(_pets); } IEnumerator IEnumerable .GetEnumerator() { return (IEnumerator )GetEnumerator(); } } public class PetsEnum : IEnumerator { public IWalk[] _pets; int position = -1; public PetsEnum(IWalk[] list) { _pets = list; } public bool MoveNext() { position++; return (position < _pets.Length); } public void Reset() { position = -1; } object IEnumerator.Current { get { return Current; } } public IWalk Current { get { try { return _pets[position]; } catch (IndexOutOfRangeException) { throw new InvalidOperationException(); } } } } Теперь я могу делать так: class Program { static void Main(string[] args) { ZooLivecycle zoo = new ZooLivecycle(); Animals animals = new Animals(new IWalk[]{new Cat(), new Dog(), new Fish(), new Bird(), new HelperPet()}); Console.WriteLine("\n*Pet Walk*"); zoo.allPetWalk(animals); Console.Read(); } } class ZooLivecycle { public void allPetWalk(Animals animals) { foreach(IWalk animal in animals) animal.walk(); } } Не реализовав интерфейс, вы не сможете использовать с вашим классом foreach, хотя на самом деле это делается очень быстро. При этом метод foreach работает с любыми объектами, и не будь интерфейсов, достигнуть такого эффекта было бы сложнее. Теперь в класс Animals можно добавить такие методы, как Add, Remove, etc. Ну и в конце концов вы можете ставить заглушки и передавать тестовые данные. Если реализация классов достаточно сложна, например, один из них получает данные из базы, а другой обрабатывает эти данные, то вы можете написать ненастоящий класс. То есть вместо реальных данных Вы передаете класс, которые не использует подключение к БД, и потом его можно будет переписать. Причем можно работать нормально как с одним, так и с другим классом попеременно.
Комментариев нет:
Отправить комментарий