使用哪种设计模式(如果存在)?

4

我对面向对象编程(OOP)实现和设计模式有疑问。

我有一个固定的类模型,我无法更改它(因为每次应用程序启动时都会自动生成)。那里有许多类,就像下面的例子一样,有相同的等值字段:如您所见,citystreets 字段都包含在这两个类中。

public class A{
   String city;
   String street;

   String name;

   ....//get methods
}

public class B{
   String city;
   String street;

   String age;

   ....//get methods
}

我需要从这两种类型的类中提取地址,并且想用一个方法来实现它(因为重复编写相同的代码看起来很愚蠢)。如果类模型是可变的,我可以添加一个新的接口AddressableAB可以实现它。

public interface Addressable{

     public String getStreet();
     public String getCity();
}

//somewhere in code
public Address getAddress(Addressable addressable){
      return new Address(addressable.getCity(), addressable.getStreet());
} 

没有使用接口并且不需要为不同的类编写相同的代码,最优雅的实现方式是什么?

1
在A和B中实际上可以改变什么并不清楚。 - davidxxx
没有优雅的方法,你只能尝试将其转换为适当的类,或者使用反射(可能对此需求来说太重了)。 - Jean-Baptiste Yunès
如果类不能被更改(尽管如果它们是生成的可能是可以的),并且您无法为实现公共接口的那些类生成包装器/装饰器,那么我所看到的唯一其他方法就是反射。但在走这条路之前,我会认真考虑一下是否可以在不使用反射的情况下完成。一种生成(或至少填充)这些包装器的方法可能是mapstruct - Thomas
@davidxxx 这些类在每次应用程序启动时都是自动生成的,因此它们中没有任何可更改的内容。因此我无法向它们添加接口。 - user2957954
@user2957954,你能改变生成这些类的方式吗? - Thomas
显示剩余2条评论
3个回答

3

如果您不能更改A或B,那么您必然会有一个降级的解决方案。
一个简单而设计良好的解决方案当然依赖于定义一个地址检索方法(Address getAddress())的接口,AB将实现该接口。

您还可以定义一个包装类:

public class WrapperA implements Addressable {

  private final A a;

  public WrapperA(A a) {
    this.a = a;
  }

  @Override
  public Address getAddress(){
     return new Address(a.getCity(), a.getStreet(), etc...);
  } 

}

但是如果你必须为许多类复制这种代码,那么它可能会非常笨拙。 此外,客户端将不再操作A类,而是操作WrapperA类,这可能会破坏实际客户端代码。 因此,如果您想要实现真正的适配器,则需要使用接口。 正如所说,如果没有重新设计最小限度的A或B,则真正好的解决方案是复杂的。
作为解决办法,您可以定义一个Address类,该类提供了从A或B实例创建Address的工厂方法。
public class Address{

    ... 
   String city;
   String street;
    ... 

   private Address(){
   }

   public static Address of(A a){
     return new Address(a.getStreet(), a.getCity(), ....);
   }

   public static Address of(B b){
     return new Address(b.getStreet(), b.getCity(), ...);
   }

}

然后使用这些方法根据需要创建地址。

2
你可以编写 适配器 来提供一个通用接口。
public class AdpaterA implements Addressable {

  private final A a;

  public AdapterA(A a) {
    this.a = a;
  }

  @Override public String getStreet() {
    return this.a.street;
  }

  // other method is omitted as homework ;-)
}

那么您将使用适配器类进行进一步处理。

0

我曾经遇到过类似的情况,即在构建过程中生成类。(在我的情况下,构建过程会检查数据库,并为每个数据库表生成一个类,其中包含所有字段。)

您提到这些类是在应用程序启动时生成的。如果它们是在构建过程中生成的,您可以向构建过程添加额外的元素来更改生成的文件。在我的情况下,我们的构建服务器只有Linux,因此我在我们的ant脚本中添加了一行sed命令。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接