Factory and Abstract Factory

Let’s imagine we need to know exchange rates in different cities, for this we are going to the Central Bank and are asking for an entity that can give us exchange rates for specific cities.

Factory

CentralBank will create or will give us instances of ExchangePlace based on the city name that are passing as a parameter – CentralBank will be a factory of ExchangeRates:

interface CentralBank {
    ExchangePlace getExchangePlace(String city);
}

interface ExchangePlace {
    BigDecimal getExchangeRateFor(String currency);
    String cityName();
}

Let’s implement two exchange places, one for Chisinau and another for Balti:

class ChisinauExchange implements ExchangePlace  {

    private final Map exchangeRate;

    public ChisinauExchange() {
        exchangeRate = new HashMap<>();
        exchangeRate.put("EUR", BigDecimal.valueOf(19.58));
    }

    @Override
    public BigDecimal getExchangeRateFor(String currency) {
        return exchangeRate.get(currency);
    }

    @Override
    public String cityName() {
        return "Chisinau";
    }
}

class BaltiExchange implements ExchangePlace {

    private final Map exchangeRate;

    public BaltiExchange() {
        exchangeRate = new HashMap<>();
        exchangeRate.put("EUR", BigDecimal.valueOf(19.52));
    }

    @Override
    public BigDecimal getExchangeRateFor(String currency) {
        return exchangeRate.get(currency).multiply(BigDecimal.valueOf(1.01));
    }

    @Override
    public String cityName() {
        return "Balti";
    }
}

Now, we will create a concrete CentralBank (the factory) that will create/give us instances for ExchangeRates:

class NationalBankOfMoldova implements CentralBank {
    private final Map exchanges;

    NationalBankOfMoldova() {
        this.exchanges = new HashMap<>();
        exchanges.put("Chisinau", new ChisinauExchange());
        exchanges.put("Balti", new BaltiExchange());
    }

    @Override
    public ExchangePlace getExchangePlace(String city) {
        return exchanges.get(city);
    }
}

Now the we have our factory implemented, we can use it by asking for EchangePlaces by city name:


class Scratch {
    public static void main(String[] args) {
        CentralBank centralBank = new NationalBankOfMoldova();
        ExchangePlace baltiExchangePlace = centralBank.getExchangePlace("Balti");
        printEuroRate(baltiExchangePlace);
    }

    static void printEuroRate(ExchangePlace exchangePlace) {
        System.out.println(exchangePlace.cityName() + " EUR <-> MDL exchange rate: " +
            exchangePlace.getExchangeRateFor("EUR"));
    }
}

Output:

Balti EUR <-> MDL exchange rate: 19.7152

AbstractFactory

Now, let’s imagine that our software is growing and we are extending our business to other countries, we had the CentralBank that gave us instances of ExchangePlace, now we know that there is a GlobalBank that will give us instances of CentralBanks

interface GlobalBank {
    CentralBank getBankForCountry(String country);
}

Each continent have a bank that implements GlobalBank:

class BigEuropeanBank implements GlobalBank {

    private final Map regionalBanks;

    public BigEuropeanBank() {
        this.regionalBanks = new HashMap<>();
        this.regionalBanks.put("Moldova", new NationalBankOfMoldova());
        // we can add more countries here
    }

    @Override
    public CentralBank getBankForCountry(String country) {
        return regionalBanks.get(country);
    }
}

This is how we use it:


class Scratch {
    public static void main(String[] args) {
        // abstract factory (GlobalBank) creates factories (CentralBank) that are creating ExchangePlaces
        GlobalBank bigEuropeanBank = new BigEuropeanBank();
        CentralBank centralBankOfMoldova = bigEuropeanBank.getBankForCountry("Moldova");
        ExchangePlace chisinauExchangePlace = centralBankOfMoldova.getExchangePlace("Chisinau");
        printEuroRate(chisinauExchangePlace);

    }

    static void printEuroRate(ExchangePlace exchangePlace) {
        System.out.println(exchangePlace.cityName() + " EUR <-> MDL exchange rate: " +
            exchangePlace.getExchangeRateFor("EUR"));
    }
}

Output:

Chisinau EUR <-> MDL exchange rate: 19.58

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *

Acest site folosește Akismet pentru a reduce spamul. Află cum sunt procesate datele comentariilor tale.