Нэш Трей - C# 2010. Ускоренный курс для профессионалов (2010) (1160865), страница 114
Текст из файла (страница 114)
Для примера реализуем звание сотрудника в виде отдельного класса по имени т111е. если следовать изложенному ранее руководству, т.е. всегда выполнять глубокое копирование для клона, то можно реализовать следующий метод клонирования: цв1пс Зуяеещ) // Класс т1Г1е // В поисках канонических форм СО 429 рпЬ11с яеа1ек) с1азя ТЬСЬе: 1С1опеаЫе ( рпЫЬс еппт ТЬС1енатеЕппт ( ЯгеепНсгп, Носяпокапгп ) рпЫЬс ТЬС1е( ТЬС1енатеЕппт СТГ1е ) ( ГЫя.с1С1е = ГЬГ1е; ЬосхпрРаузся1е(); ) ргЬтаке Т1Г1е( ТЬГ1е окпег ) ( СЫя.ГЬС1е = окпег.ГЬГ1е; Ьоокпррауяса1е О к ) У/ Реализация 1С1опеаЬ1е. рпЫЬс сЬбесс С1опе() ( гекпгп пен ТЬК1е(СЬ1з); ) ргкчасе чоас Ьоокцррауяса1е() /! Находит тарифную сетку в базе данных.
// Тарифная сетка определяется званием. рг1чаке Т1С1еМятеЕппт С1С1е; ргачаке «(опЬ1е тЬЬРау; ргЬчаке сопЬ1е тахРау; ) /У Класс Етр1оуее рпЫгс яеа1еп с1аяя Етр1оуее: 1С1опеаЬ1е ( рпЫЬс Етр1суее( япг1по пате, ТЬГ1е СЬС1е, якгапч яяп ) гпкя.пате = пате; ГЫя.с1С1е = Ггк1е; гЬЬя.яяп = яяпк ) рг1чаке Етр1оуее( Етр1оуее окпег ) ( СЫя.пате = Бкг1пд.сору( окпег.пате ); КЫя.ГЬГ1е = (ТЬС1е) сГЬег.ГЬС1е.С1опе () СЫя.яяп = БсгЬпО.Сору( оГЬег.зяп ); ) /! Реализация 1С1спеаЬ1е. рпЬ11с оЬЗеск С1опе() ( гекцгп пеы Етр1суее(ГЬЬя) ргЬчаке зкгЬпч пате; рг1чаке ТЬГ1е КЬС1е; ргЬчасе зкгЬпс яяп; Обратите внимание, что копировать объект тЬЬ1е с помощью метода метьегиЬяес1опе невозможно, потому что побочный эффект от конструктора состоит в вызове ьоокцррауБса1е на новом объекте для получения из базы данных тарифной сетки по званиям.
Предположим, что тарифная сетка может измениться между моментом создания прототипа и операцией клонирования, поэтому всегда нужно обращаться к базе данных. К тому жс заметьте, что копии содержащихся объектов выполняются с использованием соответствующих методов 1С1опеаЬ1е. Для объекта ТЬС1е просто вызывается 430 рлээя (3 его реализация с1 осе. Оказывается, что Бу я сев. Б с гу од реализует 1с1опеаЬ1е. Однако использовать метод С1опе для создания глубокой копии Евр1оуее нельзя. Если вы внимательно прочитаете описание реализации Яьг1пд.
С1оое, то увиднте, что она просто возвращает ссылку на самого себя. Это — блестящий пример проблем, о которых упоминалось, когда речь шла о несогласованности реализаций С1опе. Для получения настоящей копии исходной строки должен применяться статический метод я с гупд . сору. Тот факт, что Яуяьев. Бьг1пд возвращает ссылку на себя при вызове метода 1С1опеаЬ1е. С1опе, объясняется оптимизацией, предусмотренной разработчиками.
Несмотря на то что они удерживают от создания глубокого клона любого объекта, содержащего ссылни на строковые объекты, эта оптимизация корректна по двум причинам. Во-первых, в документации не уназано, какая копия должна быть реализована; глубокая или поверхностная. Об аргументах эа и против такого упущения в спецификации контракта уже говорилось ранее. Во-вторых, я уз Сев. Б Сг).пд — не изменяемый объент. Неизменяемость объекта — мощная концепция, о которой речь пойдет ниже, а разделе "Всегда отдавайте предпочтение безопасности типов".
Общая идея состоит в том, что, однажды созданный. строковый объект не может быть изменен на протяжении своего сутцествования. Поэтому реализация Яьгупд. С1опе, выполняющая глубокое копирование, нанесла бы ущерб эффективности. Клиенты Буяьев. Бьг).пд работают одинаково, независимо от того, выполняет Бсгупд. с1опе глубокое или поверхностное копирова- ниЕ, имЕнно по причиНЕ НЕиЗМЕНЯЕМОСти Объектов Яггуод. Стараясь сделать так, чтобы реализация 1С1ооеаЬ1е документировала сама себя, можно воспользоваться специальным атрибутом для пометки метода С1опе.
Таким образом, потребители объекта смогут определить во время проектирования или во время выполнения, какое нопирование поддерживается объектом: глубоное или поверхностное. Рассмотрим следующий пользовательский атрибут'. ияупд Буягев; павеярясе С1ооеНе1регя ( РиЬ11с еоив С1ооеясу1е ( оеер, БЬэ11ое ) (Ать 1ьисенязделгьг1ьисе(Агсг1ьисетягдеся.иесьоо)) риЬ11с яеа1ег( с1яяя с1опеясу1елссг1ьисе: Агьг1Ьисе ( риь11с С1ооеяьу1еАССг1Ьисе( С1ооеяьу1е с1ояеягу1е ) ( СЬуя.с1опеяьу1е = с1опеягу1е; ) риЬ11с С1опеяьу1е Яьу1е ( дес ( гесигл с1опеясу1е! ) ) рг1яяье С1ооезгу1е с1опеяьу1е; Полное раскрытие темы пользовательских атрибутов в .)ЧЕТ Ргагпежог)г выходит за рамки настоящей книги. Дополнительную информацию можно найти в документации МЗР)Ч или в книгах, посвященных СЬК, например, в книге Эндрю Троелсена Язык лрограммирояанил СЗ 2005 и плаляуюр иа .)УЕТ 3.5, е-е издание (ИД "Вильямс", 2010 г).
В поисках канонических форм СЗ 431 Атрибутом АссгбЬцсецзауелссгбьцсе можно пометить реализации клонов так, чтобы они сами несли в себе информацию о том, какой тип операции клонирования они поддерживают. Но имейте в виду, что данный атрибут — всего лишь маркер, который ни к чему не обязывает во время выполнения. Это не означает, что нельзя создать какой-то другой тип, который навязывает политику во время выполнения, основываясь на присоединенных пользовательских атрибутах.
Давайте вернемся к классу 01непвбопв и соответствующим образом применим этот атрибут: цвбпд Эувгеви цв1пс С1спене1регв; рцьубс вев1еб с1ввв Ь1тепв1опв: 1С1опеавуе рцвубс Ь1тэпв1опв( 1спо и1бсп, 1опс Ье1спс ) ( СЬ ьв . нббСЬ = н1бСПг СЬ1в.пес ЬС = Пеб ПС; у Я О Реализация 1С1опэвЬ1е. (С1опезпу1еАССг1Ьцпе(С1опезгу1е.реер)) рцЬ11с оЬ)есС С1опе() ( гесцгп Спбв.иеиЬегнбвеС1опе()г ) рг1чвсе 1опс нсбспг ргстасе 1опс Ье1дПСг ) Теперь вопросов о том. как реализован метод С1опе.
не возникает, и потребители этого объекта будут хорошо информированы. После сказанного выше вы наверняка согласитесь. что реализация такой на первый взгляд безобидной вещи, как 1С1опеаЬ1е, вовсе не проста. Внимание) Избегайте реализации интерфейса 1С1опеаЬ1е. Как бы опасно зто не звучало, но в М)сговой действительно выдвигают такую рекомендацию. Проблема происходит из того факта, что контракт не указывает, должна быть копия глубокой или поверхностной. Фактически, как описано в книге Кжиштова Цввлина (Кгзувг(о( Саайпа] и Брэда Абрамса (Вгаб АЬгагпв) Ргвгленогз Вез)дп Ои(бе)(лез: Сопуепйопз, (б(ол)в, апб Рауегпз 1ог ВеиззЫе .)уЕТ ЫЬгапев (Абб)воп-УУев)еу Рго(еввюпа), 2005 г.) ', авторы пересмотрели всю кодовую базу,(ЧЕТ Ггагпеэюгй и не нашли в ней код, работающий с 1С1опевЬ1е. Если бы проектировщики и разработчики .
(ЧЕТ Ргагпеаогй использовали этот интерфейс, то наверняка бы обнаружили недостатки в спецификации 1С1опеаЬ1е и устранили их. Однако эта рекомендация не направлена на то, чтобы препятствовать реализации метода с1опе, если он действительно необходим. Если классу нужен метод клонирования, можете реализовать его в общедоступном контракте класса, не реализуя интерфейса 1С1опеаь1е. Является ли ОЬ~ес~ одноразовым? Ранее уже описывались достоинства и недостатки одноразовых, нли освобождаемых (б)врозаЫе), объектов, но давайте поговорим об эффекте.
который они могут оказать на существующий дизайн. Сначала нужно определить, должен ли объект быть одноразовым. Обычно если объект управляет определенного рода неуправляемым ресурсом, таким как порция виртуальной памяти (или любым другим низкоуровневым ресурсом), то объект должен быть одноразовым. С другой стороны, если объект имеет финализатор, то скорее всего он также должен быть одноразовым. Если объект содержит другие объекты, которые сами являются одноразовыми, то такой объект также должен быть Планируется к выходу. Разработка инх)эраспгрукптуры проеютшроэаншс соглашения, идио- мы и шаблоны (ИД "Вильямс", 2010 г.).
432 Глава 13 одноразовым. Например, объект, хранящий ссылну на открытый файл с монопольным правом чтения/записи, должен быть одноразовым, чтобы клиент этого объекта мог управлять закрытием и очисткой лежащего в основе ресурса. Объенг объявляется одноразовым, если он реализует интерфейс 1 Р1 вро в аь1е.
интерфейс 1 Р1 вров аЬ1е — еще один из упрощенно выглядяппж интерфейсов, подобных 1 С1о сев Ь1е, который таит в себе массу нюансов и проблем. Ниже приведено его объявление: рпЫЯс 1пгегсасе 1разрозвЬ1е ( то1г) Р1зрове()г ) Выглядит достаточно просто. Необходимо лишь реализовать метод Раврове, чтобы он очищал ресурс, и готово, верноу Да, возможно. При создании одноразового объекта, содержащего в себе другие одноразовые обьекты, в реализации Р). ерове должны вызываться методы Р). яро ее содержащихся объектов.
К тому же вполне допускается многократный вызов Р1вроее клиентами. Поэтому вместо генерации исключения при последующих вызовах, что неправильно, согласно документации по 101вроввЬ1е, ничего не нужно делать. Чтобы нод не дал сбой, если Ра ар о ве будет вызван много раз. понадобится поддерживать какой-то внутренний флаг. Этот внутренний флаг может быть использован и для других целей.
Обычно этот метод не допускается вызывать на уже освобожденном объекте. В таких случаях можно проверить флаг, и если его значение говорит о том, что объект уже освобожден ранее, то сгенерировать исключение СЬ3 есСР1врозег(ЕхсерС1оп. Как видите, требования реализации 1РЯзроввЫе являются возрастающими, и то, что казалось простым интерфейсом, в реализации становится все более и более сложным. рассмотрим пример реализации 101врозвЫе. На заметку( Этот пример не демонстрирует правильные приемы управления неуправляемыми ресурсами. Он предназначен для иллюстрации обсуждения интерфейса 1Р1вровэь1в. Чтобы понять почему, обратитесь к разделам "Ограниченные области выполнения" и "Критичные финализаторы и яагенапг(1е" главы 7.










