Я нарушил принцип LSP в этом примере? - PullRequest
0 голосов
/ 26 апреля 2018

У меня есть этот код, который реализует 2 типа дверей.Одна дверь содержит замок, а другая - нет.

Интерфейс Дверь не представляет никакой сложности:

public interface Door {
    void open();
    void close();
}

Тогда у меня есть реализации: LockedDoor и RegularDoor

public class LockedDoor implements Door {
    private Lock lock;
    private boolean isOpen;

    @Override
    public void open() {
        if(!lock.isLocked()) {
            this.isOpen = true;
        }
    }

    @Override
    public void close() {
        this.isOpen = false;
    }
}

public class RegularDoor implements Door {
    private boolean isOpen;

    @Override
    public void open() {
        isOpen = true;
    }

    @Override
    public void close() {
        isOpen = false;
    }
}

Как видите, функция открытия LockedDoor откроет дверь, только если замок разблокирован.
Вы можетеразблокировать блокировку, получив ее от LockedDoor и вызвав функцию разблокировки.

Является ли это нарушением принципа подстановки Лискова?
Если это так, что будет хорошей альтернативой?

Ответы [ 2 ]

0 голосов
/ 26 апреля 2018

Нет , вы (вероятно) не нарушаете LSP.

Более длинный ответ: Конечно, зависит от вашего "определения" метода open() в интерфейсе Door.Если вы определяете метод как " пытается открыть дверь, если возможно ", то вы находитесь в открытом доступе.

Можно утверждать, что метод open() должен называться tryOpen()прояснить свое намерение для вызывающего абонента, что дверь может быть не открыта после вызова.

Однако если вы определите метод open() для всегда , откройте дверь, то, конечно, вынарушение вашего контракта (и LSP) в LockedDoor.

Другая проблема заключается в том, что в интерфейсе чего-то не хватает.На данный момент эффект не имеет никакого состояния открытия / закрытия ни для одного из доступных методов open() / close().Я предполагаю, что у вас есть какой-то другой метод в Door, для которого уместно состояние двери, например walkThrough() или что-то подобное.

0 голосов
/ 26 апреля 2018

Сложно ответить на этот вопрос, поскольку ваш интерфейс для Door кажется неполным в том смысле, что неясно, что должны делать open() и close().Давайте разберемся с этим, добавив метод isOpen() и определив, что после вызова open() последующий вызов isOpen() должен вернуть true (и я намеренно игнорирую вопрос о том, что произойдет, если вы попытаетесьдля краткости откройте и уже откройте дверь).

В этом случае вы определенно нарушаете принцип LSP - если вы попытаетесь открыть запертую дверь, вы потерпите неудачу, и дверь останетсязакрыто.

Один из способов решения этой проблемы - добавить возвращаемое значение в методы open() и close(), чтобы они могли сообщать, была ли операция выполнена успешно:

public interface Door {
    /**
     * Checks if the door is open.
     * @return {@code true} if the door is open, {@code false} if not.
    boolean isOpen();

    /**
     * Attempt to open the door.
     * @return {@code true} if the door was successfully opened, 
     * {@code false} if not.
     * In other words, if a call to {@code open} returns {@code true}, a
     * subsequent call to {@link #isOpen} will return {@code true}.
     */
    boolean open();

    /**
     * Attempt to close the door.
     * @return {@code true} if the door was successfully closed, 
     * {@code false} if not.
     * In other words, if a call to {@code close} returns {@code true}, a
     * subsequent call to {@link #isOpen} will return {@code false}.
     */
    void close();
}

public class RegularDoor implements Door {
    private boolean isOpen;

    @Override
    public boolean isOpen() {
        return isOpen;
    }

    @Override
    public boolean open() {
        return isOpen = true;
    }

    @Override
    public boolean close() {
        return isOpen = false;
    }
}


public class LockedDoor implements Door {
    private Lock lock;
    private boolean isOpen;

    @Override
    public boolean isOpen() {
        return isOpen;
    }

    @Override
    public boolean open() {
        if (!lock.isLocked()) {
            return isOpen = true;
        }
        return false;
    }

    @Override
    public boolean close() {
        return isOpen = false;
    }

    // Not shown here - methods to lock and unlock the door
}
...