在 class 中创建实例或从外部获取对象,哪个是正确的?
Create instance in class or get object from outside, which on is true?
我研究了 SOLID 原理并为我创建了一个关于它的问题。
你假设我们在 Mug
class 中需要一个 Tea
对象,现在这比在 Mug
class 中从 Tea
创建一个实例更好还是通过 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
对象。
你的两个案例都违反了 SOLID。
你的每个具体实现(具体 class)应该只依赖于抽象。
在你的情况下,茶不是抽象的。 Mug 与 Tea 紧密耦合。下面是一种可能的编码方式。
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.如果我们确定茶只有一种可能的实现。然后接口也更好,因为具体的实现很难模拟,因此很难进行单元测试。
- 避免使用枚举来设置类型。枚举注入 switch case 并且在未来如果添加了一个 case,所有这些 switch case 都需要修改,导致违反 SOLID 中的 O。
如果添加案例,您必须修改现有代码,如果您忘记在某处添加案例,则会导致意外错误。 (它违反了OCP。而不是枚举将逻辑放在具体实现中,具有通用接口和具体实现)。此外,如果我们在枚举的各个实例中实现案例特定逻辑,那么枚举文件将变得巨大。相反,如果我们在实现公共接口的具体 classes 中有特定的逻辑,那么用户代码就会变得简单,因为它可以以多态方式注入具体 classes。
p.s。这个答案是关于遵循原则的,并不总是可以这样做。违反原则是可以的,但我们必须知道我们正在违反原则,并且有充分的理由这样做。
我会尽可能使用第二个,注入 classes 依赖项,以这个例子为例,其中 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 依赖于多个相似的 class。比较:
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
这样的名字创建抽象。在这种情况下,具体 class 名称不够具体,或者抽象名称不够通用。
我研究了 SOLID 原理并为我创建了一个关于它的问题。
你假设我们在 Mug
class 中需要一个 Tea
对象,现在这比在 Mug
class 中从 Tea
创建一个实例更好还是通过 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
对象。
你的两个案例都违反了 SOLID。
你的每个具体实现(具体 class)应该只依赖于抽象。 在你的情况下,茶不是抽象的。 Mug 与 Tea 紧密耦合。下面是一种可能的编码方式。
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.如果我们确定茶只有一种可能的实现。然后接口也更好,因为具体的实现很难模拟,因此很难进行单元测试。
- 避免使用枚举来设置类型。枚举注入 switch case 并且在未来如果添加了一个 case,所有这些 switch case 都需要修改,导致违反 SOLID 中的 O。
如果添加案例,您必须修改现有代码,如果您忘记在某处添加案例,则会导致意外错误。 (它违反了OCP。而不是枚举将逻辑放在具体实现中,具有通用接口和具体实现)。此外,如果我们在枚举的各个实例中实现案例特定逻辑,那么枚举文件将变得巨大。相反,如果我们在实现公共接口的具体 classes 中有特定的逻辑,那么用户代码就会变得简单,因为它可以以多态方式注入具体 classes。
p.s。这个答案是关于遵循原则的,并不总是可以这样做。违反原则是可以的,但我们必须知道我们正在违反原则,并且有充分的理由这样做。
我会尽可能使用第二个,注入 classes 依赖项,以这个例子为例,其中 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 依赖于多个相似的 class。比较:
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
这样的名字创建抽象。在这种情况下,具体 class 名称不够具体,或者抽象名称不够通用。