
- •Программа курса
- •Ооп. Основные понятия
- •Конструкторы, деструкторы и др. Работа с объектами в .Net
- •Ссылочные типы и Типы значения. Передача параметров в .Net
- •Принципы ооп
- •Инкапсуляция
- •Наследование
- •Полиморфизм
- •Важные классы (типы данных)
- •Обобщенные контейнеры
- •Статические методы и свойства
- •Обработка исключений
- •Интерфейсы и слабая связь между классами
- •Рефлексия и создание объектов из внешних модулей по имени класса
Интерфейсы и слабая связь между классами
Что бы разрабатываемые модули были гибкими и, тем самым, расширилась область их применения, они не должны явно использовать внешние специфические классы и сами не должны показывать (предоставлять) слишком частных классов в своем интерфейсе. Если это случится, то модуль сможет работать только с этими специальными классами и сможет быть использован только пользователями тех специальных классов, которые показывает наш модуль.
Но как при этом сохранить принцип типизации данных, который означает, что все переменные должны иметь определенный тип? Для решения это проблемы можно использовать интерфейсы.
Объявление интерфейсов схоже с объявлением классов (см. фрагмент 12)
interface ISample
{
void Method1 ();
string Method2 ();
…
}
Фрагмент 12. Объявление интерфейса. У интерфейса нет полей и свойств. Методам нельзя менять область видимости. Методы не могут иметь реализации.
Все методы интерфейса по определению публичные и изменить это никак нельзя.
Классы могут не только наследовать от других классов, но и реализовывать интерфейсы. Подробно свойства и использование интерфейсов можно найти по ссылке http://msdn.microsoft.com/ru-ru/library/ms173156.aspx.
Модули, которые используют интерфейсы, а не явные типы данных (классы) называются слабо связанными, так как вместо одного класса, всегда можно использовать другой класс, реализующий тот же интерфейс.
Рефлексия и создание объектов из внешних модулей по имени класса
Все приведенные выше рассуждения окажутся бесполезными, если не реализован механизм, который позволят подменять реализацию классов для уже собранных модулей. И такой механизм в .Net есть – это Reflection.
Допустим, нам нужно использовать класс с именем, которое будет задано во время исполнения программы, а класс реализован в модуле, имя которого так же станет известно только во время исполнения программы, например, из конфигурационного файла. Известно так же, что класс объекта реализует некоторый прикладной интерфейс, например, IRule, заранее известный нашей программе.
Тогда код, использующий Reflection будет выглядеть примерно так:
Assembly a = Assembly.LoadFile(assemblyName);
Type classType = a.GetType(className);
IRule rule = (IRule)Activator.CreateInstance(classType);
В первой строке загружается модуль из файла (а имя файла прочитано в конфигурационном файле). В результате мы получаем объект класса Assembly - a.У этого объекта мы получаем тип (описание класса) с именем className, которое так же взято из конфигурационного файла. Наконец, при помощи системного класса Activator мы создаем объект данного типа и приводим его к нашему интерфейсу IRule. Теперь по ссылке rule можно обращаться ко всем методам, имеющимся у интерфейса IRule.
Более подробно узнать об Assembly, Type и Activator можно по ссылкам:
http://msdn.microsoft.com/ru-ru/library/system.reflection.assembly.aspx
http://msdn.microsoft.com/ru-ru/library/system.type.aspx
http://msdn.microsoft.com/ru-ru/library/system.activator.aspx
Давайте подведем итог. Благодаря тому, что мы написали код, который опирается на использование интерфейса (IRule), а не явного класса и реализации Reflection в .Net, мы смогли использовать объекты, классы которых были неизвестны на момент разработки и компиляции программы. Более того, в процессе эксплуатации программы, изменяя конфигурационные файлы, мы можем и заменить реализацию интерфейса на другую безо всякой переделки нашей программы.
В этом и проявляется слабая связь между нашим модулем и используемыми им сторонними классами.
Упражнения для подготовки к экзамену
Подготовьте пример обработки строк, используя методы указанные в ссылках.
Зачем используется StringBuilder?
В чем разница между DateTime и TimeSpan?
Каковы свойства каждого из упомянутых выше контейнеров? Какова скорость выборки данных и добавления новых данных в каждый из контейнеров?
Каким целям обработка исключительных ситуаций на основе try-catch-finally?
Что такое и зачем нужны статические свойства и методы?
Что такое ‘слабая связь’ между классами? Как она достигается?
Что дает слабая связь?