Вложенная структура классов
От: wolf_larsen  
Дата: 31.10.11 11:48
Оценка:
Здравствуйте!

Есть задача — реализовать на c# вложенную структуру классов, типа:

Дом(Дом_1).Квартира(Квартира_1).Комната(Комната_1).Дверь.Открыть();

Все достижения, которые накопал в данном направлении заключаются в следующем:

    public class Объект
    {
        public string Название;
        public List<Помещение> Помещения;
        public Объект(string Название)
        {
            this.Название=Название;
            Помещение Помещение_1= new Помещение("Помещение_1");
            Помещения.Add (Помещение_1);
        }

    }

    public class Помещение
        {
        public string Название;
        public List<Окно>    Окна;
        public Помещение(string Название)
        {
            this.Название=Название;
            Окно Окно_1= new Окно("Помещение_1");
            Окна.Add (Окно_1);
        }
    }

    public class Окно
    {
        public string Название;
        public Окно(string Название)
        {
            this.Название=Название;
        }
    }


Таким образом я могу обращаться к элементам класса через поиск:


Проект ТекущийПроект = new Проект("Проект_1");
string Название = ТекущийПроект.Помещения.Find("Помещение").Окна.Find("Окно");


Как мне доработать код, чтобы я мог обращаться к ним, как в примере сверху? Хватит хотя бы названия технологии.
Re: Вложенная структура классов
От: Alex Lakers  
Дата: 31.10.11 11:55
Оценка:
_>Как мне доработать код, чтобы я мог обращаться к ним, как в примере сверху? Хватит хотя бы названия технологии.

Попробуйте поискать по "Fluent Builder".
Re: Вложенная структура классов
От: QrystaL Украина  
Дата: 31.10.11 11:57
Оценка: +1
Здравствуйте, wolf_larsen, Вы писали:

  Скрытый текст
_>Здравствуйте!

_>Есть задача — реализовать на c# вложенную структуру классов, типа:


_>Дом(Дом_1).Квартира(Квартира_1).Комната(Комната_1).Дверь.Открыть();


_>Все достижения, которые накопал в данном направлении заключаются в следующем:


_>
_>    public class Объект
_>    {
_>        public string Название;
_>        public List<Помещение> Помещения;
_>        public Объект(string Название)
_>        {
_>            this.Название=Название;
_>            Помещение Помещение_1= new Помещение("Помещение_1");
_>            Помещения.Add (Помещение_1);
_>        }

_>    }

_>    public class Помещение
_>        {
_>        public string Название;
_>        public List<Окно>    Окна;
_>        public Помещение(string Название)
_>        {
_>            this.Название=Название;
_>            Окно Окно_1= new Окно("Помещение_1");
_>            Окна.Add (Окно_1);
_>        }
_>    }

_>    public class Окно
_>    {
_>        public string Название;
_>        public Окно(string Название)
_>        {
_>            this.Название=Название;
_>        }
_>    }
_>


_>Таким образом я могу обращаться к элементам класса через поиск:


  Скрытый текст
_>
_>Проект ТекущийПроект = new Проект("Проект_1");
_>string Название = ТекущийПроект.Помещения.Find("Помещение").Окна.Find("Окно");
_>

_>Как мне доработать код, чтобы я мог обращаться к ним, как в примере сверху? Хватит хотя бы названия технологии.


    public class Помещение
    {
        public string Название;
        public Dictionary<String, Окно> Окна = new Dictionary<String, Окно>();
        public Помещение(string Название)
        {
            this.Название=Название;
            Окно Окно_1= new Окно("Окно_1");
            Окна.Add("Окно_1", Окно_1);
        }
    }

string Название = ТекущийПроект.Помещения["Помещение_1"].Окна["Окно_1"].Название;


Стараемся не оверквотить или хотябы под спойлер прятать. H_D.
Re: Вложенная структура классов
От: rumatavz  
Дата: 31.10.11 12:15
Оценка:
Дом(Дом_1).Квартира(Квартира_1).Комната(Комната_1).Дверь.Открыть();


Мб вы имели ввиду

Дом("Дом_1").Квартира("Квартира_1").Комната("Комната_1").Дверь.Открыть();


Если это модифицировать вот так то ответ очевиден, т.к. содержится в вопросе

Корень.Дом("Дом_1").Квартира("Квартира_1").Комната("Комната_1").Дверь.Открыть();


Класс корень имеет статический метод Дом, принимающий строку и возвращающий квартиру итд, только методы становятся не статические.
Re[2]: Вложенная структура классов
От: wolf_larsen  
Дата: 31.10.11 13:20
Оценка:
Здравствуйте, rumatavz, Вы писали:

R>
R>Дом(Дом_1).Квартира(Квартира_1).Комната(Комната_1).Дверь.Открыть();
R>


R>Мб вы имели ввиду


R>
R>Дом("Дом_1").Квартира("Квартира_1").Комната("Комната_1").Дверь.Открыть();
R>


R>Если это модифицировать вот так то ответ очевиден, т.к. содержится в вопросе


R>
R>Корень.Дом("Дом_1").Квартира("Квартира_1").Комната("Комната_1").Дверь.Открыть();
R>


R>Класс корень имеет статический метод Дом, принимающий строку и возвращающий квартиру итд, только методы становятся не статические.


А разве статический класс может иметь не статические методы? А даже если и может, то не буду же я создавать для каждого случая свой метод, нужны какие-то элементы типа List
Re[2]: Вложенная структура классов
От: wolf_larsen  
Дата: 31.10.11 13:22
Оценка:
Здравствуйте, Alex Lakers, Вы писали:

_>>Как мне доработать код, чтобы я мог обращаться к ним, как в примере сверху? Хватит хотя бы названия технологии.


AL>Попробуйте поискать по "Fluent Builder".


Это не оно, таким я не могу создавать вложенные структуры.
Re: Вложенная структура классов
От: enCobalt  
Дата: 31.10.11 13:35
Оценка:
Здравствуйте, wolf_larsen, Вы писали:

_>Дом(Дом_1).Квартира(Квартира_1).Комната(Комната_1).Дверь.Открыть();

...
_> public List<Помещение> Помещения;


Просто используй Dictionary вместо List и будет тебе счастье!
Только обращаться будешь типа
Дом["дом1"].Квартира["квартира12"].Дверь[...]

А чем тебе база с foreign keys не угодила? Дальше то детали и поля начнут пухнуть
и в запросах умумукаешься с LINQ вместо SQL.
Хочу инвайт на хабру :)
Re: Вложенная структура классов
От: MazurD  
Дата: 31.10.11 18:03
Оценка:
Здравствуйте, wolf_larsen, Вы писали:

_>Здравствуйте!


_>Есть задача — реализовать на c# вложенную структуру классов, типа:


_>Дом(Дом_1).Квартира(Квартира_1).Комната(Комната_1).Дверь.Открыть();


здесь видимо подразумевается что
Дом — абстракция
Дом_1 — конкретная реализация ...
Re: Вложенная структура классов
От: Doc Россия http://andrey.moveax.ru
Дата: 01.11.11 02:41
Оценка:
Здравствуйте, wolf_larsen, Вы писали:

Может такое подойдет (на примере 2 классов, но суть должны понять):

    class Door
    {
        public string Title { get; set; }
    }

    class Room
    {
        public string Title { get; set; }
                
        public Door this[string index]
        {
            get { return this._doors.Find(r => string.Equals(r.Title, index)); }
        }

        private readonly List<Door> _doors = new List<Door>();
    }

    class House
    {
        public string Title { get; set; }

        public Room this[string index]
        {
            get { return this._rooms.Find(r => string.Equals(r.Title, index)); }
        }

        private readonly List<Room> _rooms = new List<Room>();
    }


тогда

var house = new House();
var door = house["my_room"]["my_door"];


Правда необходимо учитывать вероятность появления NullReferenceException при неправильных именах.

Кроме того, что-то мне подсказывает что надо смотреть на задачу шире. И вам тут может пригодиться шаблон Компоновщик (Composite).
Re[2]: Вложенная структура классов
От: wolf_larsen  
Дата: 01.11.11 10:11
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>Здравствуйте, wolf_larsen, Вы писали:

  Скрытый текст
Doc>Может такое подойдет (на примере 2 классов, но суть должны понять):

Doc>
Doc>    class Door
Doc>    {
Doc>        public string Title { get; set; }
Doc>    }

Doc>    class Room
Doc>    {
Doc>        public string Title { get; set; }
                
Doc>        public Door this[string index]
Doc>        {
Doc>            get { return this._doors.Find(r => string.Equals(r.Title, index)); }
Doc>        }

Doc>        private readonly List<Door> _doors = new List<Door>();
Doc>    }

Doc>    class House
Doc>    {
Doc>        public string Title { get; set; }

Doc>        public Room this[string index]
Doc>        {
Doc>            get { return this._rooms.Find(r => string.Equals(r.Title, index)); }
Doc>        }

Doc>        private readonly List<Room> _rooms = new List<Room>();
Doc>    }
Doc>


Doc>тогда


Doc>
Doc>var house = new House();
Doc>var door = house["my_room"]["my_door"];
Doc>


Doc>Правда необходимо учитывать вероятность появления NullReferenceException при неправильных именах.


Doc>Кроме того, что-то мне подсказывает что надо смотреть на задачу шире. И вам тут может пригодиться шаблон Компоновщик (Composite).


Данные конструкции в целом отражают суть того, что надо, однако есть следующая проблема: У всех вложенных классов будут одни и теже методы в intellysence. Как я могу сделать так, чтобы при погружении в структуру мне на выбор давались те элементы, которые касаются не только данного уровня, но и данной конкретной сущности?
Re[3]: Вложенная структура классов
От: HowardLovekraft  
Дата: 01.11.11 10:36
Оценка:
Здравствуйте, wolf_larsen, Вы писали:

_>Как я могу сделать так, чтобы при погружении в структуру мне на выбор давались те элементы, которые касаются не только данного уровня, но и данной конкретной сущности?

Где и как вы собираетесь это использовать?
Re[3]: Вложенная структура классов
От: Doc Россия http://andrey.moveax.ru
Дата: 01.11.11 12:07
Оценка:
Здравствуйте, wolf_larsen, Вы писали:

_>Данные конструкции в целом отражают суть того, что надо, однако есть следующая проблема: У всех вложенных классов будут одни и теже методы в intellysence.


В этом и суть Компоновщика. Однотипная работа с различными элементами. Итоговый элемент можно уже привести (при крайней необходимости) к определенному типу.

_>Как я могу сделать так, чтобы при погружении в структуру мне на выбор давались те элементы, которые касаются не только данного уровня, но и данной конкретной сущности?


Например приведением типов.

Но опять же, надо шире смотреть на задачу. Я все это к тому, что возможно ваша исходная версия структуры (в первом сообщении) не является оптимальной. Исходить тут надо от абстракий и того, что чего они нужны.
Re[3]: Вложенная структура классов
От: samius Япония http://sams-tricks.blogspot.com
Дата: 01.11.11 19:00
Оценка:
Здравствуйте, wolf_larsen, Вы писали:

_>Здравствуйте, Doc, Вы писали:


_>Данные конструкции в целом отражают суть того, что надо, однако есть следующая проблема: У всех вложенных классов будут одни и теже методы в intellysence. Как я могу сделать так, чтобы при погружении в структуру мне на выбор давались те элементы, которые касаются не только данного уровня, но и данной конкретной сущности?


В стартовом посте все у вас было нормально для этого. По различным именам вы обращались к различным типизированным коллекциям вложенных сущностей (не классов). Единственное чего не хватало — метода Find(string).

Можно объявить свои коллекции, например так:
public class СписокПомещений : List<Помещение>
{
    public Помещение Find(string name) { return this.Where(x => x.Название == name).FirstOrDefault(); };
}

И далее использовать эти коллекции вместо List<Помещение> и т.п.

Проблему дублирования описаний вспомогательных коллекций можно решить с помощью выделения поля Название в базовый класс

class NamedItem { public string Название; }

public class NamedItemList<TNamedItem> : List<TNamedItem>
     where TNamedItem : NamedItem 
{
    public TNamedItem Find(string name) { return this.Where(x => x.Название == name).FirstOrDefault(); };
}

или передав способ извлечения имени в конструктор соответствующего списка:
public class ItemList<TItem> : List<TItem>
{
    public ItemList(Func<TItem, string> getNameFunc) { _getNameFunc = getNameFunc; }
    private Func<TItem, string> _getNameFunc;
    public TNamedItem Find(string name) { return this.Where(x => _getNameFunc(x) == name).FirstOrDefault(); };
}


Но как уже упомянул Doc, использование такой конструкции будет сопряжено с риском NullReferenceException. Можно и с этим побороться.

static class MyExtensions
{
    public static Помещение Помещение(this Проект obj, string name)
    {
        if (obj == null)
            return null;
        return obj.Помещения.Where(x => x.Название == name).FirstOrDefault();
    }
}

тогда

Проект ТекущийПроект = new Проект("Проект_1");
Окно окно = ТекущийПроект.Помещение("Помещение").Окно("Окно");
if (окно != null)
   окно.Open();

На любом этапе может появиться null, но он не страшен вплоть до вызова метода Open у окна. Но и с этим можно что-то сделать:
static class MyExtensions
{
    ...
    public static void DoIfNotNull<T>(this T obj, Action<T> action)
    {
        if (obj != null) 
            action(obj);
    }
}
Проект ТекущийПроект = new Проект("Проект_1");
ТекущийПроект.Помещение("Помещение").Окно("Окно").DoIfNotNull(x => x.Open());

Но с этим путем появляется другая проблема. После выполнения выражения нельзя быть уверенным что окно было найдено и метод Open вызвался. Так что вопросы, о том как это будет использовано, не праздные.
Re[4]: Вложенная структура классов
От: wolf_larsen  
Дата: 02.11.11 05:31
Оценка:
Здравствуйте, samius, Вы писали:

S>Здравствуйте, wolf_larsen, Вы писали:


_>>Здравствуйте, Doc, Вы писали:


_>>Данные конструкции в целом отражают суть того, что надо, однако есть следующая проблема: У всех вложенных классов будут одни и теже методы в intellysence. Как я могу сделать так, чтобы при погружении в структуру мне на выбор давались те элементы, которые касаются не только данного уровня, но и данной конкретной сущности?


S>В стартовом посте все у вас было нормально для этого. По различным именам вы обращались к различным типизированным коллекциям вложенных сущностей (не классов). Единственное чего не хватало — метода Find(string).


S>Можно объявить свои коллекции, например так:

S>
S>public class СписокПомещений : List<Помещение>
S>{
S>    public Помещение Find(string name) { return this.Where(x => x.Название == name).FirstOrDefault(); };
S>}
S>

S>И далее использовать эти коллекции вместо List<Помещение> и т.п.

S>Проблему дублирования описаний вспомогательных коллекций можно решить с помощью выделения поля Название в базовый класс


S>
S>class NamedItem { public string Название; }

S>public class NamedItemList<TNamedItem> : List<TNamedItem>
S>     where TNamedItem : NamedItem 
S>{
S>    public TNamedItem Find(string name) { return this.Where(x => x.Название == name).FirstOrDefault(); };
S>}
S>

S>или передав способ извлечения имени в конструктор соответствующего списка:
S>
S>public class ItemList<TItem> : List<TItem>
S>{
S>    public ItemList(Func<TItem, string> getNameFunc) { _getNameFunc = getNameFunc; }
S>    private Func<TItem, string> _getNameFunc;
S>    public TNamedItem Find(string name) { return this.Where(x => _getNameFunc(x) == name).FirstOrDefault(); };
S>}
S>


S>Но как уже упомянул Doc, использование такой конструкции будет сопряжено с риском NullReferenceException. Можно и с этим побороться.


S>
S>static class MyExtensions
S>{
S>    public static Помещение Помещение(this Проект obj, string name)
S>    {
S>        if (obj == null)
S>            return null;
S>        return obj.Помещения.Where(x => x.Название == name).FirstOrDefault();
S>    }
S>}
S>

S>тогда

S>
S>Проект ТекущийПроект = new Проект("Проект_1");
S>Окно окно = ТекущийПроект.Помещение("Помещение").Окно("Окно");
S>if (окно != null)
S>   окно.Open();
S>

S>На любом этапе может появиться null, но он не страшен вплоть до вызова метода Open у окна. Но и с этим можно что-то сделать:
S>
S>static class MyExtensions
S>{
S>    ...
S>    public static void DoIfNotNull<T>(this T obj, Action<T> action)
S>    {
S>        if (obj != null) 
S>            action(obj);
S>    }
S>}
S>Проект ТекущийПроект = new Проект("Проект_1");
S>ТекущийПроект.Помещение("Помещение").Окно("Окно").DoIfNotNull(x => x.Open());
S>

S>Но с этим путем появляется другая проблема. После выполнения выражения нельзя быть уверенным что окно было найдено и метод Open вызвался. Так что вопросы, о том как это будет использовано, не праздные.

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

Изначально я вообще хотел использовать чисто статические класса объектов, но т.к. помещений может быть очень много, то это будет очень геморно поддерживать.
Re[5]: Вложенная структура классов
От: HowardLovekraft  
Дата: 02.11.11 06:04
Оценка:
Здравствуйте, wolf_larsen, Вы писали:

_>Смоделированы трехмерные помещения. Идея следующая: создать объектную модель помещения, чтобы к любому элементу помещения можно было бы обратиться способом "от общего к частному" и получить на выходе методы присущие только данному устройству — дверь(методы — открыть, закрыть), шкаф(методы — цвет, типдерева), лампа(методы — включить, получитьяркость).


Либо использовать уже предложенный подход:
building.Appartments["A1"].Rooms["Bathroom"].Doors["Main"].Open();

либо, если очень хочется статики в compile-time, берете вашу модель, T4 и генерируете по модели с помощью T4 классы, отражающие специфику каждого конкретного объекта:
building.A1.Bathroom.MainDoor.Open();


В первом случае нет статической проверки на этапе компиляции, и вы узнаете о том, что в помещении нет такой комнаты в рантайме. Но при этом изменение исходной модели вам пофиг.
Во втором случае статическая проверка есть, но при изменении модели вам необходимо повторно сгенерировать код классов.
Re[5]: Вложенная структура классов
От: samius Япония http://sams-tricks.blogspot.com
Дата: 02.11.11 06:21
Оценка:
Здравствуйте, wolf_larsen, Вы писали:

_>Здравствуйте, samius, Вы писали:


_>Смоделированы трехмерные помещения. Идея следующая: создать объектную модель помещения, чтобы к любому элементу помещения можно было бы обратиться способом "от общего к частному" и получить на выходе методы присущие только данному устройству — дверь(методы — открыть, закрыть), шкаф(методы — цвет, типдерева), лампа(методы — включить, получитьяркость).

_>Суть идеи — удобное логическое обращение с разнородными объектами принадлежащими помещению.
Удобное для кого? Кто будет имена предметов вводить? Пользователь? Программист?

_>Изначально я вообще хотел использовать чисто статические класса объектов, но т.к. помещений может быть очень много, то это будет очень геморно поддерживать.


З.Ы. Оверквотинг не приветствуется.
Re[5]: Вложенная структура классов
От: Doc Россия http://andrey.moveax.ru
Дата: 02.11.11 07:00
Оценка:
Здравствуйте, wolf_larsen, Вы писали:

_>Смоделированы трехмерные помещения. Идея следующая: создать объектную модель помещения, чтобы к любому элементу помещения можно было бы обратиться способом "от общего к частному"


Повторюсь — берите Компоновщик.

_>и получить на выходе методы присущие только данному устройству — дверь(методы — открыть, закрыть), шкаф(методы — цвет, типдерева), лампа(методы — включить, получитьяркость).


В определенный момент приводить к заданному типу. Т.е. все объекты получат общий интерфейс для работы с ними (перебор, поиск, добавление, удаление и т.д.), но при необходимости можно обратиться и как конкретному типу.
Re[6]: Вложенная структура классов
От: wolf_larsen  
Дата: 02.11.11 08:51
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>Повторюсь — берите Компоновщик.


_>>и получить на выходе методы присущие только данному устройству — дверь(методы — открыть, закрыть), шкаф(методы — цвет, типдерева), лампа(методы — включить, получитьяркость).


Doc>В определенный момент приводить к заданному типу. Т.е. все объекты получат общий интерфейс для работы с ними (перебор, поиск, добавление, удаление и т.д.), но при необходимости можно обратиться и как конкретному типу.


Поискал примеры компоновщика — да, действительно он позволяет создать виртуальную структуру, однако я не нашел примера, как мне обратиться к конкретному члену данной структуры и получить его конкретные методы. Все что описано — как добавить элемент в структуру и как удалить.
Re[7]: Вложенная структура классов
От: Doc Россия http://andrey.moveax.ru
Дата: 02.11.11 18:29
Оценка:
Здравствуйте, wolf_larsen, Вы писали:

_>Поискал примеры компоновщика — да, действительно он позволяет создать виртуальную структуру, однако я не нашел примера,


Выше я давал ссылку на пример реализации данного шаблона.

_>как мне обратиться к конкретному члену данной структуры


Там есть поиск.

_>и получить его конкретные методы.


Приводите тип.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.