2016-08-18 8 views
1

Я нашел много подобных сообщений о смежных вопросах, этот ответ taylonr пришел близко, но не совсем ответил на мой сценарий.Как я могу создать это лучше, используя принципы OO и SOLID?

Предположим, у меня есть интерфейс:

public interface IShape 
{ 
    decimal GetArea(); 
} 

Я затем создать 3-х классов с помощью этого интерфейса

public class Rectangle : IShape 
{ 
    public decimal GetArea() 
    { 
     ... 
    } 
} 

public class Triangle : IShape 
{ 
    public decimal GetArea() 
    { 
     ... 
    } 
} 

public class Circle : IShape 
{ 
    public decimal GetArea() 
    { 
     ... 
    } 
} 

теперь я хочу добавить int GetNumberOfSides() функцию (или какой-либо другой функции, которая имеет отношение только к некоторые из моих IShape). Очевидно, это не относится к классу Circle. Если бы у меня тогда были объекты List<IShape> и вы захотели выполнить итерацию по вызову этой функции в соответствующих IShapes, как бы вы использовали объектно-ориентированные принципы проектирования для решения этой проблемы?

Я мог бы добавить логическое значение для моего интерфейса IShape bool HasSides { get; set; } и запустить любую логику этого, однако мне нужно было бы передать конкретный класс, чтобы получить доступ к функции GetNumberOfSides(). Я знаю, что это неправильно, поскольку это не так, но я не знаю, как это сделать.

Я думал о наличии другого интерфейса ISidedShape, который унаследовал от IShape, но затем вернулся к повторению моего списка, как бы я узнал, какая из фигур имеет этот конкретный метод?

Любая помощь будет высоко оценена.

Благодаря

+2

Не может ли 'Circle' просто« возвращать 0; »для количества сторон? Как насчет других нечетных фигур, таких как полукруг? Это будет законно иметь 1 «сторону», а также 1 «нечто иное, чем сторона, в зависимости от того, как вы определяете сторону». Может быть, «сторона» - это не тот термин, который вы ищете? С более подходящим названием для термина, моделирование может иметь больше смысла. – David

+0

Мой пример, возможно, не был лучшим. Я пытался найти пример, не используя мой фактический сценарий, который потребует других знаний. Я получаю вашу мысль о возврате 0, но это тоже не так. – user1244893

+2

Почему он не чувствует себя хорошо? Это совершенно логично. – jrahhali

ответ

1

Если вы хотите идти по пути ООП, вы можете добавить интерфейс, так как вы можете реализовать столько, сколько вам нравится в большинстве языков:

public interface IPolygon 
{ 
    int GetNumberOfSides(); 
} 

public class Rectangle : IShape, IPolygon 
{ 
    public decimal GetArea() { return 0; } 
    public int GetNumberOfSides() { return 4; } 
} 

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

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

+0

Спасибо, Джош. Когда вы перебираете «Список », вы бы тогда использовали «is IPolygon», чтобы определить, следует ли его перевести на «IPolygon»? – user1244893

0

Если вы уже имея List<IShape> в некоторых местах в вашем коде (так вы полагаетесь на IShape полиморфизм), я бы сказал, что лучшим решением является добавление GetNumberOfSides() в IShape и реализовать его как

public class Circle : IShape 
{ 
    public decimal GetNumberOfSides() 
    { 
     return 0; 
    } 
} 

If вы все еще находитесь в фазе «дизайна», и на самом деле у вас нет кода, который использует List<IShape>, вы можете реализовать второй интерфейс IPolygon (точно так же, как @Josh ответ).

Подходит ли одно из двух этих решений (в зависимости от того, как в настоящее время используется IShape) и «подход ООП». Я не могу сказать, какой из них лучше, потому что вы не показали нам свой настоящий код (и было бы нецелесообразно принимать такое решение на основе примера формы).

Однако, единственный подход, который я бы отговорить является добавление hasSides метод в IShape, потому что ваш код будет в скором времени будет завален много if каждый раз, когда вы будете перебирать на List<IShape> и, следовательно, будет кошмар для тестирования и поддержки. Поэтому, пожалуйста, пусть полиморфизм обрабатывает ветвление вместо ручного разветвления с if по адресу boolean.

+0

Разве вы не заменили бы 'if hasSides' на' if xxx is IPolygon' при переходе через ваш 'List '? – user1244893

+0

@ user1244893 Если вы планируете свою систему заранее с помощью «IPolygon», приемлемым вариантом может быть «Список ». Тем не менее, у вас будет два списка для поддержки сейчас вместо одного. Поэтому первый подход (добавление 'GetNumberOfSides' к' IShape') кажется наиболее удобным для меня. – Spotted

0

Он подпадает под принцип LSP и IS. Если вы добавите метод getSides() в интерфейс IShape, это нарушит LSP, когда этот интерфейс будет реализован Кругом, поскольку он не имеет сторон. Итак, вы хотите создать новый интерфейс IPolygon, как упоминание в одном из сообщений, чтобы оно соответствовало как Is, так и LSP.