概述
需求
设计一个咖啡店点餐系统
设计一个咖啡类(Coffee);并定义其两个子类(美式咖啡AmericanCoffee和拿铁咖啡LatteCoffee);再设计一个咖啡店类(CoffeeStore),其具备点咖啡的功能。
类图
咖啡类
public abstract class Coffee {
// 获取咖啡名
public abstract String getName();
// 加糖
public void addSugar(){
System.out.println("加糖");
}
// 加奶
public void addMilk(){
System.out.println("加奶");
}
}
美式咖啡类
public class AmericanCoffee extends Coffee {
@Override
public String getName() {
return "美式咖啡";
}
}
拿铁咖啡类
public class LatteCoffee extends Coffee {
@Override
public String getName() {
return "拿铁咖啡";
}
}
咖啡店类
public class CoffeeStore {
public Coffee orderCoffee(String type) {
// 根据类型创建咖啡实例
Coffee coffee = null;
if("Latte".equals(type)) {
coffee = new LatteCoffee();
}
else if("Americano".equals(type)) {
coffee = new AmericanCoffee();
}
else {
System.out.println("Sorry, we don't have this kind of coffee.");
}
// 加糖和奶
coffee.addSugar();
coffee.addMilk();
return coffee;
}
}
测试
public class Client {
public static void main(String[] args) {
// 1 创建咖啡店类
CoffeeStore coffeeStore = new CoffeeStore();
// 2 点咖啡
Coffee coffee = coffeeStore.orderCoffee("Latte");
System.out.println(coffee.getName());
}
}
在Java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new,就会对该对象耦合严重,假如需要更换对象,所有new的地方都需要修改一遍,这显然违背了开闭原则。如果使用工厂来生产对象,就只需要和工厂打交道就好了,彻底和对象解耦,如果需要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的。所以说,工厂模式的最大优点就是:解耦。
三种工厂:
- 简单工厂模式(不属于GOF的23种经典设计模式)
- 工厂方法模式
- 抽象工厂模式
简单工厂模式
简单工厂不是一种设计模式,反而比较像是一种编程习惯。
结构
简单工厂包含以下角色:
- 抽象产品:定义了产品的规范,描述了产品的主要特征和功能(通用行为)
- 具体产品:实现或继承抽象产品(接口/抽象类)的子类
- 具体工厂:提供了创建产品的方法,调用者通过该方法来获取产品(根据传递的不同参数来创建不同的产品示例)
实现
咖啡类:
public abstract class Coffee {
// 获取咖啡名
public abstract String getName();
// 加糖
public void addSugar(){
System.out.println("加糖");
}
// 加奶
public void addMilk(){
System.out.println("加奶");
}
}
美式咖啡类:
public class AmericanCoffee extends Coffee {
@Override
public String getName() {
return "美式咖啡";
}
}
拿铁咖啡类:
public class LatteCoffee extends Coffee {
@Override
public String getName() {
return "拿铁咖啡";
}
}
简单咖啡工厂类:
public class SimpleCoffeeFactory {
public Coffee createCoffee(String type) {
// 根据类型创建咖啡实例
Coffee coffee = null;
if("Latte".equals(type)) {
coffee = new LatteCoffee();
}
else if("Americano".equals(type)) {
coffee = new AmericanCoffee();
}
else {
System.out.println("Sorry, we don't have this kind of coffee.");
}
return coffee;
}
}
咖啡店类:
public class CoffeeStore {
public Coffee orderCoffee(String type) {
// 实例化工厂
SimpleCoffeeFactory simpleCoffeeFactory = new SimpleCoffeeFactory();
// 调用生产咖啡的方法
Coffee coffee = simpleCoffeeFactory.createCoffee(type);
// 加糖和奶
coffee.addSugar();
coffee.addMilk();
return coffee;
}
}
测试:
public class Cilent {
public static void main(String[] args) {
// 创建咖啡店类对象
CoffeeStore coffeeStore = new CoffeeStore();
// 点咖啡
Coffee coffee = coffeeStore.orderCoffee("Latte");
System.out.println(coffee.getName());
}
}
总结
工厂(factory)处理创建对象的细节,一旦有了SimpleCoffeeFactory,CoffeeStore类中的orderCoffee()就变成此对象的客户,后期如果需要Coffee对象直接从工厂中获取即可。这样就解除了CoffeeStore和Coffee实现类的耦合,同时又产生了新的耦合,CoffeeStore和SimpleCoffeeFactory的耦合,工厂对象和商品对象的耦合。
后期如果需要增加新咖啡,势必需要修改SimpleCoffeeFactory的代码,违反了开闭原则。工厂的客户端可能有很多,如创建美团外卖等,这样只需要修改工厂类的代码,省去了其他的操作。
简单工厂简化了客户端操作,客户端可以调用工厂方法来获取具体的产品,而无需直接与具体产品类交互,降低了耦合,但是有一个很大的问题就是不够灵活,如果需要添加新产品,就需要修改工厂类的代码。
优点:
- 封装了创建对象的过程,可以通过参数直接获取对象
- 把对象的创建和业务逻辑层分开,避免了修改客户端的代码,如果要实现新产品直接修改工厂类,不需要在原代码中修改,降低客户代码修改的可能性,更容易扩展
缺点:
- 增加新产品时需要修改工厂类的代码,违背了开闭原则
扩展(静态工厂)
在实际开发中,一部分开发人员将工厂类中创建对象的功能定义成静态的,这就是静态工厂模式,也不属于23种设计模式,是一种编程习惯。
好处就是客户端可以不用实例化工厂对象,直接调用即可。
public class SimpleCoffeeFactory {
public static Coffee createCoffee(String type) {
// 根据类型创建咖啡实例
Coffee coffee = null;
if("Latte".equals(type)) {
coffee = new LatteCoffee();
}
else if("Americano".equals(type)) {
coffee = new AmericanCoffee();
}
else {
System.out.println("Sorry, we don't have this kind of coffee.");
}
return coffee;
}
}