Принцип, описывает 3 правила:
Предусловия (Preconditions) не могут быть усилены в подклассе. Другими словами подклассы не должны создавать больше предусловий, чем это определено в базовом классе, для выполнения некоторого поведения
Постусловия (Postconditions) не могут быть ослаблены в подклассе. То есть подклассы должны выполнять все постусловия, которые определены в базовом классе.
Инварианты (Invariants) — все условия базового класса - также должны быть сохранены и в подклассе
Вроде, все логично, но не понимаю, что в таком случае вооще можно делать при наследовании, что бы не нарушить данный принцип...
Например, вот пример с метанита: Усиление предусловия:
class Account
{
public int Capital { get; protected set; }
public virtual void SetCapital(int money)
{
if (money < 0)
throw new Exception("Нельзя положить на счет меньше 0");
this.Capital = money;
}
}
class MicroAccount : Account
{
public override void SetCapital(int money)
{
if (money < 0)
throw new Exception("Нельзя положить на счет меньше 0");
if (money > 100)
throw new Exception("Нельзя положить на счет больше 100");
this.Capital = money;
}
}
Ослабление постусловия:
class Account
{
public virtual decimal GetInterest(decimal sum, int month, int rate)
{
// предусловие
if (sum < 0 || month >12 || month <1 || rate <0)
throw new Exception("Некорректные данные");
decimal result = sum;
for (int i = 0; i < month; i++)
result += result * rate / 100;
// постусловие
if (sum >= 1000)
result += 100; // добавляем бонус
return result;
}
}
class MicroAccount : Account
{
public override decimal GetInterest(decimal sum, int month, int rate)
{
if (sum < 0 || month > 12 || month < 1 || rate < 0)
throw new Exception("Некорректные данные");
decimal result = sum;
for (int i = 0; i < month; i++)
result += result * rate /100;
return result;
}
}
Что-то не понимаю, а что если в наследних мне действительно нужно изменить некоторое поведение?
Или вот есть интерфейс и 10-ок классов реализует этот интерфейс => они могут реализовать различное поведение, так как первоначальной реализации нет.
Этот принцип уже обсужден много раз (например, раз, два, три)
В общем случае он звучит как
Функции, которые используют ссылки на базовые классы, должны иметь возможность использовать объекты производных классов, не зная об этом
Каким образом этого можно добиться?
Допустим, у вас есть интерфейс. И у этого интерфейса есть описание (образно говоря, контракт, то есть описание, что должны делать члены этого интерфейса), например вот IList, возьмем его метод Add
Добавляет элемент в коллекцию IList.
Параметры value Object Объект, добавляемый в коллекцию IList.
Возвращаемое значение Int32 Позиция, в которую вставлен новый элемент, или значение -1, если элемент не вставлен в коллекцию.
Здесь явно прописано поведение реализации. Таким образом, не важно, какую вы используете реализацию списка, метод должен принимать объект и возвращать индекс.
Как можно сломать предусловие? Очень просто
public int Add (object value)
{
if (!(value is MyClass)) throw new ArgumentException();
.....
}
В интерфейсе явно не прописано, что можно добавлять каие то особенные элементы, потому, клиенты этого интерфейса очень удивятся, если в этот необобщенный список можно будет добавлять не все объекты, что захочется.
Как сломать постусловие? Очень просто
public int Add (object value)
{
.....
// вставка в коллекцию
return -1;
}
В интерфейсе четко указано, что при успешной вставке в коллекцию, метод должен вернуть корректный индекс. Если мы нарушаем это правило - мы нарушаем контракт интерфйса.
Таким образом принцип подстановки Лисков говорит вам - вы можете реализовать как вы хотите ваши классы, но контракт интерфейса или базового класса вы должны сохранить. В таком случае, если существует уже написанный код, который оперирует с IList согласно контракту интерфейса, то вы можете подсунуть ему любую реализацию IList и код должен продолжать успешно работать.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Хочу сформировать модель таким образом что б при возвращение на клиент я обращался через точку и свойство а не через номер в массивеПример
Постепенно начал изучать IoC и всю эту кухню и вот не как не могу понять, как работать с ними в WPF приложение по правилам MVVM
Окно WPF запускается с WindowState="Maximized"Если сразу после запуска посмотреть Left или Top окна то они будут равны -8