假设我有一个抽象基类和许多不可变的派生类:
public abstract class Communication{
private final String message;
private final Medium medium;
// getters, other methods, etc.
public Communication(String message, Medium medium){
this.message = message;
this.medium = medium;
}
}
public class HateMail extends Communication{
public Hatemail(String message){
super(message, Medium.Written);
}
}
public class CasualGreeting extends Communication{
public CasualGreeting(String message){
super(message, Medium.Speech);
}
}
我想要做的是"修改"与Communication
类似的String
,类似于:
HateMail hateMail = new HateMail("I'm saying some really mean things.");
hateMail = hateMail.censor();
从censor()返回的新对象是派生类型而不是基类型。
我曾想过实现这个的一些方法:
1.使用Class.newInstance()
:
public abstract class Communication{
private final String message;
private final Medium medium;
// getters, other methods, etc.
public Communication(String message, Medium medium){
this.message = message;
this.medium = medium;
}
public <T extends Communication> T censor(){
String censored = // Censorship logic
Communication newComm = this.getClass().newInstance();
newComm.message = censored;
newComm.medium = this.medium;
return (T) newComm;
}
}
但这种方式非常糟糕,我必须为所有派生类实现无参数构造函数。
2.使用Class.getConstructors()
。但这并不比以前的解决方案好得多。
3.在Communication
中有一个抽象方法,在每个派生类中重写,返回该类的正确转换实例。但这感觉它确实违反了DRY,因为这些方法只会在他们返回的课程中有所不同。
我觉得必须有一种更简单的方法来使用泛型,我只是不知道它的语法。
答案 0 :(得分:1)
一般来说,你想要做的是一个坏主意,并且可能有更好的设计可以避免这个问题。
让我解释一下。
如果censor
是适用于每个Communication
的方法,那么它应该是该类中的方法。但是,现在这意味着它应该适用于Communication
的任何变量,因此应该返回Communication
。例如,这将允许子类决定审查通信返回不同的子类。你可能会认为这种情况永远不会发生,直到它发生的时候!
但是,如果censor
仅适用于Communication
的某些子类,则它应该是每个子类中的一个适当命名的方法,并返回该类的对象。
例如,如果我们假设所有通信都能够通过默认的无审查进行审查,那么您可能会遇到以下情况:
abstract class Communication {
private final String message;
private final Medium medium;
protected Communication(String message, Medium medium) {
this.message = message;
this.medium = medium;
}
public Communication censor() {
return this;
}
}
class HateMail extends Communication {
public HateMail(String message) {
super(message, Medium.EMAIL);
}
@Override
public Communication censor() {
return new HateMail(toCensoredMessage(message));
}
}
class Greeting extends Communication {
public Greeting(String message) {
super(message, Medium.SPEECH);
}
}
请注意,在this
方法中默认返回censor
是完全安全的,因为您的类是不可变的。 (请注意,您在问题中发布的代码无法编译,因为您在调用newInstance
后将值分配给最终变量。)
我怀疑你的问题确实隐藏了一个完全不同的问题:一旦通信被审查(因此,现在是Communication
),你如何调用你知道特定于原始子类的方法。我的建议是考虑Visitor pattern。这使您可以优雅地处理不知道新类是什么而不诉诸投射或反射。
答案 1 :(得分:-1)
你不需要泛型。允许子类返回比超类更复杂的返回类型。
你可以这样写 - 共享审查逻辑将在受保护的方法censored()
中(显然,审查逻辑可以为所有通信类一般定义 - 如果不是这样, censored()
方法只应在子类中定义:
public abstract class Communication{
private final String message;
private final Medium medium;
// getters, other methods, etc.
public Communication(String message, Medium medium){
this.message = message;
this.medium = medium;
}
protected String censored() {
return // Censorship logic
}
public abstract Communication censor();
}
public class HateMail extends Communication{
public HateMail(String message){
super(message, Medium.Written);
}
public HateMail censor() {
return new HateMail(censored());
}
}