Является ли хорошей идеей разделить каждую графическую форму на две части - ее геометрию и компоненты рендеринга? - PullRequest
0 голосов
/ 27 мая 2009

Я пишу простой графический редактор для университетского проекта с использованием C #.
Я создал иерархию, в которой каждый тип фигуры - круги, прямоугольники, эллипсы, ... - наследуются от базового класса Shape, он содержит цвет фигуры в качестве защищенного поля.


public abstract class Shape {
        protected Color color;

        public Shape(Color c) {
            color = c;
        }

        public Color FigureColor {
            get { return color; }
            protected set { color = value; }
        }

        public abstract void render(Bitmap canvasToDrawOn);

        public abstract void unrender(Bitmap canvasToDrawOn);

        public abstract void renderPrototype(Bitmap canvasToDrawOn);
    }

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


public class TwoDPoint: TwoDShape {
        Point2DGeometry point;

        public TwoDPoint(Color c, Point2DGeometry p): base(c) {
            point = new Point2DGeometry(p);
        }

public struct Point2DGeometry {
        Int32 x;
        Int32 y;

        public Point2DGeometry(Int32 X, Int32 Y) {
            x = X;
            y = Y;
        }

        public Point2DGeometry(Point2DGeometry rhs) {
            x = rhs.Abscissa;
            y = rhs.Ordinate;
        }

        public Int32 Abscissa {
            get { return x; }
            private set { x = value; }
        }

        public Int32 Ordinate {
            get { return y; }
            private set { y = value; }
        }
    }

Класс Ellipse будет инкапсулировать EllipseGeometry и т. Д.
Является ли это хорошим решением с точки зрения проектирования ОО, и, если это так, может быть, лучше создать параллельную иерархию типов только для геометрии?

Ответы [ 2 ]

1 голос
/ 27 мая 2009

Я думаю, что ответ - да, потому что он следует по дорожке, проложенной почитаемой моделью MVC.

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

0 голосов
/ 27 мая 2009

Я бы сказал, что это зависит. Собираетесь ли вы повторно использовать ваши геометрические объекты вне ваших фигурных объектов или делиться геометрическими объектами как Flyweights? Если нет, возможно, вы излишне усложняете иерархию классов.

Просматривая свой код, вы также можете рассмотреть следующее:

  1. Наличие какого-то соглашения об именах между вашими частными полями и вашими общедоступными свойствами. Нет смысла увлекаться Abscissa / Ordinate, когда ваши личные переменные имеют значение x / y, а ваш конструктор использует X / Y. Ditto Color и FigureColor in Shape.

  2. Зачем в Shape защищать «цвет», если у «FigureColor» также есть защищенный установщик? В большинстве API (и вы можете думать о своем абстрактном классе как о API для его производных классов) вы захотите свести к минимуму путаницу, которую члены используют при изменении состояния. В этом конкретном примере я бы, скорее всего, сделал «цвет» закрытым.

  3. Следите за "внутренними классами" в вашей иерархии классов, которые не добавляют никакого значения. Например, у вас есть абстрактный класс Shape, и, судя по всему, TwoDShape. В чем разница между двумя? У вас есть поддержка 3-х измерений? Ваше наследственное дерево больше похоже на палку?

HTH, и удачи в вашем проекте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...