我很高兴收到(潜在的,截至撰写本文时)潜行者的反馈。
让我们假设我想创建一个存储类XXX的单个对象及其所有派生类的类。
我应该采用LSP方法还是采用泛型有界类型参数方法?
在我看来,考虑到Lieskov替换原则(LSP)的含义,具有单个有界类型参数的泛型类是不必要的:
以下两个类都接受相同类型的对象(仅作为示例我使用下面的类Object及其派生类)。
class LSP { //this class uses Lieskov Substitution Principle (LSP)
Object a;
LSP(Object a) { this.a= a; }
Object get() { return this.a; }
}
class Gen<V extends Object> { //this is a generic class with bounded type parameter
V a;
Gen(V a) { this.a= a; }
V get() { return this.a; }
}
class Stackoverflow {
public static void main(String[] arg){
LSP l = new LSP(5);
Gen<Integer> g = new Gen<Integer>(5);
}
}
你能指出我可能的分歧吗?好处?缺陷?
答案 0 :(得分:3)
假设你有一个这样的课程:
class SomeClass<T extends Number> {
T instance;
SomeClass(T instance) { this.instance = instance; }
T get() { return instance; }
int intValue() { return instance.intValue(); }
}
要调用instance.intValue()
方法,T
必须是具有intValue
方法的类型。通过约束T
扩展Number
,我们保证这一点。
答案 1 :(得分:1)
用你的例子我可以做到:
LSP l = new LSP(5);
Integer i = (Integer) l.get();
需要演员阵容,但这不是一个安全演员。我也可以这样做:
LSP l = new LSP(new Object());
Integer i = (Integer) l.get(); // Crash
使用泛型,如果我不使用原始类型,我总是可以确保至少来自get
的整数:
Gen<Integer> g = new Gen<>(new Object()); // Does not compile
...
Gen<Integer> g2 = new Gen<>(5);
Integer i = g2.get(); // no need to cast
答案 2 :(得分:0)
如果您发现错误或不完整,请使用评论来帮助我改进对自己问题的摘要答案。再次感谢所有帮助我做到这一点的人。
假设Base
类:
class Base {}
并将使用其派生类,例如:
class Der1 extends Base {}
class Der2 extends Base {}
Der1 d1 = new Der1();
Der2 d2 = new Der2();
...可以选择通过使用泛型或利用两者具有相同Der1
父级的事实将Der2
和Base
实例同时接收到其他类中=利用Lieskov替代原则,LSP):
class Gen<T extends Base> { //this class uses bounded generics
T o;
void set(T o){ this.o = o; }
T get(){ return o; }
}
class LSP{ // this class uses LSP
Base o;
void set(Base o){ this.o = o; }
Base get(){ return o; }
}
<强> 1。在为LSP
类实例化它们时,Gen
和Base
之间几乎没有区别,例如:
Gen<Base> g = new Gen<Base>();
LSP l = new LSP();
...因为这两个类在接受Der1
和Der2
时非常相似:
g.set(d1);
g.set(d2);
l.set(d1);
l.set(d2);
...并且这两个类都具有强制转换的特性,在运行时不安全,因为不明显哪个派生类型实际存储在LSP
或Gen
中:
d2 = (Der2) g.get(); //results in runtime error if `Der1` has been stored in `g`
d2 = (Der2) l.get(); //results in runtime error if `Der1` has been stored in `l`
<强> 2。泛型Gen
在为派生类实例化时具有不同的特征,例如:
Gen<Der1> g1 = new Gen<>();
Gen<Der2> g2 = new Gen<>();
现在,编译器能够确保类型安全,同时将数据放入Gen<>
,以及从Gen<>
获取数据时,代价是为每个派生类型单独的Gen<>
实例:
g1.set(d1); //can only put d1 to g1
g2.set(d2); //can only put d2 to g2
d1 = g1.get(); // no casting needed, only d1 can be in g1
d2 = g2.get(); // no casting needed, only d2 can be in g2