Java设计问题-向固定类添加功能

Java设计问题-向固定类添加功能,java,class,Java,Class,我有一组类,所有这些类都需要以某种(单独的)方式进行操作 通常我只需要使用一个doSomething()方法创建一个dosomethinterface,并让每个类以适合每个类需要的方式实现该方法。但是,在这种情况下,我不能这样做,因为类定义是不可修改的(自动生成的) 因此,我认为我需要创建一组不同的类,每个类都接受一个自动生成的类并对它们执行操作。因此,假设我有两个自动生成的类,Class1和Class2,我将首先定义一个通用的操作符接口: public interface Operator &

我有一组类,所有这些类都需要以某种(单独的)方式进行操作

通常我只需要使用一个
doSomething()
方法创建一个
dosomethinterface
,并让每个类以适合每个类需要的方式实现该方法。但是,在这种情况下,我不能这样做,因为类定义是不可修改的(自动生成的)

因此,我认为我需要创建一组不同的类,每个类都接受一个自动生成的类并对它们执行操作。因此,假设我有两个自动生成的类,
Class1
Class2
,我将首先定义一个通用的
操作符
接口:

public interface Operator <TYPE>{
  public void doSomething(TYPE type);
}
这对我来说是一种坏习惯

我能想到的唯一其他方法是创建操作符到类名的映射,如下所示:

Map<Class, Operator> allOperators = new HashMap<Class, Operator>();
allOperators.put(Class1.class, new Class1Operator());
allOperators.put(Class2.class, new Class2Operator());
但这似乎不对(我不确定,将对象从其类中设置关键帧是否有任何问题……)

关于这些方法是否“正确”的任何输入?还是有更优雅的解决方案

谢谢

您所实现的(按类映射方法)是我在教授模式时提到的GoF访问者模式的替代方案之一。它高效且可扩展,即使在运行时也是如此。比if/else if/else硬连线方法要好得多

关闭类的唯一问题是实际实例是否实现了子类型而不是您提到的类类型;那么查找映射将不起作用

如果您需要识别子类型,我推荐Aaron的方法(沿着超类链走),但您也可能希望查看实现的接口。如果您只需要“精确的类匹配”,请保持getOperator简单

请注意,getOperator中有一个bug——它应该如下所示:

public Operator getOperator(Object obj){
    return allOperators.get(obj.getClass());
}
private Map<Class<?>, Operator<?>> map = new HashMap<Class<?>, Operator<?>>();
public <T> void register(Class<T> clazz, Operator<T> operator) {
    map.put(clazz, operator);
}
还有一件事。。。将地图隐藏在另一个类中,并按如下方式进行管理:

public Operator getOperator(Object obj){
    return allOperators.get(obj.getClass());
}
private Map<Class<?>, Operator<?>> map = new HashMap<Class<?>, Operator<?>>();
public <T> void register(Class<T> clazz, Operator<T> operator) {
    map.put(clazz, operator);
}
privatemap>Map=newhashmap>();
公共无效登记簿(类别分类、操作员){
地图放置(clazz,操作员);
}

这可以防止任何人注册一个不会对其键入的类工作的运算符。(您可能希望使用Operator作为参数,以允许针对超类编写运算符,但这可能不是必需的)

您可以使用Class.isAssignableFrom来解决子类型问题。我一直在使用它,虽然它不是“访客”这在实践中很好。

是否可以创建自己的类来扩展生成的类,然后让类实现接口?

构建映射的问题之一是,除非您专门注册子类或扩展get函数以查找超类,否则它将不支持子类具体地说

也就是说,如果B从A继承,并且您已经向A.class注册了一个运算符。除非将getOperator更改为以下内容,否则使用B.class获取运算符将失败:

public Operator getOperator(Object obj){
  Class<?> current = obj.getClass();
  Operator op;

  while((op = allOperators.get(current)) == null){
    current = current.getSuperclass();

    if(current == null){
      /* 
       * We've walked all the way up the inheritance hierarcy
       * and haven't found a handler. 
       */
      return null;
    }
  }

  return op;
}
公共运算符getOperator(对象obj){
Class current=obj.getClass();
操作员op;
while((op=allOperators.get(current))==null){
current=current.getSuperclass();
如果(当前==null){
/* 
*我们一路走到了遗产的最高等级
*还没有找到处理程序。
*/
返回null;
}
}
返回op;
}

一旦获得了合理的getOperator实现,将类映射到运算符似乎是一种合理的方法。

我要说的是,基于Java处理泛型的方式,仅使用接口本身是不可能的

在Java中,泛型在编译时被删除并替换为强制转换

我实际上还没有检查它在内部是如何工作的,但据猜测,您的界面变成了这样:

public interface Operator {
  public void doSomething(Object type);
}
public class Class1Operator implements Operator{
    public void doSomething(Object type){
      Class1 oType = (Class1) type;
      ...
      ...
    }
}
在它被称为的地方,进入这个:

public interface Operator {
  public void doSomething(Object type);
}
public class Class1Operator implements Operator{
    public void doSomething(Object type){
      Class1 oType = (Class1) type;
      ...
      ...
    }
}
这仍然不完全正确,因为类型在返回后也将被强制转换,而且Java字节码实际上看起来不像Java,但是您可能会得到一般的想法


instanceof和Map方法应该可以工作,即使它们有点凌乱。

您是否考虑过这一点:

public Interface Operator {
    public void doSomething();
}

public class Class1Operator extends Class1 implements Operator {
    ...
}

public class Class2Operator extends Class2 implements Operator {
    ...
}
但是关于你的第二个问题,让操作符访问一个对象,而不需要真正执行“instanceof”mojo(我想这就是看起来不干净的原因):

我建议,如果您不能根据自己的具体需要修改类,请围绕它们编写一个包装:

public Interface Operator<T> {
    public void doSomething(T obj);
}

public Interface WrappedObject<T> {
    public Operator<T> getOperator();
}
public class WrappedClass1 extends Class1 implements WrappedObject<Class1> {
    ...
}
public class WrappedClass2 extends Class2 implements WrappedObject<Class2> {
    ...
}
public class Class1Operator implements Operator<Class1> {
    ...
}
public class Class2Operator implements Operator<Class2> {
    ...
}    
公共接口操作符{
公共无效剂量测定(T obj);
}
公共接口包装对象{
公共运算符getOperator();
}
公共类WrappedClass1扩展Class1实现WrappedObject{
...
}
公共类WrappedClass2扩展类2实现WrappedObject{
...
}
公共类运算符实现运算符{
...
}
公共类Class2运算符实现运算符{
...
}    
这能满足你的需要吗

编写与您的需求不完全匹配且无法由您控制的类的包装器始终是一种很好的做法。它可以帮助您保持代码健康,即使这些野生类发生了变化

干杯


jrh.

这可能最终会创建很多额外的对象(取决于他的对象图有多大),如果这些对象相互引用,包装器也需要为引用创建包装器。但我还是建议一般考虑适配器/装饰器。为什么这会影响映射?不会,我现在已经澄清了这一点。谢谢Aaron,我不认为子类型会是一个问题,事实上可能会是相反的情况,因为子类型需要注册不同的操作符。。。