Создать экземпляр в классе или получить объект извне, что на 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. Если мы уверены, что есть только одна возможная реализация чая. Кроме того, интерфейс также лучше, так как конкретные реализации трудно подделать и, следовательно, затрудняет модульное тестирование.
- Избегайте использования перечислений для установки типа. Перечисляет случаи внедрения переключателя и в будущем, если добавляется случай, необходимо изменить все такие случаи переключения, что приведет к нарушению 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
, В таком случае либо конкретное имя класса недостаточно конкретное, либо имя абстракции недостаточно общее.