Assume I have a juice store, which provide apple juice, orange juice and kiwi juice. As I accept customer's order, I will make juice and deliver juice to customer.
Therefore, I will do make juice and deliver juice no matter which juices are ordered.
package albert.practice.designpattern.factory;
public interface Juice {
void makeJuice();
void deliverJuice();
}
Each juice will implement Juice interface, and implement its own logic in each class.
Here is apple juice:
package albert.practice.designpattern.factory;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class AppleJuice implements Juice {
@Override
public void makeJuice() {
log.debug("making APPLE juice.");
}
@Override
public void deliverJuice() {
log.debug("deliver APPLE juice to customer.");
}
}
Here is orange juice:
package albert.practice.designpattern.factory;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class OrangeJuice implements Juice {
@Override
public void makeJuice() {
log.debug("making ORANGE juice.");
}
@Override
public void deliverJuice() {
log.debug("deliver ORANGE juice to customer.");
}
}
Here is kiwi juice:
package albert.practice.designpattern.factory;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class KiwiJuice implements Juice {
@Override
public void makeJuice() {
log.debug("making KIWI juice.");
}
@Override
public void deliverJuice() {
log.debug("deliver KIWI juice to customer.");
}
}
I also create a fruit enumeration to tell which juice I will make:
package albert.practice.designpattern.factory;
public enum FruitEnum {
APPLE, ORANGE, KIWI;
}
And I create a JuiceStore to process customers' order. The processOrder method is used to create apple, orange or kiwi object depends on customer's order.
package albert.practice.designpattern.factory;
public class JuiceStore {
public static void main(String[] args) {
JuiceStore test = new JuiceStore();
test.processOrder(FruitEnum.KIWI);
test.processOrder(FruitEnum.APPLE);
test.processOrder(FruitEnum.ORANGE);
}
public void processOrder(FruitEnum fruit) {
Juice juice = null;
if (FruitEnum.APPLE == fruit) {
juice = new AppleJuice();
} else if (FruitEnum.ORANGE == fruit) {
juice = new OrangeJuice();
} else if (FruitEnum.KIWI == fruit) {
juice = new KiwiJuice();
}
juice.makeJuice();
juice.deliverJuice();
}
}
It seems good so far. But if we would like to create object without exposing the if-else creating logic to client, we need to apply factory pattern to refactor the existing architecture.
Therefore, we need to create a JuiceFactory to generate object of concrete class based on given fruit.
package albert.practice.designpattern.factory;
public class JuiceFactory {
public Juice getJuice(FruitEnum fruitEnum) {
Juice juice = null;
if (FruitEnum.APPLE == fruitEnum) {
juice = new AppleJuice();
} else if (FruitEnum.ORANGE == fruitEnum) {
juice = new OrangeJuice();
} else if (FruitEnum.KIWI == fruitEnum) {
juice = new KiwiJuice();
}
return juice;
}
}
We can see the updated JuiceStore class, the creating logic had been hide in JuiceFactory, we only need to tell JuiceFactory which fruit I would like to make:
package albert.practice.designpattern.factory;
public class JuiceStore {
public static void main(String[] args) {
JuiceFactory factory = new JuiceFactory();
Juice apple = factory.getJuice(FruitEnum.APPLE);
apple.makeJuice();
apple.deliverJuice();
Juice orange = factory.getJuice(FruitEnum.ORANGE);
orange.makeJuice();
orange.deliverJuice();
Juice kiwi = factory.getJuice(FruitEnum.KIWI);
kiwi.makeJuice();
kiwi.deliverJuice();
}
}
We can see JuiceStore asks JuiceFactory to create object based on its demands, and JuiceStore will use its object to make juice and deliver juice.