Создать экземпляр в классе или получить объект извне, что на true?

Я изучил принцип SOLID и создал для меня вопрос об этом. Вы полагаете, что нам нужен Tea Объект в Mug класс, теперь это лучше, чем создать экземпляр из Tea в Mug класс или пройти снаружи через Constructor или же setter метод.

что это правда?

пример:

class Mug {

    private Tea tea;

    public Mug(){
       this.tea = new Tea();
    }

    public boolean isFull(){
       return this.tea.value != 10;
    }
}

или же

class Mug {

    private Tea tea;

    public Mug(Tea tea){
       this.tea = tea;
    }

   // public void setTea(Tea tea){
   //    this.tea = tea;
   // }

    public boolean isFull(){
       return this.team.value != 10;
    }
}

использовать:

  public class Test {

   static void main(String[] args){
       Mug mug = new Mug();
       //or
       Mug mug = new Mug(new Tea());
  }
}

какой из них лучше?

ПРИМЕЧАНИЕ. Предположим, что Mug только поддержка Tea объект в нашей программе.

2 ответа

Оба ваших дела нарушают SOLID.

Каждая конкретная реализация (конкретный класс) должна зависеть только от абстракций. в твоем случае чай это не абстракция. Кружка имеет крепкую связь с чаем. Ниже приведен возможный способ его кодирования.

public interface ITea{
     //tea related methods which you think should be exposed to outside world. Also all implementation of ITea must support these method (L in SOLID)
 }

public class Tea implements ITea{
  // Implement the contract methods from ITea
}

public class Mug {
    private ITea tea;
    // Have constructor or setter to inject concrete implementation. Setter will provide you capability to modify behavioral at run time.
 }

РЕДАКТИРОВАТЬ: 1. Если мы уверены, что есть только одна возможная реализация чая. Кроме того, интерфейс также лучше, так как конкретные реализации трудно подделать и, следовательно, затрудняет модульное тестирование.

  1. Избегайте использования перечислений для установки типа. Перечисляет случаи внедрения переключателя и в будущем, если добавляется случай, необходимо изменить все такие случаи переключения, что приведет к нарушению O в SOLID.

Если кейс добавлен, вы должны изменить существующий код, а если вы забудете добавить кейс где-либо, это приведет к неожиданным ошибкам. (Это нарушает OCP. Вместо перечислений ставить логику в конкретную реализацию, иметь общий интерфейс и конкретную реализацию). Также, если мы реализуем логику для конкретного случая в отдельных экземплярах enum, тогда файл enum станет гигантским. Вместо этого, если у нас есть конкретная логика в отдельных конкретных классах, реализация общего интерфейса упрощает пользовательский код, так как он может быть внедрен в конкретные классы полиморфным способом.

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

Я бы использовал второй, где это возможно, вставляя зависимости классов, возьмите этот пример, где Tea Конструктор требует больше информации:

class Mug {

    private Tea tea;

    public Mug(int temperature) {
        this.tea = new Tea(temperature);
    }

    public boolean isFull() {
        return tea.value != 10;
    }
}

Посмотрите, как это уродливо Mugдля конструктора теперь нужна информация, используемая только Teaконструктор.

Но я бы сказал, что ни один из ваших примеров не нарушает принцип SOLID.

Ничто не говорит о том, что вы не можете создать новый объект внутри другого, и ничего, что говорит о том, что вы должны создавать абстракции.

Здесь было бы реальным нарушением в этой области:

class Mug { // VIOLATION

    private Tea tea;
    private Coffee coffee;

    public Mug(boolean tea) {
        if (tea) {
            this.tea = new Tea();
        } else {
            this.coffee = new Coffee();
        }
    }

    public boolean isFull() {
        return tea.value != 10 || coffee.value != 10;
    }
}

Класс зависит от нескольких похожих классов. Сравнить с:

class Mug {

    private Liquid liquid;

    public Mug(Liquid liquid) {
        this.liquid = liquid;
    }

    public boolean isFull() {
        return liquid.getVolume() != 10;
    }
}

interface Liquid {
    int getVolume();
}

class Tea implements Liquid {

    private int volume;

    @Override
    public int getVolume() {
        return volume;
    }
}

class Coffee implements Liquid {

    private int volume;

    @Override
    public int getVolume() {
        return volume;
    }
}

Но так как у вас есть только одна вещь, которая может пойти в Mug нет нарушения и нет необходимости в абстракции. В общем, никогда не пишите код, который не решает проблему.

И никогда не создавайте абстракцию с таким именем, как ITea, В таком случае либо конкретное имя класса недостаточно конкретное, либо имя абстракции недостаточно общее.

Другие вопросы по тегам