设计模式:将一个类转换为另一个类

51

我有一个名为GoogleWeather的类,我想将它转换为另一个类CustomWeather。

是否有任何设计模式可帮助您转换类?


你的层次结构是什么(CustomWeather是否扩展了GoogleWeather)? “转换”是什么意思? - Mickäel A.
转换是指如何?创建子类,重命名它等等?不清楚您在“CustomWeather”类中想要什么。 - r36363
GoogleWeather和CustomWeather之间没有继承关系。 - user1549004
工厂模式在这里。你正在创建一个新对象(CustomWeather),并使用另一个对象作为“原材料”(GoogleWeather)。 - RooN3y
3个回答

65

在这种情况下,我会使用一个带有一堆静态方法的Mapper类:

public final class Mapper {

   public static GoogleWeather from(CustomWeather customWeather) {
      GoogleWeather weather = new GoogleWeather();
      // set the properties based on customWeather
      return weather;
   }

   public static CustomWeather from(GoogleWeather googleWeather) {
      CustomWeather weather = new CustomWeather();
      // set the properties based on googleWeather
      return weather;
   }
}

所以你的类之间没有依赖关系。

示例用法:

CustomWeather weather = Mapper.from(getGoogleWeather());

3
使用Mapper是一个好的方法吗? - user1549004
9
当然,这是迄今为止最好的方法!(开个玩笑,但是嘿,我不会在这里推荐糟糕的解决方案)。 - Andreas Dolk
3
需要注意的是:这是一次性转换,源对象以后的更改不会影响到结果对象的字段。 - thkala
9
保留类型而不依赖其他类型的写法得到加分,但采用静态方法实现单位转换会导致这些使用此方法的代码难以独立测试(除非使用一些奇怪的技巧),因此扣分。 - Arne Burmeister
2
@alex 没错,测试这个工具类的静态方法很容易,但是测试使用这些方法的类会很难,因为你不能轻易地模拟它们。通过不使用静态方法,而是将其作为实例的普通 API,您可以使用依赖注入并模拟 Mapper 逻辑。 - Arne Burmeister
显示剩余4条评论

56

需要做出一个关键决定:

你是否需要从转换生成的对象反映源对象的未来更改?

如果不需要这样的功能,则最简单的方法是使用具有静态方法的实用程序类,该类基于源对象的字段创建一个新对象,如其他答案中所述。

另一方面,如果你需要转换后的对象反映源对象的更改,则可能需要类似于适配器设计模式的东西:

public class GoogleWeather {
    ...
    public int getTemperatureCelcius() {
        ...
    }
    ...
}

public interface CustomWeather {
    ...
    public int getTemperatureKelvin();
    ...
}

public class GoogleWeatherAdapter implements CustomWeather {
    private GoogleWeather weather;
    ...
    public int getTemperatureKelvin() {
        return this.weather.getTemperatureCelcius() + 273;
    }
    ...
}

5
适配器是一个包装器 - 所有方法都会被转发到源对象。这意味着源对象的任何更新都会通过适配器传播。另一方面,使用映射器类只是一次性的 - 源的任何更新通常不会影响转换结果。 - thkala
请给我一个使用映射器类的例子,其中源的任何更新都不会影响转换结果。 - user1549004
使用我上面的示例,假设有一个GoogleWeather实例,它有一个字段int temperature = 30;。使用映射器将会产生一个CustomWeather实例,并带有一个字段int temperature = 303;。如果原始的GW实例在温度变化时被修改,例如变为32,那么转换后的CW实例仍然会保留旧值303,而不是更新为305。 - thkala
@user1549004:另一方面,使用适配器只会将任何对适配器对象的访问传递回源对象,从而立即反映任何更改。 - thkala
2
问题不是关于转换吗? - Andreas Dolk
显示剩余2条评论

9

1
这只是一个简单的单向转换器 - 有效的,但您可以在任何Java版本中完全相同地实现它。 - Arne Burmeister

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