51

I have a class called GoogleWeather, I want to convert it to another class CustomWeather.

Is there any design pattern which helps you to convert classes?

Thom
  • 14,013
  • 25
  • 105
  • 185
user1549004
  • 549
  • 1
  • 4
  • 5
  • What is your hierarchy (does CustomWeather extends GoogleWeather) ? What do you mean by "converting" ? – Mickäel A. Aug 06 '12 at 16:17
  • Convert as in how? Creating a subclass, renaming it, etc? It's unclear what you desire in the "CustomWeather" class – r36363 Aug 06 '12 at 16:18
  • there is no inheritance between GoogleWeather and CustomWeather – user1549004 Aug 06 '12 at 16:22
  • Factory pattern here IMO. You are creating a new object (CustomWeather) and using another as the "ingredients" (GoogleWeather). – RooN3y Jan 26 '23 at 13:05

3 Answers3

65

In that case I'd use a Mapper class with a bunch of static methods:

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;
   }
}

So you don't have dependencies between the classes.

Sample usage:

CustomWeather weather = Mapper.from(getGoogleWeather());
Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
  • 3
    is it a good approach to work with Mapper ? – user1549004 Aug 06 '12 at 16:23
  • 9
    Of cause, it is **the best approach ever**! (just kidding, but hey, I wouldn't recommend bad solutions here) – Andreas Dolk Aug 06 '12 at 16:24
  • 3
    Something that should be noted: this is a one-time conversion; future changes in the source object will not affect the fields of the resulting object. – thkala Aug 06 '12 at 19:45
  • Why would you do the class final here? (it makes the class [non-extendable](http://stackoverflow.com/a/5181618/2279924), I heard) – Patrick Apr 23 '14 at 19:48
  • @Patrick yes, as this is a utility class (aka global methods) declaring it final (and often also create a private constructor) should avoid wrong usage. In Java you cannot override static methods so inheritance is not useful here. – Arne Burmeister Jun 21 '16 at 13:25
  • 9
    +1 for keeping the types without dependency, -1 for implementing it by static methods making units using this not testable independent (without some crazy magic) – Arne Burmeister Jun 21 '16 at 13:28
  • @ArneBurmeister I don't understand why you say this isn't testable? You can easily write a unit test for classes/methods like these. – alex Apr 19 '21 at 16:48
  • 2
    @alex right, it is easy to test the static methods of this utility class but it would be hard to test classes using this methods as you cannot mock them easily. By not using static methods but making it normal api of the instance you could use dependency injection and mock the Mapper logic. – Arne Burmeister Apr 21 '21 at 17:10
  • @ArneBurmeister I agree with that. I would only recommend this answer as an option when the developer does not have access to the class. When it is a normal API of the instance, it makes it easier to convert between objects, IDE friendly, and like you mentioned, it can be mocked. Also to use the static methods like the answer, what happens when you add other "Weather" types? What am I converting from in that regard? Not the best approach in my opinion. – Brandon Oct 25 '21 at 20:06
56

There is one critical decision to make:

Do you need the object that is generated by the conversion to reflect future changes to the source object?

If you do not need such functionality, then the simplest approach is to use a utility class with static methods that create a new object based on the fields of the source object, as mentioned in other answers.

On the other hand, if you need the converted object to reflect changes to the source object, you would probably need something along the lines of the Adapter design pattern:

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;
    }
    ...
}
Visruth
  • 3,430
  • 35
  • 48
thkala
  • 84,049
  • 23
  • 157
  • 201
  • i didn't understand the difference between adapter and mapper appproche what is the advantage of using the adapter pattern in this case ? – user1549004 Aug 06 '12 at 21:34
  • 5
    @user1549004: The adapter is a wrapper - all methods are forwarded to the source object. That means that any updates to the source object, are propagated through the adapter. On the other hand, using a mapper class is a one-time thing - any updates to the source will not generally affect the result of the conversion. – thkala Aug 06 '12 at 21:46
  • can you please give me an example when using a mapper class in the case that any updates to the source doesn't affect the result of the conversion. – user1549004 Aug 06 '12 at 22:04
  • im sorry i mean affect the result* – user1549004 Aug 06 '12 at 22:10
  • @user1549004: Using my example above, assume a GoogleWeather instance with a field `int temperature = 30;` Using a mapper will produce a CustomWeather instance with a field `int temperature = 303;`. If the original GW instance is modified when the temperature changes e.g. to 32, the converted CW instance will still have the old value of 303 instead of 305. – thkala Aug 06 '12 at 22:14
  • @user1549004: using an adapter on the other hand, would just pass any access to the adapter object back to the source object, thus reflecting any changes immediately. – thkala Aug 06 '12 at 22:16
  • 2
    Wasn't the question about converting? – Andreas Dolk Aug 07 '12 at 04:57
9

Besides, You can also use new Java8 feature 'Function' from java.util.function'.

More detailed explanation is provided in http://www.leveluplunch.com/java/tutorials/016-transform-object-class-into-another-type-java8/ . Kindly have a look!

hasanac
  • 168
  • 3
  • 13