С точки зрения дизайна ОО, могут ли двумерные и трехточечные классы быть выведены из одного базового класса? - PullRequest
0 голосов
/ 27 июня 2009

В настоящее время я разрабатываю дизайн для простого графического редактора, который поддерживает тривиальные операции для двумерных и трехмерных фигур.
Дело в том, что я хочу сделать прототип этих фигур, как это делает MsPaint. И на данный момент это рендеринг, мне нужно где-то хранить пиксели от холста, которые покрываются прототипом, на тот случай, когда прототип меняется, чтобы восстановить свое состояние на холсте. Итак, я хочу, чтобы все мои фигуры поддерживали этот тип буферизации (Графическая операция является базовым классом для всех операций рендеринга):

public abstract class Shape: GraphicOperation {
        protected List<SomePoint> backup;
        public Shape(Color c): base(c) { }

        public Color FigureColor {
            get { return color; }
            protected set { color = value; }
        }
        public abstract void renderPrototype(Bitmap canvasToDrawOn);
}


Основная идея заключается в том, что с точки зрения проектирования ОО было бы здорово обеспечить поддержку буфера на уровне базового класса (Shape), я имею в виду, что для классов TwoDShape и ThreeDShape этот список должен быть инициализирован по-разному - для TwoDShape с экземплярами TwoDPoint и для ThreeDShape с экземплярами ThreeDPoint.
Но для этого SomePoint должен быть базовым классом как для двумерных, так и для трехмерных классов точек. Допустимо ли с точки зрения ОО выводить оба этих класса из одного базового класса?
Возможно, здесь слишком много слов, но я просто хотел, чтобы проблема была понятна всем.
Edit : кстати, это хорошая идея, чтобы получить точечные классы от их короля форм? Лично я не вижу других вариантов, но, может быть, будет лучше, если я выведу это непосредственно из формы? Теперь это:

public abstract class TwoDShape : Shape {
        protected List<SomePoint> backup;
        public TwoDShape(Color c) : base(c) { }
    }
public class TwoDPoint: TwoDShape {
        //...
}

и то же самое для ThreeDPoint.

Ответы [ 7 ]

2 голосов
/ 27 июня 2009

Я не могу придумать способа, который бы не нарушал принцип подстановки Лискова каким-то тонким (или не очень тонким) способом. Это классический пример того, почему не сойти с ума с наследованием, просто потому, что два класса совместно используют некоторые поля, например, здесь или здесь .

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

2 голосов
/ 27 июня 2009

Что общего между 2d и 3d точками? Если это просто «при рисовании их на поверхности они заменяют пиксели, которые должны быть зарезервированы», это звучит скорее как композиция, чем как наследство для меня. Обе фигуры 2d и 3d имеют буфер пикселей, которые они смещают.

В любом случае, можете ли вы всегда использовать как 2D, так и 3D-фигуры, когда ожидается базовый класс?

Если так, дайте им общий базовый класс. Иначе нет.

Основывайте свой дизайн класса на том, как используются объекты. Если они используются в контексте, где они имеют общую базу, реализуйте ее как общий базовый класс. Если это просто вопрос «Я не могу быть обеспокоен добавлением элемента данных к обоим», наследование, вероятно, не правильный инструмент.

2 голосов
/ 27 июня 2009

Не вижу причин не делать этого. Но если единственное различие между Shapes заключается в типе точек, которые они содержат, почему бы не сделать сам класс Shape шаблоном или «универсальным» на языке Java?

1 голос
/ 27 июня 2009

Существует совершенно общее правило OOD, которое гласит: Состав предпочтения по наследованию.

На практике это означает, что вы не должны использовать наследование для повторного использования кода. Все еще допустимо и допустимо использовать наследование, если мотивация для этого заключается в использовании полиморфизма.

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

Если, с другой стороны, вы обнаружите, что вам нужно уменьшить экземпляры до, скажем, TwoDPoint или ThreeDPoint, то вы ничего не получите от наследования и нарушите принцип подстановки Лискова. Если это так, вы должны рассмотреть проект, в котором вы можете реализовать повторное использование, не прибегая к наследованию - возможно, с использованием Сервиса или Стратегии.

0 голосов
/ 12 февраля 2010

Более простое решение, позволяющее избежать некоторых тонких проблем проектирования, состоит в том, чтобы просто рассматривать все точки как 3D и просто игнорировать координату Z, если вы работаете в 2D-контексте. Вы можете рассматривать 2D-фигуру как просто 3D-фигуру, лежащую на плоской плоскости.

0 голосов
/ 27 июня 2009

Не могли бы вы заставить ThreeDimensionalPoint получать себя из TwoDimensionalPoint?

public class ThreeDimensionalPoint : TwoDimensionalPoint
{

}

Я мог видеть многократно используемый код (методы / свойства) в 2D, который будет таким же в 3D ... И вы можете посмотреть на 3D с точки зрения 2D, и тогда все, что вам нужно сделать, это брось это. Только мои мысли ...

0 голосов
/ 27 июня 2009

В играх 2-й пункт и 3-й пункт типично не наследуются друг от друга, но, честно говоря, я не могу придумать какой-либо фундаментальной причины для этого. Так что да, все должно быть в порядке, так как для именования это обычно vector2 и vector3, поэтому они могут содержать измерения, точки и цвета в одном объекте.

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