Модераторы: Partizan, gambit

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> незадача с интерфейсами и типами 
:(
    Опции темы
Alek86
Дата 4.9.2007, 14:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 2
Всего: 25



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

в связи с этим у меня 2 проблемы.

1)
Если мне нужен  класс, в котором есть переменная состояния и функция, изменяющая это состояние, я делаю вот так:
(попрошу не придираться к коду, ибо пишу для примера, может есть ошибки) smile

Код

class Widget {
    public enum EType {Type1, Type2};
    public SetType(EType vType) {
        m_Type = vType;
    }
    EType m_Type
}


если для этого класса нужен интерфейс, то тип этот и функцию в интерфейсе я сделать не могу.

Это первая проблема.

2)
Вторая похожа на первую, только я не могу объявлять в интерфейсе делегаты для того, чтобы класс, унаследованный от интерфейса мог посылать сообщения тем, кто знает только об интерфейсе :(


Застрял я на этом, когда стал читать известную книжку "Design Patterns". На С++ я смог "реализовать" некоторые из паттернов, а на шарпе, благодаря этому ограничению, не могу.

Может, кто знает, как быть?



--------------------
user posted image    user posted image
PM MAIL   Вверх
mihryak
Дата 4.9.2007, 14:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 19
Всего: 36



теперь, похоже, понял оба вопроса
Код

    public interface IStateable
    {
        void SetState(Stateable.State newState);
        event Stateable.StateChangedHandler Event;
    }

    public class Stateable : IStateable
    {
        public delegate void StateChangedHandler(State state);

        public enum State
        {
            StateA,
            StateB
        }

        private State state;

        #region IStateable Members

        public void SetState(State newState)
        {
            state = newState;

            if (Event != null)
            {
                Event(state);
            }
        }

        public event StateChangedHandler Event;

        #endregion
    }

и делегат, и энум можно вынести из класса

Это сообщение отредактировал(а) mihryak - 4.9.2007, 14:20
PM MAIL ICQ   Вверх
FREEDEV
Дата 4.9.2007, 14:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 238
Регистрация: 6.3.2007
Где: Украина->Одесс а

Репутация: 1
Всего: 3



mihryak,  так же делал, но все равно, кажется, что это как-то не корректно
--------------------
Microsoft Windows Visla ©
PM MAIL   Вверх
SpaceSpace
Дата 4.9.2007, 14:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 366
Регистрация: 10.4.2007
Где: Самара

Репутация: 2
Всего: 10



1. 
для класса  интерфейс
Код

    class Widget : IWidget {
    public enum EType {Type1, Type2};
    public void SetType(EType vType) {
        m_Type = vType;
    }

    interface IWidget
    {
        void SetType(Widget.EType vType);
    }

если тебе нужны поля - используй базовые классы

2.
делегаты можно использовать  из базовых классов

Это сообщение отредактировал(а) SpaceSpace - 4.9.2007, 14:24


--------------------
Репутация - самое ценное, что есть у человека. Зарабатывают годы, теряют за мгновение.
70-565
MCPD Enterprise 3.5 
PM MAIL   Вверх
mihryak
Дата 4.9.2007, 14:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 19
Всего: 36



Цитата(FREEDEV @  4.9.2007,  15:21 Найти цитируемый пост)
mihryak,  так же делал, но все равно, кажется, что это как-то не корректно 

чем же? не пойму...
PM MAIL ICQ   Вверх
FREEDEV
Дата 4.9.2007, 14:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 238
Регистрация: 6.3.2007
Где: Украина->Одесс а

Репутация: 1
Всего: 3



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

Это сообщение отредактировал(а) FREEDEV - 4.9.2007, 14:50
--------------------
Microsoft Windows Visla ©
PM MAIL   Вверх
mihryak
Дата 4.9.2007, 14:55 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 19
Всего: 36



ну вообще крайне редко интерфейсы ограничиваются базовыми типами данных, так что, так или иначе, они будут навязывать классам много особенностей и требований.
а внесённые в сам класс enum и delegate мне тоже не очень нравятся (причём в большей степени внешне, а не из-за нарушения концепции), но их можно безболезненно вынести из класса
PM MAIL ICQ   Вверх
Alek86
Дата 4.9.2007, 15:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 2
Всего: 25



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

Наверно запутанно высказался.

допустим тип:

Код


interface IPoint {
    SetCoord(int x, int y);
    Draw(ICanvas vCanvas);
}



можно реализовать как с помощью класса

Код

 class LinuxPoint : IPoint {
    void SetCoord(int x, int y) { m_x = x; m_y = y;};
    void Draw(ICanvas vCanvas) {/* рисуется по-линуховому */}
    int m_x;
    int m_y;
}


так и с помощью класса:

Код

 class WindowsPoint : IPoint {
    void SetCoord(int x, int y) { m_x = x; m_y = y;};
    void Draw(ICanvas vCanvas) {/* рисуется по-виндозному */}
    int m_x;
    int m_y;
}



как с помощью метода, который предложил mihryak в тип IPoint можно было бы добавить  "виды" прорисовки точки (звездочкой его рисовать, или квадратом или еще как-то)
Код

enum EView {Star, Square, Circle};

??

опять же, пример надуманный smile

Это сообщение отредактировал(а) Alek86 - 4.9.2007, 15:11


--------------------
user posted image    user posted image
PM MAIL   Вверх
mihryak
Дата 4.9.2007, 15:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 19
Всего: 36



ну так объяви в интерфейсе
вместо
Код

void SetState(Stateable.State newState);

Код

void SetDrawStyle(EView style);

а в методе Draw кейси по стилю рисования

пс. решение такая же хрень, как и пример smile
PM MAIL ICQ   Вверх
Alek86
Дата 4.9.2007, 15:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 2
Всего: 25



ну, получается очень плохо, ибо "вид" точки не инкапсулирован в саму точку и является совершенно отдельным типом, хотя нужен только там.

если подобных объектов будет много (прямоугольники, круги) и у каждого свои "виды", то   нужно будет и EView переименовывать в EPointView, и, потом. будет банальное засорение глобального пространства имен.

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


тогда последний в теме вопрос (может, кто знает)

Для чего разработчики языка сделали невозможным объявление типов в интерфейсах? Чем это плохо?

Это сообщение отредактировал(а) Alek86 - 4.9.2007, 15:50


--------------------
user posted image    user posted image
PM MAIL   Вверх
mihryak
Дата 4.9.2007, 15:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 19
Всего: 36



что-то какое-то месево smile

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

interface IPoint
{
    SetCoord(int x, int y);
    Draw(ICanvas vCanvas);
}

Если посчиташь возможным/нужным реализуй SetCoord, а Draw оставь абстракным
потом объяви наследника от этого абстрактного класса, например SquarePoint, метод Draw которого и будет рисовать квадратную точку
при использовании в списках тебе достаточно будет знать, что это - просто какая-то штуковина, реализующая интерфейс, а как она себя будет рисовать - не имеет значения, ей виднее
Таким образом, перечисление тут вообще не нужно

и на последний вопрос - а нафига объявлять типы в интерфейсах?
PM MAIL ICQ   Вверх
Alek86
Дата 4.9.2007, 18:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 2
Всего: 25



эх...

mihryak, рекомендую почитать Design Patterns, так подробно рассмотрены подобные проблемы и их нормальные решения

ни в коем случае не хочу сказать, что твое решение плохое, но в нем, имхо, ты не учитываешь всех условий (к примеру, что методы Draw будут различаться не только для разных "видов", но и для разных систем (винда, линух)), а также возможность расширения.
и, как говорилось там же, 
Цитата("Design Patterns")

наследование нарушает инкапсуляцию 


а на
Цитата(mihryak @  4.9.2007,  15:54 Найти цитируемый пост)
и на последний вопрос - а нафига объявлять типы в интерфейсах?

я, кажется, ответил, что иначе
Цитата(Alek86 @  4.9.2007,  15:43 Найти цитируемый пост)
 будет банальное засорение глобального пространства имен.






--------------------
user posted image    user posted image
PM MAIL   Вверх
mihryak
Дата 4.9.2007, 19:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 19
Всего: 36



сдаюсь и жду "хорошое решение" smile
пс #1. с паттернами знаком, использую при целесообразности
пс #2. даже если бы в интерфейсах можно было бы объявлять классы, они всё равно лежали бы в том же пространстве имён, что и сам интерфейс (при этом являясь общедоступными), чем не "засорение"?
пс #3. не так давно спорили тут с SpaceSpace о делегатах, обсуждая подобное надуманное решение, пришли к выводу, что каков вопрос - такой и ответ. для более адекватно представленной проблемы, скорее всего, нашлось бы и более адекватное решение, делать выводы о неудобной декларации интерфейсов .Net, исходя из невозможности рисовать звёздообразные точки в линуксе, право слово, не стоит

Это сообщение отредактировал(а) mihryak - 5.9.2007, 10:08
PM MAIL ICQ   Вверх
Alek86
Дата 4.9.2007, 22:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 2
Всего: 25



ответ на ПС №2
они бы лежали в самом интерфейсе, и чтоб обратиться к их названиям, нужно было бы приписать к ним спереди название интерфейса с точкой, и не выдумывать уникальные для неймспейса имена.

Цитата(mihryak @  4.9.2007,  19:42 Найти цитируемый пост)
рисовать звёздообразные точки в линуксе

красиво сказано smile пример и правда не совсем по паттернам, хотя лично я считаю предложенное решение "некрасивым" с точки зрения проектирования.

Приведу пример из жизни

есть интерфейс, некоторые функции которого могут возвращать не false в случае ошибки, а саму ошибку (нужно заметить, что коды ошибок, равно как и их значения нужны только при использовании этого интерфейса и его всех возможных реализаций)

ошибки, как я считаю, нужно кодировать через enum. Функции должны возвращать код ошибки (т.е. элемент enum'а).

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

как нужно это делать на шарпе?

ЗЫ.
Вопрос
Цитата(Alek86 @  4.9.2007,  15:43 Найти цитируемый пост)
Для чего разработчики языка сделали невозможным объявление типов в интерфейсах? Чем это плохо?

подразумевал: "зачем эту возможность убрали (по сравнению с С++), а не почему не добавили?"


Это сообщение отредактировал(а) Alek86 - 4.9.2007, 22:56


--------------------
user posted image    user posted image
PM MAIL   Вверх
SpaceSpace
Дата 5.9.2007, 07:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 366
Регистрация: 10.4.2007
Где: Самара

Репутация: 2
Всего: 10



Цитата

рекомендую почитать Design Patterns, так подробно рассмотрены подобные проблемы и их нормальные решения

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


--------------------
Репутация - самое ценное, что есть у человека. Зарабатывают годы, теряют за мгновение.
70-565
MCPD Enterprise 3.5 
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.0621 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.