
概述
需求
设计一个咖啡店点餐系统
设计一个咖啡类(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;
    }
}














![[Qt学习笔记]Qt鼠标事件mouseMoveEvent实时获取图像的坐标和像素值](https://img-blog.csdnimg.cn/img_convert/46d409e97a8ea4ad68ad7cb738ba0f0a.gif)




