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.