Паттерн Composite
От: SomewhereSomehow Россия  
Дата: 30.09.10 12:52
Оценка:
Здравствуйте все!
Есть небольшой вопрос по паттерну Composite
Казалось бы тривиальная задача, но что-то туплю.

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

Немного путанно звучит, наверное понятнее будут по коду.

    // абстрактрные классы фигур
    public abstract class ShapeBase
    {
        // размеры, ширина высота
        public virtual int Width { get; set; } 
        public virtual int Height { get; set; } 
        // простой конструктор
        public ShapeBase(){Width = 10;Height = 20;}
    }
    public abstract class ShapeCompositeBase: ShapeBase
    {
        // размер композитной фигуры, сумма соотв.размеров дочерних
        public override int Width { get { return Shapes.Sum(new Func<ShapeBase, int>(SumW)); }  }
        public override int Height { get{ return Shapes.Sum(new Func<ShapeBase, int>(SumH)); } }
        private int SumW(ShapeBase sb) {return sb.Width;}
        private int SumH(ShapeBase sb) {return sb.Height;}
        //дочерние фигуры
        public virtual List<ShapeBase> Shapes { get; set; } 
        public ShapeCompositeBase()
        {
            Shapes = new List<ShapeBase>();
        }
    }
    // производные класы
    // представляет конкретную простую фигуру
    public class SimpleShape : ShapeBase { public int SpecProperty { get; set; } }//свойство производного класса 
    // представляет конкретную сложную фигуру состоящую из конкретных простых
    public class CompositeShape : ShapeCompositeBase{}

    public static class MyTester
    {
        public static void Test()
        {
            SimpleShape ss = new SimpleShape();
            CompositeShape cs = new CompositeShape();
            cs.Shapes.Add(ss);
            cs.Shapes.Add(ss);
            
            // вот тут хотелось бы иметь коллекцию типа List<SimpleShape> а не List<ShapeBase>
            // чтобы не разыменовывать, а обращаться напрямую ведь cs.Shapes лежат объекты SimpleShape
            // а не ShapeBase. Хотя конечно я нигде это не указывал, потмоу как если попытаться в CompositeShape
            // добавить public override List<SimpleShape> Shapes { get; set; } - будет ошибка:
            // "CompositeShape.Shapes': type must be 'System.Collections.Generic.List<ShapeBase>' to match overridden member 'ShapeCompositeBase.Shapes'"
            ((SimpleShape) cs.Shapes[0]).SpecProperty = 1;
            // вместе с тем нужно сохранить возможность передавать объекты коллекции на обработку как ShapeBase
            ShowSizes(cs.Shapes[0]);
            ShowSizes(cs);
            /* 
             * соответственно вопрос
             * как можно в производном классе сложной фигуры, хранить коллекцию конкретных простых фигур,
             * пока нашел только способ с промежуточным классом-коллекцией, которая инкапсулирует преобразование 
             * из ShapeBase в SimpleShape, а само свойство в CompositeShape скрывается следующим образом:

             * SimpleShapeCollection shapes = new SimpleShapeCollection(base.Shapes);
             * public new SimpleShapeCollection Shapes { get{ return shapes; } }

             * Но это похоже на какие-то костыли, наверняка есть способ поизящнее аткое организоать..
             */
        }
        public static void ShowSizes(ShapeBase sb)
        {
            //some code to show Width,Height
        }
    }
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.