类图+案例+代码详解:软件设计模式----简单工厂方法、工厂方法、抽象工厂方法
1、简单工厂方法
只一个具体的创建者类,包含一个静态的工厂方法,在该方法中根据传过来的参数(所要创建的产品类型),用条件语句进行判断来创建相应的对象。有一个产品接口(一种产品,例如保险),具体产品(同种产品不种类型的,例如意外保险、事故保险等)实现产品接口。创建类的接口与产品接口通过客户(<---client--->)进行连接。
因此,当增加具体产品时,需要修改工厂方法的判断语句,违背了开闭原则。
核心思想:找一个 “工厂” 帮你生产东西,你不用关心怎么做,只说要什么
比如你去快餐店买汉堡:
-
你不用自己揉面、煎肉饼、组装汉堡,只需要告诉点餐机 “我要牛肉堡” 或 “鸡肉堡”;
-
点餐机(工厂)会根据你的需求,偷偷安排后厨(具体生产逻辑)做出对应的汉堡,然后交给你。
用生活案例拆解核心角色:
-
工厂(点餐机):
-
负责接收 “需求”,决定创建哪种 “产品”。
-
隐藏了具体产品的制作细节,对你来说是个 “黑盒子”。
-
-
产品(汉堡):
-
所有汉堡都有共同特点(比如 “有面包、夹肉”),但具体类型不同(牛肉堡、鸡肉堡)。
-
-
具体产品(牛肉堡、鸡肉堡):
-
每种汉堡的制作方式不同,但都属于 “汉堡” 家族。
-
代码思维:用 “if-else” 判断造什么对象
假设你要写一个 “动物创建” 的程序:
// 1. 定义产品接口(动物)
interface Animal {void makeSound();
}
// 2. 具体产品类(狗、猫)
class Dog implements Animal {@Overridepublic void makeSound() {System.out.println("汪汪!");}
}
class Cat implements Animal {@Overridepublic void makeSound() {System.out.println("喵喵!");}
}
// 3. 简单工厂类
class AnimalFactory {public static Animal createAnimal(String type) {if ("dog".equalsIgnoreCase(type)) {return new Dog();} else if ("cat".equalsIgnoreCase(type)) {return new Cat();}throw new IllegalArgumentException("不支持的动物类型: " + type);}
}
// 4. 客户端使用
public class Main {public static void main(String[] args) {// 通过工厂创建对象,无需直接newAnimal dog = AnimalFactory.createAnimal("dog");Animal cat = AnimalFactory.createAnimal("cat");dog.makeSound(); // 输出: 汪汪!cat.makeSound(); // 输出: 喵喵!}
}
简单工厂的优缺点:
-
优点:
-
你不用关心对象怎么造的,只管用,减少了代码复杂度。
-
比如新增 “猪” 动物时,只需要改工厂的 if-else,客户端代码不用变。
-
-
缺点:
-
工厂像个 “大管家”,如果产品太多(比如 100 种动物),工厂的 if-else 会巨长无比,难以维护。
-
这也是为什么有 “工厂方法模式” 和 “抽象工厂模式” 来优化它。
-
2、工厂方法
有一个创建类的接口,具体的创建类实现这个接口,每个具体的创建类只负责创建相应的具体产品。有一个产品接口(一种产品,例如保险),具体产品(同种产品不种类型的,例如意外保险、事故保险等)实现产品接口。创建类的接口与产品接口通过客户(<---client--->)进行连接。
但是,当有多种产品时,若为每种产品都创建一个创建类的接口,过于麻烦,所以有了抽象工厂方法。
也就是一个Creator对应一个Product,有多个Product则需要多个Creator。
核心思想:把 “造东西” 的权力下放给子类,每个分店自己决定怎么造
对比简单工厂(只有一个中央厨房):
-
工厂方法模式像 “连锁快餐品牌”(比如麦当劳):
-
总部(抽象工厂)规定 “必须卖汉堡”,但每个分店(具体工厂)可以自己决定卖 “北京分店限定汉堡” 还是 “上海分店限定汉堡”。
-
你去哪家分店,就拿到哪家的汉堡,总部不插手具体制作。
-
用生活案例拆解核心角色:
-
抽象工厂(快餐品牌总部):
-
定义 “创建产品” 的抽象方法(比如
createHamburger()
),但不具体实现。 -
相当于规定 “每个分店必须能做汉堡”。
-
-
具体工厂(北京分店、上海分店):
-
各自实现
createHamburger()
方法,决定做什么汉堡。 -
比如北京分店做 “北京烤鸭堡”,上海分店做 “生煎牛肉堡”。
-
-
抽象产品(汉堡):
-
定义所有汉堡的共同特征(比如
eat()
方法)。
-
-
具体产品(北京烤鸭堡、生煎牛肉堡):
-
每个分店的汉堡有自己的实现方式。
-
代码思维:用 “抽象类 + 子类” 替代简单工厂的 if-else
用 Java 实现 “动物工厂” 案例:
// 1. 抽象产品:定义动物共同行为
interface Animal {void makeSound();
}
// 2. 具体产品
class Dog implements Animal {@Override public void makeSound() { System.out.println("汪汪!"); }
}
class Cat implements Animal {@Override public void makeSound() { System.out.println("喵喵!"); }
}
// 新增产品:比如猪
class Pig implements Animal {@Override public void makeSound() { System.out.println("哼哼!"); }
}
// 3. 抽象工厂:定义创建动物的方法,但不实现
abstract class AnimalFactory {public abstract Animal createAnimal();
}
// 4. 具体工厂:各自决定创建什么动物
class DogFactory extends AnimalFactory {@Override public Animal createAnimal() { return new Dog(); }
}
class CatFactory extends AnimalFactory {@Override public Animal createAnimal() { return new Cat(); }
}
// 新增工厂:猪工厂
class PigFactory extends AnimalFactory {@Override public Animal createAnimal() { return new Pig(); }
}
// 5. 客户端使用:选哪个工厂,就造哪种动物
public class Main {public static void main(String[] args) {// 想创建狗?找狗工厂AnimalFactory dogFactory = new DogFactory();Animal dog = dogFactory.createAnimal();dog.makeSound(); // 输出:汪汪!// 想创建猪?新增猪工厂即可,无需修改原有代码AnimalFactory pigFactory = new PigFactory();Animal pig = pigFactory.createAnimal();pig.makeSound(); // 输出:哼哼!}
}
工厂方法对比简单工厂:
模式 | 核心区别 | 优缺点 |
---|---|---|
简单工厂 | 一个工厂用 if-else 判断所有产品 | 简单,但新增产品需改工厂代码 |
工厂方法 | 每个产品对应一个工厂子类 | 新增产品只需新增工厂,符合开闭原则 |
工厂方法的优缺点:
-
优点:
-
新增产品时,只需新增对应的工厂子类,无需修改原有代码(开闭原则)。
-
比如新增 “鸟” 动物,只需要写
Bird
类和BirdFactory
类,其他代码不用动。
-
-
缺点:
-
如果产品种类太多(比如 100 种动物),会导致工厂子类数量爆炸(100 个工厂类)。
-
3、抽象工厂方法
与工厂方法的区别是,有多个Product(多个产品系列)时,抽象工厂方法的Creator负责创建所有的Product。
但是,当增加Product时,需要对Creator进行修改,此时违背了开闭原则。
核心思想:造 “一家人” 而不是 “一个人”—— 批量生产相关联的产品家族
比如你要开一家家具厂:
-
简单工厂 / 工厂方法只能造 “沙发” 或 “椅子” 单个产品
-
抽象工厂能造 “北欧风沙发 + 北欧风椅子 + 北欧风茶几” 一整套家具 (每个风格就是一个 “产品家族”,工厂负责造一整套)
用生活案例拆解核心角色:
-
抽象工厂(家具工厂总部):
-
定义 “创建一整套家具” 的方法(比如
createSofa()
、createChair()
),但不具体实现。 -
相当于规定 “工厂必须能造沙发和椅子”。
-
-
具体工厂(北欧风工厂、中式工厂):
-
实现抽象工厂的方法,决定每个家具的具体样式。
-
北欧工厂造 “极简沙发 + 原木椅子”,中式工厂造 “红木沙发 + 雕花椅子”。
-
-
抽象产品(沙发、椅子):
-
定义同类产品的共同特征(比如
Sofa
接口有use()
方法)。
-
-
具体产品(北欧沙发、中式沙发、北欧椅子、中式椅子):
-
每个工厂的产品属于同一系列(风格统一)。
-
代码思维:用 “工厂接口” 生产 “多个产品接口” 的实现类
用 Java 实现 “家具工厂” 案例:
// 1. 抽象产品1:沙发
interface Sofa {void use(); // 使用沙发
}
class NordicSofa implements Sofa {@Override public void use() { System.out.println("坐北欧风极简沙发"); }
}
class ChineseSofa implements Sofa {@Override public void use() { System.out.println("坐中式红木沙发"); }
}
// 2. 抽象产品2:椅子
interface Chair {void sit(); // 坐椅子
}
class NordicChair implements Chair {@Override public void sit() { System.out.println("坐北欧风原木椅子"); }
}
class ChineseChair implements Chair {@Override public void sit() { System.out.println("坐中式雕花椅子"); }
}
// 3. 抽象工厂:定义创建一整套家具的方法
interface FurnitureFactory {Sofa createSofa(); // 创建沙发Chair createChair(); // 创建椅子
}
// 4. 具体工厂1:北欧风格工厂
class NordicFactory implements FurnitureFactory {@Overridepublic Sofa createSofa() { return new NordicSofa(); }@Overridepublic Chair createChair() { return new NordicChair(); }
}
// 5. 具体工厂2:中式风格工厂
class ChineseFactory implements FurnitureFactory {@Overridepublic Sofa createSofa() { return new ChineseSofa(); }@Overridepublic Chair createChair() { return new ChineseChair(); }
}
// 6. 客户端使用:选工厂=选风格,直接拿一整套家具
public class Main {public static void main(String[] args) {// 想要北欧风家具?FurnitureFactory nordicFactory = new NordicFactory();Sofa nordicSofa = nordicFactory.createSofa();Chair nordicChair = nordicFactory.createChair();nordicSofa.use(); // 输出:坐北欧风极简沙发nordicChair.sit(); // 输出:坐北欧风原木椅子// 想要中式风家具?换个工厂即可FurnitureFactory chineseFactory = new ChineseFactory();chineseFactory.createSofa().use(); // 坐中式红木沙发chineseFactory.createChair().sit(); // 坐中式雕花椅子}
}
抽象工厂对比工厂方法:
模式 | 生产能力 | 适用场景 |
---|---|---|
工厂方法 | 生产单个产品(如一把椅子) | 产品种类多,但每个产品独立生产 |
抽象工厂 | 生产成套产品(椅子 + 沙发) | 产品需成系列(风格 / 品牌统一) |
抽象工厂的优缺点:
-
优点:
-
保证同一系列产品的风格统一(比如北欧工厂绝不会造出中式沙发)。
-
新增产品系列时(如日式家具),只需新增工厂和产品类,不修改原有代码(开闭原则)。
-
-
缺点:
-
新增单个产品(如 “茶几”)需要修改所有工厂接口和实现类,违反开闭原则。 (比如抽象工厂要新增
createTable()
方法,所有具体工厂都要实现)
-
总结
简单工厂:一个工厂造所有东西(用 if-else)
工厂方法:每个产品有专属工厂(分权给子类)
抽象工厂:一个工厂造一整套东西(家族化生产)