I've been working on software architecture refactoring for last couple weeks. During a workshop one of architects showed me an interesting approach.

We were applying MVP-like style and then faced with the question: How a Presenter should tell a View to change its state?

Brute force approach looks like following:

public class Presenter {

private View view;

public void doSomething() {

//Here, services are processing something really important

view.setTitle( "Updated" );
view.setName( "New name" );
}
}

public class Form extends JFrame implements View {

private JTextfield nameTf;

@Override
public void setTitle( String title ) {
setTitle( title );
}

@Override
public void setName( String name ) {
nameTf.setText( name );
}
}
Well, this is actually ok, but the more components you have on the form, more verbose View interface becomes.

The move I am talking above is encapsulating a setter into separate object. Look here:
public abstract class ValueSetter {

private static Map<Class<?>, ValueSetter> SETTERS;

static {
SETTERS = new HashMap<Class<?>, ValueSetter>();
SETTERS.put(JTextField.class, new JTextFieldSetter());
}

public static ValueSetter get( Class<?> type ) {
if( SETTERS.containsKey(type) ) {
return SETTERS.get(type);
}

throw new IllegalArgumentException( "Missing ValueSetter for " + type );
}

public abstract void set( Object target, Object value );

private static class JTextFieldSetter extends ValueSetter {

@Override
public void set(Object target, Object value) {
((JTextField)target).setText( (String) value );
}
}

private static class JFrameSetter extends ValueSetter {

@Override
public void set(Object target, Object value) {
((JFrame)target).setTitle( (String) value );
}
}
}
Now it is possible to write more elegant code:
public class Form extends JForm implements View {

private Map<String, JComponent> components;

@Override
public void updateComponent(String id, Object value) {
JComponent component = components.get(id);
ValueSetter.get(component.getClass()).set(component, value);
}
}
So thanks Marcin for this nice tip and fresh idea for me ;)

.