繁体   English   中英

Java类层次结构重构,而无需更改调用代码,这可能吗?

[英]Java class hierarchy refactoring without changing the invoking code, is it possible?

现在的情况:

在Java系统中,我们有一个名为Passenger的类,如下所示,

public Class Passenger{
//lots of member fields
private String firstName ;
private String lastName ;
private WhatEverAttribute att;

//lots of getters & setters
WhatEverAttribute getAtt(){ return att;}
void setAtt(WhatEverAttribute attIn){ this.att=attIn;}
...

//and lots of methods,for example
List<String> doWhatEverFuction(...){ return ... }
...
}

在其他地方的应用程序中,有很多地方可以创建和使用此类:

Passenger p1 = new Passenger();
p.setFirstName("blablabla")
p.setAtt(xxx);
Passenger p2 = new Passenger();
p2.setAtt(yyy)
List retl = p2.doWhatEverFuction(...);
...

该系统以前只管理航空旅客,因此“旅客”类别实际上是航空旅客的数据模型,

现在的问题是,我们需要扩展模型并建立层次结构,因为“乘客”将是具有通用字段和功能的通用“乘客”模型,新模型AirPassenger和SeaPassenger将对其进行扩展: 在此处输入图像描述

因此,某些常见的字段和功能将保留在“乘客”中,以在AirPassenger和SeaPassenger之间共享,但大多数特定于航空乘客的字段和功能将被下推到AirPassenger,

那么每个人都知道我必须更改现有代码来访问

   Passenger p = new Passenger();
   p.xxxxxx();

   AirPassenger p = new AirPassenger();
   p.xxxxxx();  

地方太多了,我不想在现有代码中的很多地方手动更改它们,以便从整个应用程序访问“乘客”,

我想要的是在完成层次结构后,其余代码仍可以正常工作,而无需进行任何更改,通过使用一些技巧,我可以通过新的Passenger()构造函数返回AirPassenger,例如:

Passenger{

Passenger(){

return Passenger("Air")

}

Passenger(String type){
  Switch(type){
  ...
  case "Air": return new AirPassenger();
  ...
  }

}

}

通过Java,CGLIB或其他一些动态功能,是否可能?

您最终选择的方法将取决于许多因素,很大程度上取决于代码的使用方式和位置。 如果您可以访问此类的所有用法,我强烈建议您提出的解决方案不建议使用-适当的继承层次结构将有助于使代码井井有条,并有可能在将来轻松扩展程序。 许多IDE(例如IntelliJ)都提供了强大的功能,可以对代码进行智能重构并将其提取到新类中,这将自动执行几乎所有工作并确保代码按预期运行。

如果可能,您的情况是使用抽象父类的经典案例。 由于没有“一般旅客”之类的东西,因此针对您的层次结构更正确的设计是将“旅客”声明为抽象类。 这样,无法直接创建Passenger实例,但是类本身可以保存实现,这些继承类可以根据需要使用或重写。 您还可以向此类添加工厂方法,根据输入(如您建议的那样),该方法将返回正确类型的新乘客。

编辑:

多态和类层次结构在Java中的工作方式非常特殊。 也就是说,程序员在维护代码可读性和模块化方面受到一些限制。 您所要求的(在您的澄清评论中)是不可能的描述方式。

您创建两个新类:

class AirPassenger extends Passenger {

    ...

    public void doSomethingAir() {
    ...
    }

    ...
}

class SeaPassenger extends Passenger {
    ...

    public void doSomethingSea() {
    ...
    }

    ...  
}

您可以将其某些方法重构为新的AirPassenger类,然后将其保留在原处。 您会注意到的第一件事是,您不能使用现有的Passenger构造函数来返回AirPassenger或SeaPassenger的实例,因为构造函数是void方法且没有返回值。 因此,您将需要提供一些构造工厂方法来创建AirPassenger或SeaPassenger的实例。

    Passenger createPassenger(String passengerType) { 
        switch (passengerType) {
            case "sea":
                return new SeaPassenger();
            default:
                return new AirPassenger();
        }
    }

您将方法从旅客中重构到了AirPassenger中。 这些方法在“乘客”类中不再存在,并且不能由“乘客”对象调用。 但是,您可以使用显式类型转换将所有乘客对象重新投射到AirPassenger,然后您将能够使用AirPassenger中现在使用的所有方法。 也可以使用一种方法来完成:

AirPassenger convertToAirPassenger(Passenger passenger) {
    return (AirPassenger) passenger;
}

我当然可以找到并替换,并且大多数IDE都可以做到,但是问题是系统中存在一些配置文件,txt文件,用作字典以及您知道的模板,它们使用乘客词或添加前缀和后缀,或者小写字母,您不能仅仅找到并替换,因此不仅需要更改Java代码,所以我宁愿不要更改它们(如果有的话),这是我的问题。

//you create an instance of class
ClassA obj = new ClassA();
//you call method doIT() inside ClassA
obj.doIt();

现在我必须重新建模,因为ClassA成为超类,并且这些方法下推到它的子类中,比如说ClassB,所以ClassB扩展了ClassA,方法doIt()现在在ClassB内部 ,每个人都知道我需要像往常一样更改以上代码

//you create an instance of ClassB, 
ClassB obj = new ClassB(); 
//or ClassB obj = new ClassA(); you have little code in the ClassA constuctor, etc.
//then you call a method
obj.doIt();

我知道,但我的问题是 ,无需对其进行更改

ClassA obj = new ClassA();
obj.doIt();

有什么技巧可以使其与新模型兼容?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM