对象toString方法及里氏代换原则
Object toString method and Liskov substitution principle
每个 class 都直接或间接地继承自 Object
class。
Object
class 等具有重要的方法,最常被重写:toString
.
问题是:重写此方法是否会违反关于 Object
class 的里氏替换原则?
我来举个例子。
public class Main
{
public static void main(String[] args)
{
Object o = new Object();
String s = o.toString();
if (s.indexOf('@') > -1) {
System.out.println("OK");
} else {
System.out.println(":-(");
}
}
}
public class MyClass
{
private int x;
public string toString()
{
return Integer.toString(x);
}
}
显然,如果我将 new Object()
替换为 new MyClass()
,系统的行为就会发生变化。
好吧,这是一个品味问题。 Object
几乎没有保证属性。所以也没有什么可以违反的。
如果说返回class名字是这样一个可能违规的属性,那当然是一个subclass 不应该改变这一点。但是看了Object.toString()的文档发现并没有这样的保证:
Returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object.
所以我在这里没有看到 LSP 违规。
LSP 并没有说子class 的行为必须与超级class 完全相同。这将使 subclasses 完全无用。只要求subclasses 满足superclass.
的规范
唯一可以提及的是 Object
对每个对象 执行了一个无意义的方法 toString
.更复杂的设计可能会将其放入界面中。
我认为这种设计选择只是一种妥协,也被 .NET 等其他语言所取代。
里氏代换原则只要求接口兼容。它没有说明任何有关潜在行为的信息。例如
public interface Text {
String value();
}
public class SimpleText implements Text {
private final String value;
public SimpleText(String value) {
this.value = value;
}
@Override
public String value() {
return this.value;
}
}
public class NumberText implements Text {
private final Number number;
public NumberText(Number number) {
this.number = number;
}
@Override
public String value() {
return String.format("%.3f", this.number.doubleValue());
}
}
你不关心实现细节,可以这样交流:
//We care only about value() method, not its specific implementation
Text text = new SimpleText("text");
text.value();
text = new NumberText(44);
text.value();
请注意,如果您的实现将抛出任何异常,那么它将违反 LSP,因为 Object.toString() 不会抛出任何异常。
每个 class 都直接或间接地继承自 Object
class。
Object
class 等具有重要的方法,最常被重写:toString
.
问题是:重写此方法是否会违反关于 Object
class 的里氏替换原则?
我来举个例子。
public class Main
{
public static void main(String[] args)
{
Object o = new Object();
String s = o.toString();
if (s.indexOf('@') > -1) {
System.out.println("OK");
} else {
System.out.println(":-(");
}
}
}
public class MyClass
{
private int x;
public string toString()
{
return Integer.toString(x);
}
}
显然,如果我将 new Object()
替换为 new MyClass()
,系统的行为就会发生变化。
好吧,这是一个品味问题。 Object
几乎没有保证属性。所以也没有什么可以违反的。
如果说返回class名字是这样一个可能违规的属性,那当然是一个subclass 不应该改变这一点。但是看了Object.toString()的文档发现并没有这样的保证:
Returns a string representation of the object. In general, the toString method returns a string that "textually represents" this object.
所以我在这里没有看到 LSP 违规。
LSP 并没有说子class 的行为必须与超级class 完全相同。这将使 subclasses 完全无用。只要求subclasses 满足superclass.
的规范唯一可以提及的是 Object
对每个对象 执行了一个无意义的方法 toString
.更复杂的设计可能会将其放入界面中。
我认为这种设计选择只是一种妥协,也被 .NET 等其他语言所取代。
里氏代换原则只要求接口兼容。它没有说明任何有关潜在行为的信息。例如
public interface Text {
String value();
}
public class SimpleText implements Text {
private final String value;
public SimpleText(String value) {
this.value = value;
}
@Override
public String value() {
return this.value;
}
}
public class NumberText implements Text {
private final Number number;
public NumberText(Number number) {
this.number = number;
}
@Override
public String value() {
return String.format("%.3f", this.number.doubleValue());
}
}
你不关心实现细节,可以这样交流:
//We care only about value() method, not its specific implementation
Text text = new SimpleText("text");
text.value();
text = new NumberText(44);
text.value();
请注意,如果您的实现将抛出任何异常,那么它将违反 LSP,因为 Object.toString() 不会抛出任何异常。