【需求】设计一个咖啡店点餐系统。设计一个咖啡类 (Coffee),并定义其两个子类:美式咖啡【AmericanCoffee】和拿铁咖啡【LatteCoffee】;再设计一个咖啡店类 (CoffeeStore),咖啡店具有点咖啡的功能。具体类的设计如下:
在 Java 中,万物皆对象,这些对象都需要创建,如果创建的时候直接 new 该对象,就会对该对象耦合严重,假如要更换对象,所有 new 对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则。如果使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦,如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的;所以说工厂模式最大的优点就是:解耦。
简单工厂不是一种设计模式,反而比较像是一种编程习惯。
简单工厂包含如下角色:
Coffee.java
public abstract class Coffee {
public abstract String getName();
//加糖
public void addSugar(){
System.out.println("加糖");
}
//加奶
public void addMilk(){
System.out.println("加奶");
}
}
AmericanCoffee.java
//美式咖啡
public class AmericanCoffee extends Coffee {
@Override
public String getName() {
return "美式咖啡";
}
}
LatteCoffee.java
//拿铁咖啡
public class LatteCoffee extends Coffee {
@Override
public String getName() {
return "拿铁咖啡";
}
}
SimpleCoffeeFactory.java
public class SimpleCoffeeFactory {
public Coffee createCoffee(String type) {
//声明 Coffee 类型的变量,根据不同类型创建不同的 coffee 子类对象
Coffee coffee = null;
if("american".equals(type)) {
coffee = new AmericanCoffee();
} else if("latte".equals(type)) {
coffee = new LatteCoffee();
} else {
throw new RuntimeException("对不起,您所点的咖啡没有");
}
return coffee;
}
}
CoffeeStore.java
public class CoffeeStore {
public Coffee orderCoffee(String type){
SimpleCoffeeFactory factory = new SimpleCoffeeFactory();
//调用生产咖啡的方法
Coffee coffee = factory.createCoffee(type);
//加配料
coffee.addMilk();
coffee.addSugar();
return coffee;
}
}
Clien.java
public class Clien {
public static void main(String[] args) {
// 1.创建咖啡店类
CoffeeStore store = new CoffeeStore();
// 2.点咖啡
Coffee coffee = store.orderCoffee("american");
System.out.println(coffee.getName());
}
}
工厂 (factory) 处理创建对象的细节,一旦有了 SimpleCoffeeFactory
,CoffeeStore 类中的 orderCoffee()
就变成此对象的客户,后期如果需要 Coffee 对象直接从工厂中获取即可。这样也就解除了和 Coffee 实现类的耦合,但同时又产生了新的耦合,CoffeeStore 对象和SimpleCoffeeFactory 工厂对象的耦合,工厂对象和商品对象的耦合。后期如果再加新品种的咖啡,我们势必要需求修改SimpleCoffeeFactory 的代码,违反了开闭原则。工厂类的客户端可能有很多,比如创建美团外卖等,这样只需要修改工厂类的代码,省去其他的修改操作。
静态工厂:在开发中也有一部分人将工厂类中的创建对象的功能定义为静态的,这个就是静态工厂模式,它不是 23 种设计模式中的。代码如下:
public class SimpleCoffeeFactory {
public static Coffee createCoffee(String type) {
Coffee coffee = null;
if("americano".equals(type)) {
coffee = new AmericanoCoffee();
} else if("latte".equals(type)) {
coffee = new LatteCoffee();
}
return coffe;
}
}
工厂方法模式 (Factory Method Pattern) 是一种创建型设计模式,它定义了一个用于创建对象的接口,但将具体的对象创建推迟到子类中进行。在工厂方法模式中,我们通过定义一个抽象工厂类(通常是一个接口),其中包含一个创建对象的抽象方法。具体的对象创建则由实现了抽象工厂类的具体工厂类来完成,每个具体工厂类负责实例化一种具体的对象。这样就将对象的创建和使用分离开来,便于系统的扩展和解耦。
工厂方法模式的主要角色:
CoffeeFactory.java
//抽象工厂,提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品
public interface CoffeeFactory {
//生产咖啡
Coffee createCoffee();
}
AmericanCoffeeFactory.java
//具体工厂:生产美式咖啡
public class AmericanCoffeeFactory implements CoffeeFactory{
@Override
public Coffee createCoffee() {
return new AmericanCoffee();
}
}
LatteCoffeeFactory.java
//具体工厂:生产拿铁咖啡
public class LatteCoffeeFactory implements CoffeeFactory{
@Override
public Coffee createCoffee() {
return new LatteCoffee();
}
}
CoffeeStore.java
//咖啡店
public class CoffeeStore {
//创建咖啡工厂
private CoffeeFactory factory;
public void setFactory(CoffeeFactory factory) {
this.factory = factory;
}
//点咖啡功能
public Coffee orderCoffee() {
Coffee coffee = factory.createCoffee();
//加配料
coffee.addMilk();
coffee.addSugar();
return coffee;
}
}
Client.java
public class Client {
public static void main(String[] args) {
//创建咖啡店对象
CoffeeStore coffeeStore = new CoffeeStore();
//创建具体的咖啡店工厂
CoffeeFactory factory = new AmericanCoffeeFactory();
//CoffeeFactory factory = new LatteCoffeeFactory();
coffeeStore.setFactory(factory);
//点咖啡
Coffee coffee = coffeeStore.orderCoffee();
System.out.println(coffee.getName());
}
}
从以上的编写的代码可以看到,要增加产品类时也要相应地增加工厂类,不需要修改工厂类的代码了,这样就解决了简单工厂模式的缺点。工厂方法模式是简单工厂模式的进一步抽象。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且也克服了其缺点。
(1)优点
(2)缺点
(1)工厂方法模式适用于以下应用场景:
(2)总而言之,工厂方法模式适用于需要根据不同条件创建不同对象、需要动态添加新产品、隐藏对象创建细节或进行依赖注入的场景。