3.工厂方法模式 (单点咖啡和甜点)
(1).概述
需求: 设计一个咖啡点餐系统。
设计1个咖啡类,并定义两个子类(美式咖啡)和拿铁咖啡;再设计一个咖啡店类,咖啡店具有点咖啡的功能。
- 反列
咖啡类
package com.jsxs.pattern.factory.before; /** * @Author Jsxs * @Date 2023/4/17 12:47 * @PackageName:com.jsxs.pattern.factory.before * @ClassName: Coffe * @Description: TODO 咖啡类 * @Version 1.0 */ public abstract class Coffee { // 0. 子类必须要实现抽象方法 public abstract String getName(); // 1.加糖 public void addSuger() { System.out.println("加糖"); } // 2.加奶 public void addMilk() { System.out.println("加奶"); } }
咖啡类型
package com.jsxs.pattern.factory.before; /** * @Author Jsxs * @Date 2023/4/17 12:51 * @PackageName:com.jsxs.pattern.factory.before * @ClassName: LatteCoffe * @Description: TODO 拿铁咖啡 * @Version 1.0 */ public class LatteCoffee extends Coffee{ @Override public String getName() { return "拿铁咖啡"; } }
package com.jsxs.pattern.factory.before; /** * @Author Jsxs * @Date 2023/4/17 12:50 * @PackageName:com.jsxs.pattern.factory.before * @ClassName: AmericanCoffee * @Description: TODO 美式咖啡 * @Version 1.0 */ public class AmericanCoffee extends Coffee{ @Override public String getName() { return "美式咖啡"; } }
咖啡商店
package com.jsxs.pattern.factory.before; /** * @Author Jsxs * @Date 2023/4/17 12:52 * @PackageName:com.jsxs.pattern.factory.before * @ClassName: CoffeeStore * @Description: TODO 咖啡店 * @Version 1.0 */ public class CoffeeStore { public Coffee orderCoffee(String type){ // /声明Coffee类型的变量,根据不同类型创建不同的coffee子类对象 Coffee coffee=null; if ("american".equals(type)){ coffee=new AmericanCoffee(); // 1. 创建一个美食咖啡 }else if ("latte".equals(type)){ coffee=new LatteCoffee(); //2. 创建一个拿铁咖啡 }else { throw new RuntimeException("对不起,你点的咖啡没有"); } // 添加配料 coffee.addMilk(); coffee.addSuger(); return coffee; } }
package com.jsxs.pattern.factory.before; /** * @Author Jsxs * @Date 2023/4/17 12:57 * @PackageName:com.jsxs.pattern.factory.before * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { CoffeeStore coffeeStore = new CoffeeStore(); Coffee coffee = coffeeStore.orderCoffee("american"); System.out.println(coffee.getName()); } }
假如需要新增产品,那么我们就迫不得已需要修改数据
在Java种,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重
。假如我们要更换对象,所有new对象的地方需要修改一遍,这显然违背了软件设计的开闭原则。如果使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦。如果要更换对象,直接在工厂里更换该对象即可,达到了对象解耦的目的,所以说: “工厂模式最大的优点是: 解耦”。
(2).简单工厂模式
简单工厂模式不是一种设计模式,反而更像一种编程习惯。
- 结构
简单工厂包含以下的角色
- 抽象产品: 定义了产品的规范、
描述了产品的主要特性和功能
。 - 具体产品:
实现或者继承
抽象产品的子类 - 具体工厂: 提供了创建产品的方法,调用者通过方法来获取产品。
抽象产品
package com.jsxs.pattern.factory.Single_Factory; /** * @Author Jsxs * @Date 2023/4/17 13:54 * @PackageName:com.jsxs.pattern.factory.Single_Factory * @ClassName: Coffee * @Description: TODO * @Version 1.0 */ public abstract class Coffee { // 0. 子类必须要实现抽象方法 public abstract String getName(); // 1.加糖 public void addSuger() { System.out.println("加糖"); } // 2.加奶 public void addMilk() { System.out.println("加奶"); } }
具体产品
package com.jsxs.pattern.factory.Single_Factory; /** * @Author Jsxs * @Date 2023/4/17 12:51 * @PackageName:com.jsxs.pattern.factory.before * @ClassName: LatteCoffe * @Description: TODO 拿铁咖啡 * @Version 1.0 */ public class LatteCoffee extends Coffee { @Override public String getName() { return "拿铁咖啡"; } }
package com.jsxs.pattern.factory.Single_Factory; /** * @Author Jsxs * @Date 2023/4/17 12:50 * @PackageName:com.jsxs.pattern.factory.before * @ClassName: AmericanCoffee * @Description: TODO 美式咖啡 * @Version 1.0 */ public class AmericanCoffee extends Coffee { @Override public String getName() { return "美式咖啡"; } }
简单工厂
package com.jsxs.pattern.factory.Single_Factory; /** * @Author Jsxs * @Date 2023/4/17 13:56 * @PackageName:com.jsxs.pattern.factory.Single_Factory * @ClassName: SimleCoffeeFactory * @Description: TODO 简单工厂 * @Version 1.0 */ public class SimpleCoffeeFactory { public Coffee createCoffee(String type){ Coffee coffee=null; if ("american".equals(type)){ coffee=new AmericanCoffee(); // 1. 创建一个美食咖啡 }else if ("latte".equals(type)){ coffee=new LatteCoffee(); //2. 创建一个拿铁咖啡 }else { throw new RuntimeException("对不起,你点的咖啡没有"); } return coffee; } }
咖啡店
package com.jsxs.pattern.factory.Single_Factory; /** * @Author Jsxs * @Date 2023/4/17 13:55 * @PackageName:com.jsxs.pattern.factory.Single_Factory * @ClassName: CoffeeStore * @Description: TODO * @Version 1.0 */ public class CoffeeStore { // 1.创建点餐业务 public Coffee orderCoffee(String type) { // 2.具体商品我们去工厂获取 SimpleCoffeeFactory simpleCoffeeFactory = new SimpleCoffeeFactory(); Coffee coffee = simpleCoffeeFactory.createCoffee(type); // 3.加配料 coffee.addMilk(); coffee.addSuger(); return coffee; } }
客户端
package com.jsxs.pattern.factory.Single_Factory; /** * @Author Jsxs * @Date 2023/4/17 14:02 * @PackageName:com.jsxs.pattern.factory.Single_Factory * @ClassName: Client * @Description: TODO * @Version 1.0 */ public class Client { public static void main(String[] args) { CoffeeStore coffeeStore = new CoffeeStore(); Coffee coffee = coffeeStore.orderCoffee("american"); System.out.println(coffee.getName()); } }
简单工厂的优缺点
工厂处理创建对象的细节,一旦有了简单工厂类
、咖啡店类
中的订单方法
就变成此对象的客户,后期如果需要咖啡对象直接从该工厂种获取即可,这样也就接触了和Coffee实现类的耦合;同时又产生了新的耦合,咖啡店对象
和简单工厂类对象
的耦合,工厂对象
和商品对象
的耦合。
后期如果再加新产品的咖啡,我们势必需要简单工厂类的代码
,违反了开闭原则。工厂类的客户端可能有很多,比如创建美团外卖等,这样只要修改该工厂类的代码,省去其他的修改操作。
优点: 封装了创建对象的过程,可以通过参数直接获取对象,把对象的创建和业务逻辑分开
,这样以后就避免了修改客户端代码,如果要实现新产品直接修改工厂类,而不要在源代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展
缺点:增加新产品的时候,依然需要修改工厂类,违反了开闭原则