第2章 工厂方法模式
2.1 关于工厂方法模式
工厂模式在Java种是比较常用的一种创建型设计模式。
工厂模式创建对象时对外界暴露接口隐藏创建对象的细节。
2.2 我们来举个例子
说起了工厂,我们第一想到的是,肯定是造东西用的吧。
现在有一个食物售卖机,有热狗、汉堡包、炸鸡腿三种快餐供选择。 现有老八前来买它想念依旧的食物。
用户只需要知道有什么,点击自己想要的把信息告诉机器,
机器则给我们调配出我们所要的东西。而我们只需知道这样调用、
不需要知道在售卖机内部到底发生了什么。
抽象类(食物) 个体类(热狗、汉堡包、炸鸡腿) 工厂(售卖机) 客户端(顾客)
2.3 我们先来试着编写代码吧
-
类图
-
Food.java
public abstract class Food {
protected String name;
protected float price;
public String getName(){
return name;
}
public float getPrice(){
return price;
}
}
- FriedChicken.java
public class FriedChicken extends Food {
public FriedChicken(){
this.name="炸鸡腿";
this.price=4.3f;
}
}
- Hamburger.java
public class Hamburger extends Food {
public Hamburger(){
this.name="汉堡包";
this.price=3.3f;
}
}
- HotDog.java
public class HotDog extends Food {
public HotDog(){
this.name="热狗";
this.price=2.3f;
}
}
- Main.java
public class Main {
public static void out(Food[] foods){
for(int i=0;i<foods.length;i++){
System.out.println(String.format("名称 %s 价格 %f",foods[i].getName(),foods[i].getPrice()));
}
}
public static void main(String[] args) {
//现在有一个顾客购买汉堡包、炸鸡
Food hotDog=new HotDog();
Food friedChicken=new FriedChicken();
out(new Food[]{hotDog,friedChicken});
}
}
- 运行结果
名称 热狗 价格 2.300000
名称 炸鸡腿 价格 4.300000
可见我们的顾客直接与各个实体类打交道,我们并没有在创建实体类时隐藏细节。
2.4 进行改进
-
在Main客户与各种食物之间放置工厂,客户使用工厂,工厂负责调度创建哪些实体。
-
类图
-
Main.java
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void out(Food[] foods){
for(int i=0;i<foods.length;i++){
System.out.println(String.format("名称 %s 价格 %f",foods[i].getName(),foods[i].getPrice()));
}
}
public static void main(String[] args) {
//创建工厂
FoodFactory foodFactory=new FoodFactoryImpl();
//现在有一个顾客购买汉堡包、炸鸡
Food hotDog=foodFactory.getFood("汉堡包");
Food friedChicken=foodFactory.getFood("炸鸡腿");
out(new Food[]{hotDog,friedChicken});
//批量生产
List<String> names=new ArrayList<>();
names.add("汉堡包");names.add("炸鸡腿");names.add("热狗");names.add("热狗");
List<Food> foods=foodFactory.getFoods(names);
System.out.println("批量生产");
for(Food food:foods){
System.out.println(String.format("名称 %s 价格 %f",food.getName(),food.getPrice()));
}
}
}
- Food.java
public abstract class Food {
protected String name;
protected float price;
public void setName(String name){
this.name=name;
}
public void setPrice(float price){
this.price=price;
}
public String getName(){
return name;
}
public float getPrice(){
return price;
}
}
- FriedChicken.java
public class FriedChicken extends Food {
public FriedChicken(float price){
setName("炸鸡腿");
setPrice(price);
}
}
- Hamburger.java
public class Hamburger extends Food {
public Hamburger(float price){
setName("汉堡包");
setPrice(price);
}
}
- HotDog.java
public class HotDog extends Food {
public HotDog(float price){
setName("热狗");
setPrice(price);
}
}
- FoodFactory.java
import java.util.*;
public interface FoodFactory {
public Food getFood(String name);
public List<Food> getFoods(List<String> names);
}
- FoodFactoryImpl.java
import java.util.ArrayList;
import java.util.List;
public class FoodFactoryImpl implements FoodFactory{
private final float hamburgerPrice=2.3f;
private final float hotdogPrice=3.4f;
private final float friedChickenPrice=4.3f;
@Override
public Food getFood(String name) {
Food food=null;
if(name.equals("汉堡包")){
food=new Hamburger(hamburgerPrice);
}else if(name.equals("炸鸡腿")){
food=new FriedChicken(friedChickenPrice);
}else if(name.equals("热狗")){
food=new FriedChicken(hotdogPrice);
}
return food;
}
@Override
public List<Food> getFoods(List<String> names) {
List<Food> foods=new ArrayList<>();
for(int i=0;i<names.size();i++){
foods.add(getFood(names.get(i)));
}
return foods;
}
}
- 运行结果
名称 汉堡包 价格 2.300000
名称 炸鸡腿 价格 4.300000
批量生产
名称 汉堡包 价格 2.300000
名称 炸鸡腿 价格 4.300000
名称 炸鸡腿 价格 3.400000
名称 炸鸡腿 价格 3.400000
可见、我们解耦了各种食物类与Main,Main不再需要直接创建食物对象,而是由工厂来进行,
大部分的细节我们隐藏到了工厂内部。可以看见,
我们把各种食物的价格设置功能提到了抽象类里面,而且当我们修改价格时,
直接去工厂类里面修改就好了。我们增加一些食物时,
我们也能很快的有规律的对我们的程序添加内容。
2.5 总结
当在不同情况下实例化不同的对象时,我们建立工厂接口提供外界服务。
工厂实例内部提供创建这些对象的细节,工厂返回的是抽象类的子类。
避免了用户与所创建的大量类的创建交互。