Парадигма "программа для интерфейсов, а не реализаций" против паттерна компоновщика - PullRequest
0 голосов
/ 24 мая 2018

Мне нравится шаблон компоновщика (пример https://stackoverflow.com/a/1953567) по разным причинам, например, из-за того, что я могу работать с неизменяемыми объектами и что я могу контролировать создание объектов так, как нельзя создавать недопустимые объекты.

Однако я стараюсь следовать парадигме «программа для интерфейсов, а не для реализаций» (пример https://stackoverflow.com/a/2697810).

. Я понял, что эти два руководства не очень хорошо сочетаются друг с другом.

Если у меня есть интерфейс Person, класс PersonImpl и сборщик PersonImplBuilder, который создает PersonImpl. Теперь я могу заверить, что каждый экземпляр PersonImpl является действительным и неизменным. Но каждое возвращаемое значение и особенно каждыйПараметр метода в моем API использует интерфейс. Поэтому я не могу зависеть от действительного объекта.

Я что-то упустил, соответственно, есть ли другой способ объединить эти два очень полезных руководства?

РЕДАКТИРОВАТЬ

Некоторый код для пояснения. В этом примере построитель бесполезен с точки зрения обеспечения достоверности и / или неизменности объекта в моей точке доступаЯ. only гарантирует, что любой объект PersonImpl является действительным (и, кстати, это работает только потому, что PersonImpl не объявлено как final ).Но я не могу контролировать, использует ли клиент мой безопасно сконструированный объект PersonImpl или любую другую реализацию интерфейса Person.

public interface Person {
    LocalDate getBirthday();
}
public final class PersonImpl implements Person {
    private final LocalDate birthday;

    private PersonImpl(PersonImplBuilder builder) {
        this.birthday = builder.birthday;
    }

    @Override
    public LocalDate getBirthday() {
        return birthday;
    }
}
public class PersonImplBuilder {
    private LocalDate birthday;

    public LocalDate getBirthday() {
        return birthday;
    }

    public void setBirthday(LocalDate birthday) {
        this.birthday = birthday;
    }

    public PersonImpl build() {
        if(birthday.isAfter(LocalDate.now().minusYears(21).minusDays(1))) {
            throw new IllegalStateException("Person must be 21 years or above");
        }
        return new PersonImpl(this);
    }
}
// this is my API
public interface PersonService { 
    void doSomeAdultStuff(Person person);
}
public class PersonServiceImpl implements PersonService {
    //...
}
public void maliciousMethod() {
    PersonService service = new PersonServiceImpl();
    service.doSomeAdultStuff(new Person() {
        @Override
        public LocalDate getBirthday() {
            return LocalDate.now();
        }
    });
}

Ответы [ 2 ]

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

Сочетание концепции «программа-интерфейс» и шаблона Builder не должно иметь проблем.Причина в следующем коде:

service.doSomeAdultStuff(new Person() {
    @Override
    public LocalDate getBirthday() {
        return LocalDate.now();
    }
});

Вы написали новый класс, который не имеет имени и реализует интерфейс Person (анонимный класс).Этот класс отличается от класса PersonImpl вашего кода.В вашем случае просто удалите реализацию анонимного класса и используйте вместо нее новый PersonImpl (строитель).

service.doSomeAdultStuff(new PersonImpl(builder));
0 голосов
/ 25 мая 2018

Вы не используете конструктор где-либо в вашем коде.Если вы не хотите, чтобы ваш код использовал разные реализации класса Person, а только ваш PersonImpl, тогда не используйте интерфейс, а конкретную реализацию.Таким образом, вы будете уверены, что у вас есть только объекты, построенные так, как вы хотите.

Вы должны учитывать, что человек может быть младше 21 года и при этом оставаться «действительным» человеком (например, ребенком).У вас могут быть взрослый сборщик и дочерний сборщик (разные реализации), но вам все равно нужно будет проверить, правильно ли вы получили реализацию.Поэтому, возможно, вам следует проверить в службе, если человек имеет правильный возраст, а не во время строительства объекта.В противном случае его следует называть Взрослым, а не Человеком;)

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