“工厂方法模式”是对“简单工厂模式”的进一步抽象化。
好处:使系统在不修改原来代码情况下引进新产品,满足开闭原则。(在改进的案例中会体现)
结构:
抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法(创建产品的方法)来创建产品。
具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
应用:我们通过改进“点咖啡”案例,来体会“工厂方法模式”和“简单工厂模式”之间的联系和不同。
分析:工厂方法模式在结构上相比简单工厂模式增加了抽象工厂角色,在此我们在类图中相比原来的类图,去掉简单工厂类(SimpleCoffeeFactory),新增抽象咖啡工厂接口(CoffeeFactory)及其实现类:专门生产美式咖啡的工厂(AmericanCoffeeFactory)和专门生产拿铁咖啡的工厂(LatteCoffeeFactory)。
让咖啡店类依赖抽象咖啡工厂和抽象咖啡类,这也遵循了“依赖倒转原则”。(依赖抽象,不依赖细节)
抽象咖啡类(Coffee)和具体子类美式咖啡类(AmericanCoffee)、拿铁咖啡(LatteCoffee)的代码不变,这里就不再重复了(可到简单工厂模式那篇查看代码)
1.抽象咖啡工厂类(CoffeeFactory),包含生产咖啡的抽象方法。
public interface CoffeeFactory {
//创建咖啡对象的方法
Coffee creatCoffee();
}
2.美式咖啡工厂(AmericanCoffeeFactory),实现抽象咖啡工厂类中生产咖啡的功能(直接new美式咖啡对象,然后返回),专门生产美式咖啡。
public class AmericanCoffeeFactory implements CoffeeFactory{
@Override
public Coffee creatCoffee() {
return new AmericanCoffee();
}
}
3.拿铁咖啡工厂(LatteCoffeeFactory),实现抽象咖啡工厂类中生产咖啡的功能,专门生产拿铁咖啡。
public class LatteCoffeeFactory implements CoffeeFactory{
@Override
public Coffee creatCoffee() {
return new LatteCoffee();
}
}
4.咖啡店类(CoffeeStore),里面要声明抽象咖啡工厂类型的对象,因为在客户端要传入具体的咖啡生产工厂类型的对象(所以类中也有factory对应的set方法,从而进行赋值),从而调用其对应的生产咖啡的方法。(“简单工厂模式”中不用声明,因为在简单工厂模式中,工厂类中生产咖啡的方法是静态的,直接通过类名和点运算符就可以调用生产咖啡的方法)
public class CoffeeStore {
//声明私有工厂对象
private CoffeeFactory factory;
public void setFactory(CoffeeFactory factory){
this.factory = factory;
}
//点咖啡功能
public Coffee orderCoffee(){
Coffee coffee = factory.creatCoffee();
//加配料
coffee.addMilk();
coffee.addSugar();
return coffee;
}
}
5.测试类(Client),这里我们以创建拿铁咖啡为例,如果要创建美式咖啡,只需要改变new的具体咖啡工厂对象的类型(改成new AmerianCoffeeFacory())。
public class Client {
public static void main(String[] args) {
//创建咖啡店
CoffeeStore store = new CoffeeStore();
//创建工厂对象
//CoffeeFactory factory = new AmericanCoffeeFactory();
CoffeeFactory factory = new LatteCoffeeFactory();
store.setFactory(factory);
//点咖啡
Coffee coffee = store.orderCoffee();
System.out.println(coffee.getName());
}
}
6.运行结果
总结分析:“工厂方法模式”保留了“简单工厂模式”的优点:①生产过程封装到具体工厂中,例如,拿铁咖啡在拿铁咖啡工厂中生成,生产过程对客户隐藏,客户只需告诉我们要什么样的咖啡,然后我们传入对应的工厂类型的对象。②解除了咖啡店与咖啡类的耦合(咖啡类发生变化,也不会影响咖啡店)。
解决了“简单工厂模式”的缺点:同样面对客户需求改变,简单工厂模式需要修改工厂类的代码,违背了“开闭原则”;而“工厂方法模式”只需新增具体产品类和生产新产品的具体工厂类就可以,不用修改原本的代码,遵循了“开闭原则”。
优点:
①用户只需要知道具体工厂的名称就可以得到所要的产品,无需知道产品的具体创建过程。(具体创建过程被封装到了具体工厂类中,不对用户展现细节)
②在系统增加新的产品时,只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则。
缺点:
上述优点中的第2条也引发了一个缺点,那就是:每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
应用场景:
客户只知道创建产品的工厂名,而不知道具体的产品名。
创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
客户不关心创建产品的细节,只关心产品的品牌。(和第一条意思相近)
{{ cmt.username }}
{{ cmt.content }}
{{ cmt.commentDate | formatDate('YYYY.MM.DD hh:mm') }}