简体   繁体   中英

Two constructors that do different things but take the same data type

I have recently ran into this problem with my MorseString class. I have two different constructors that do different things, but take the same data type:

/*
 * Constructor that takes the Morse Code as a String as a parameter
 */

public MorseString(String s) {
    if(!isValidMorse(s)) {
        throw new IllegalArgumentException("s is not a valid Morse Code");
    }
    // ...
}

and

/*
 * Constructor that takes the String as a parameter and converts it to Morse Code
 */

public MorseString(String s) {
    // ...
}

I came up with this solution:

public MorseString(String s, ParameterType type) {
    if(type == ParameterType.CODE) {
        if(!isValidMorse(s)) {
            throw new IllegalArgumentException("s is not a valid Morse Code");
        }
        // Constructor that takes Morse
    } else {
        // Constructor that takes String
    }
}

But it looks ugly. Any other solutions?

Yes. Get rid of your constructors and use instead some other approach, such as

1) A Factory Method , so you'd have methods like this:

class MorseString {
    private MorseString(){};
    public static MorseString getFromCode(String s) {
        // ...
    }
    public static MorseString getFromString(String s) {
        // ...
    }
}

// Usage: MorseString.getFromCode(foo);

or

2) A Builder , so you'd have methods like this

class MorseString {
    private MorseString(){};
    static class Builder {
       Builder initFromCode(String code) {
          // ..
          return this;
       }
       Builder initFromString(String str) {
          // ..
          return this;
       }
       MorseString build() {
          // ..
       }
    }
}

// Usage: MorseString.Builder.initFromCode(foo).build();

A builder is good if you have a highly complex creation logic, lots of parameters, having objects with only some of their information in mid-creation, some preliminary validations etc. A factory method is lighter approach for a situation where you have multiple ways of creating your object with slightly varying parameters.

Since one of the constructors is expecting ready-made Morse Code data (so it is more like a "constructor" - literally constructing an object from the data), and the other has to do some conversion, it might make more sense to make a static factory method called something like convert :

/*
 * Constructor that takes the Morse Code as a String as a parameter
 */

public MorseString(String s) {
    if(!isValidMorse(s)) {
        throw new IllegalArgumentException("s is not a valid Morse Code");
    }
    // ...
}

/*
 * Factory method that takes the String as a parameter and converts it to Morse Code
 */

public static MorseString convert(String s) {
    // ...
    return new MorseString(convertedString);
}

So if you had a valid morse code string, you use the constructor to turn it into an object. However if you have data that needs conversion, you would call the static factory method:

MorseString ms = MorseString.convert(myString);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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