Skip to main content
12 of 21
added 382 characters in body
Laiv
  • 14.8k
  • 2
  • 33
  • 71

You are right, 8 parameters -all of them strings- make the constructor a good candidate for a code refactoring.

Essential attributes first

Look at the message model and guess what attributes are essential to initialize a valid instance. Only subject and body? The source too? The targets?

Reduce the number of arguments to the essential. Add setters for the rest.

Encapsulation

Consider encapsulating related parameters. For example, a,b and c might go together within a new class.

Use creational patterns

Instead of initializing messages directly, do It from factories or builders.

Inheritance

With the time you will realise that messages are excellent candidates for inheritance. Segmenting messages by attribute generates a little overhead because you will find yourself often asking for the type if(message.getType() == ...).

Inheritance works perfectly alongside with the previous points (creational patterns, encapsulation) and with next one.

Abstractions

Use abstractions. Don't work directly with concrete classes. For example, if Message is the superclass and CloudMessage a subclass, don't use CloudMessage in the interfaces. Do work as much as possible with Message.

Brief example

The interface

public interface Message{
    String getBody();
    String getSubject();
 }

The abstraction

public abstract class AbstractMessage implements Message{
   private String body;
   private String subject;
   AbstractMessage(String subject, String body){...}

   public String getBody(){...}
   public String getSubject(){...}
 }

Concrete message

public class CloudMessage extends  AbstractMessage{
   
  private String[] tokens;

  CloudMessage(String subject, String body, String[] tokens){
    super(subject, body);
    this.tokens = Arrays.copyOf(tokens,tokens.length);
  }

  public String[] getTokens(){
    return Arrays.copyOf(tokens,tokens.length);
  }
}

The Factory

public MessageFactory{
  private MessageFactory(){}
   
  public static Message createCloudMessage(String subject, String body, String[] tokens){
    // Validations...
    return new CloudMessage(subject, body, tokens);
    }
 }

Note that I didn't mention the Reader. The message will arrive at you somehow and the reading can be delegated to the Reader. The Factory could get the reader as a parameter instead of those Strings I used. For example:

The Factory and MessageReader

public MessageFactory{
  private MessageFactory(){}
   
  public static Message createCloudMessage(MessageReader messageReader){
    // Validations...
    return new CloudMessage(
      messageReader.getValueFor('subject'),
      messageReader.getValueFor('body'), 
      messageReader.getValuesFor('tokens'));
    }
 }

Consider the Builder pattern instead of the Factory (or both) if you find your messages initialization to be too complex.

public static Message createCloudMessage(MessageReader messageReader){
  // Validations...
  return new CloudMessageBuilder()
    .subject(messageReader.getValueFor('subject'))
    .body(messageReader.getValueFor('body'))
    .tokens(messageReader.getValuesFor('tokens'))
    //...more fields whether they are present or not.
    .build();
   }
 }

Worth to mention here, TolerantReaders

Finally, note also that each component contributes to the separation of concerns (SRP).

Laiv
  • 14.8k
  • 2
  • 33
  • 71