jeudi 11 janvier 2024

Why do we use factory class to instantiate interface

I'm currently reading book pro spring 6. I am a bit confused on one example from book

Hello World Application

Here is the main class:

public class HelloWorldDecoupledWithFactory {

    public static void main(String... args) {
        MessageRenderer mr = MessageSupportFactory.getInstance().getMessageRenderer()
                .orElseThrow(() -> new IllegalArgumentException("Service of type 'MessageRenderer' was not found!"));
        MessageProvider mp = MessageSupportFactory.getInstance().getMessageProvider()
                .orElseThrow(() -> new IllegalArgumentException("Service of type 'MessageProvider' was not found!"));
        mr.setMessageProvider(mp);
        mr.render();
    }
}

The book mentions, that there is a small problem "changing the implementation of either the MessageRenderer or MessageProvider interface means a change to the code. To get around this we need to delegate the responsibility of retrieving the two implementation types and instantiating them to somebody else. The most manual one is to create a simple factory class, that reads the implementation class names from a properties file and instantiates them on behalf of the application"

I'm a bit confused on changing the implementation of either the MessageRenderer or MessageProvider interface means a change to the code. For example, if we add an additional method to interface, the classes implement it will change. So what is purpose using Factory?

public class MessageSupportFactory {

    private static MessageSupportFactory instance;
    private Properties props;
    private MessageRenderer renderer;
    private MessageProvider provider;

    private MessageSupportFactory() {
        props = new Properties();
        try {
            props.load(this.getClass().getResourceAsStream("/msf.properties"));
            String rendererClass = props.getProperty("renderer.class");
            String providerClass = props.getProperty("provider.class");
            renderer = (MessageRenderer) Class.forName(rendererClass).getDeclaredConstructor().newInstance();
            provider = (MessageProvider) Class.forName(providerClass).getDeclaredConstructor().newInstance();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    static {
        instance = new MessageSupportFactory();
    }

    public static MessageSupportFactory getInstance() {
        return instance;
    }

    public Optional<MessageRenderer> getMessageRenderer() {
        return renderer != null?  Optional.of(renderer) : Optional.empty();
    }

    public Optional<MessageProvider> getMessageProvider() {
        return provider!= null?  Optional.of(provider) : Optional.empty();
    }
}

Aucun commentaire:

Enregistrer un commentaire