【设计模式系列】(二) 工厂模式
问题描述
需求:现在要设计一个鸡店点餐系统。先设计一个鸡类(Chicken)、在设计两个子类黄焖鸡【YellowChicken】以及大盘鸡【BigChicken】、在设计一个鸡店类【ChickenStore】具有点鸡功能。
原型图如下:
实现代码如下:
- Chicken
public abstract class Chicken {
public abstract String getName();
public void addSolt(){
System.out.println("加糖");
}
public void addSugar(){
System.out.println("加盐");
}
public void addMoney(){
System.out.println("得加钱");
}
}
- BigChicken
public class BigChicken extends Chicken{
@Override
public String getName() {
return "大盘鸡";
}
}
- YellowChicken
public class YellowChicken extends Chicken{
@Override
public String getName() {
return "黄焖鸡";
}
}
假如我们要去更换对象、就需要去重新去进行new、这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象、就和工厂打交道就可以了、彻底和对象进行解耦、更换对象在工厂里更换对象即可、达到和对象解耦的目的。
按照实际的业务划分、工厂模式分为三种:简单工厂模式、工厂方法模式、抽象工厂模式。
简单工厂模式
概述
简单工厂不是一种设计模式、一般我们把创建对象的叫做产品、创建产品的对象叫做工厂、如果只是创建的产品不多、只需要一个工厂类即可完成、叫做简单狗工厂模式。
在简单工厂模式中创建实例的方法通常为静态方法、因此简单工厂模式又称为静态工厂模式(Static Factory Method Pattern)
需要注意:简单工厂模式不属于23中设计模式之列。
结构
具体实现流程:先去创建Product接口、在去创建 ShowProductA、ShowProductB类去实现 Product 接口、通过 SimpleFactory 来去调用产品的实现。
- Product
public interface Product {
// 秀产品
public void show();
}
- ShowProductA
public class ShowProductA implements Product{
@Override
public void show() {
System.out.println("我是A");
}
}
- SimpleFactory
/**
* @ClassName: SimpleFactory
* @Author: VV
* @Version: 1.0.0
* @Description: TODO
* @MyEmail: vv1213418894@163.com
* @CreateTime: 2022-08-26 15:01:41
*/
public abstract class SimpleFactory implements Product {
public static Product showProduct(String name){
if(name.equals("A")){
return new ShowProductA();
}else if(name.equals("B")){
return new ShowProductB();
}else{
throw new RuntimeException("没有当前产品");
}
}
}
现在在以改进后的鸡店为例、进行讲解。
- Chicken
public abstract class Chicken {
public abstract String getName();
public void addSolt(){
System.out.println("加糖");
}
public void addSugar(){
System.out.println("加盐");
}
public void addMoney(){
System.out.println("得加钱");
}
}
- BigChicken
public class BigChicken extends Chicken{
@Override
public String getName() {
return "大盘鸡";
}
}
- YellowChicken
public class YellowChicken extends Chicken{
@Override
public String getName() {
return "黄焖鸡";
}
}
- SimpleChickenFactory
public class SimpleChickenFactory {
/**
* 生成 chicken 类
* @param type
* @return 返回完成的 Chicken
*/
public Chicken orderChicken(String type){
Chicken chicken = null;
if(type.equals("YellowChicken")){
chicken = new YellowChicken();
}else if(type.equals("BigChicken")){
chicken = new BigChicken();
}else {
throw new RuntimeException("对不起、此鸡不在服务范围之内... ");
}
return chicken;
}
}
- ChickenStore
/**
* @ClassName: ChickenStore
* @Author: VV
* @Version: 1.0.0
* @Description: TODO
* @MyEmail: vv1213418894@163.com
* @CreateTime: 2022-08-26 15:28:28
*/
public class ChickenStore {
public Chicken orderChicken(String type){
// 从简单鸡厂获取鸡
SimpleChickenFactory simpleChickenFactory = new SimpleChickenFactory();
// 生产鸡
Chicken chicken = simpleChickenFactory.orderChicken(type);
// 自己加料
chicken.addSugar();
chicken.addSolt();
chicken.addMoney();
// 返回
return chicken;
}
}
后期要去点鸡、只要去 SimpleChickenFactory 去点鸡就行、但是产生了新的耦合、ChickenStore 与 SimpleChickenFactory 的耦合、工厂与产品的耦合。如果要去添加新的鸡种类、必定需要修改工厂、违法了开闭原则。
优缺点
优点:
- 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
- 客户端无需知道所创建具体产品的类名,只需知道参数即可。
缺点: - 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
- 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度。
- 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂。
- 简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。
- 增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。
工厂方法模式
概述
针对工厂模式的缺点(引入新产品、必须修改工厂类代码、违反开闭原则),使用工厂模式就可以解决问题、可以在不修改原来代码的情况下引进新的产品。
结构
1、抽象工厂:提供了创建产品的接口、调用者访问具体工厂产品的创建。
2、具体工厂:实现抽象工厂方法、完成具体产品的创建。
3、抽象产品:定义了产品的规范、描述产品主要特性及功能
4、具体产品:实现了抽象产品所定义的方法、由具体工厂来创建。
- Product
public abstract class Product {
public abstract void show();
}
- ShowProductA
public class ShowProductA extends Product{
@Override
public void show() {
System.out.println("产品A");
}
}
- ShowProductB
public class ShowProductB extends Product{
@Override
public void show() {
System.out.println("产品B");
}
}
- SimpleFactory
public interface SimpleFactory {
public Product createProduct();
}
- SimpleFactoryA
public class SimpleFactoryA implements SimpleFactory{
@Override
public Product createProduct() {
return new ShowProductA();
}
}
- SimpleFactoryB
public class SimpleFactoryB implements SimpleFactory{
@Override
public Product createProduct() {
return new ShowProductB();
}
}
- Client
/**
* @ClassName: Client
* @Author: VV
* @Version: 1.0.0
* @Description: TODO
* @MyEmail: vv1213418894@163.com
* @CreateTime: 2022-08-26 16:28:32
*/
public class Client {
public static void main(String[] args) {
// A 工厂生产 A 产品
SimpleFactory simpleFactoryA = new SimpleFactoryA();
Product product = simpleFactoryA.createProduct();
// B 工厂生产 B 产品
SimpleFactoryB simpleFactoryB = new SimpleFactoryB();
Product product1 = simpleFactoryB.createProduct();
// 开始秀
product.show();
product1.show();
}
}
现在在以改进后的鸡店为例、进行讲解。(画了半天、还是GG了)
- Chicken
public abstract class Chicken extends Client {
public abstract String getName();
public void addSolt(){
System.out.println("加盐");
}
public void addSugar(){
System.out.println("加糖");
}
public void addMoney(){
System.out.println("加钱");
}
}
- BigChicken
public class BigChicken extends Chicken{
@Override
public String getName() {
return "大盘鸡";
}
}
- YellowChicken
public class YellowChicken extends Chicken{
@Override
public String getName() {
return "黄焖鸡";
}
}
- ChickenFactory
public interface ChickenFactory {
public Chicken createChicken();
}
- BigChickenFactory
public class BigChickenFactory implements ChickenFactory{
@Override
public Chicken createChicken() {
return new BigChicken();
}
}
- YellowChickenFactory
public class YellowChickenFactory implements ChickenFactory{
@Override
public Chicken createChicken() {
return new YellowChicken();
}
}
- Client
public class Client {
public static void main(String[] args) {
// 开始创建产品、大盘鸡
BigChickenFactory bigChickenFactory = new BigChickenFactory();
Chicken chicken = bigChickenFactory.createChicken();
chicken.getName();
// 黄焖鸡
YellowChickenFactory yellowChickenFactory = new YellowChickenFactory();
Chicken chicken1 = yellowChickenFactory.createChicken();
chicken1.getName();
}
}
优点:
- 用户只需要知道工厂名称即可、无需知道产品的创建过程。
- 灵活性增强、对于新产品、只需要多写一个相应的工厂类。
- 典型的解耦框架、高层模块只需要知道产品的抽象类、无需关系其他实现类、满足迪米特法则、依赖倒置原则和里氏替换原则。
缺点:
- 类的个数容易过多、增加复杂度。
- 增加系统抽象性和理解难度
- 工厂模式只能生产一种产品、可以使用抽象工厂模式解决。
抽象工厂
概述
前面介绍这么多、都是去生产跟鸡相关的产品、但是现实生活中也不能天天去吃鸡、得换换口味、比如鸭、牛、猪等。但是鸡场只能产鸡、想要吃其他就要开其他厂子。
这些工厂只生产同种类产品,同种类产品称为同等级产品,也就是说:工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如电器厂既生产电视机又生产洗衣机或空调,大学既有软件专业又有生物专业等。
接下来介绍的是抽象工厂模式、将要考虑多等级多产品的生产。
结构
抽象工厂有以下几个角色:
- 抽象工厂:提供了创建产品的接口、包含多个创建产品的方法、可以创建多个不同等级的产品。
- 具体工厂:主要实现抽线工厂的多个抽象方法、完成具体产品的创建。
- 抽象产品:定义了产品的规范、描述了产品的主要特性和功能、抽象工厂有多个抽象产品。
- 具体产能:实现了抽象产品角色定义的接口、由具体工厂来创建、它同具体工厂是一对多的关系。
- ProductA
public abstract class ProductA {
public abstract void show();
}
- ProductB
public abstract class ProductB {
public abstract void show();
}
- ShowProductA1
public class ShowProductA1 extends ProductA{
@Override
public void show() {
System.out.println("这是 A 系列 1 号产品");
}
}
- ShowProductA2
public class ShowProductA2 extends ProductA{
@Override
public void show() {
System.out.println("这是 A 系列 2 号产品");
}
}
- ShowProductB1
public class ShowProductB1 extends ProductB{
@Override
public void show() {
System.out.println("这是 B 系列 1 号产品");
}
}
- ShowProductB2
public class ShowProductB2 extends ProductB{
@Override
public void show() {
System.out.println("这是 B 系列 2 号产品");
}
}
- ProductFactory
public interface ProductFactory {
public ProductA createProductA();
public ProductB createProductB();
}
- Factory01
public class Factory01 implements ProductFactory{
@Override
public ProductA createProductA() {
return new ShowProductA1();
}
@Override
public ProductB createProductB() {
return new ShowProductB1();
}
}
- Factory02
public class Factory02 implements ProductFactory{
@Override
public ProductA createProductA() {
return new ShowProductA2();
}
@Override
public ProductB createProductB() {
return new ShowProductB2();
}
}
改进后的程序为了便于理解、我们不在以做鸡为例、以电子厂为例、比较好描述、做鸡做鸭同理。
电子厂可以做手机、平板、电脑、但是会有不同的品牌、就是产品族的问题。
- Phone
public abstract class Phone {
// 呼叫
public abstract void call();
// 充话费
public abstract void addMoney();
}
- TabletPC
public abstract class TabletPC {
// 看电视
public abstract void watchTV();
// 游戏
public abstract void playGame();
}
-Computer
public abstract class Computer {
// 敲代码
public abstract void code();
// 玩虚拟机
public abstract void playLinux();
}
- ApplePhone
public class ApplePhone extends Phone{
@Override
public void call() {
System.out.println("打电话");
}
@Override
public void addMoney() {
System.out.println("充话费");
}
}
- HuaWeiPhone
public class HuaWeiPhone extends Phone{
@Override
public void call() {
System.out.println("打电话");
}
@Override
public void addMoney() {
System.out.println("充话费");
}
}
-Ipad
public class Ipad extends TabletPC{
@Override
public void watchTV() {
System.out.println("看剧");
}
@Override
public void playGame() {
System.out.println("玩游戏");
}
}
- HuaWeiPad
public class HuaWeiPad extends TabletPC{
@Override
public void watchTV() {
System.out.println("看电视");
}
@Override
public void playGame() {
System.out.println("玩游戏");
}
}
- MacBookPro
public class MacBookPro extends Computer{
@Override
public void code() {
System.out.println("敲代码");
}
@Override
public void playLinux() {
System.out.println("虚拟机");
}
}
- MateBookPro
public class MateBookPro extends Computer{
@Override
public void code() {
System.out.println("敲代码");
}
@Override
public void playLinux() {
System.out.println("虚拟机");
}
}
- ElectronicsFactory
public interface ElectronicsFactory {
public Phone createPhone();
public TabletPC createTabletPC();
public Computer createComputer();
}
- AppleFactory
public class AppleFactory implements ElectronicsFactory{
@Override
public Phone createPhone() {
return new ApplePhone();
}
@Override
public TabletPC createTabletPC() {
return new Ipad();
}
@Override
public Computer createComputer() {
return new MacBookPro();
}
}
- HuaWeiFactory
public class HuaWeiFactory implements ElectronicsFactory{
@Override
public Phone createPhone() {
return new HuaWeiPhone();
}
@Override
public TabletPC createTabletPC() {
return new HuaWeiPad();
}
@Override
public Computer createComputer() {
return new MateBookPro();
}
}
优点
抽象工厂模式除了具有工厂方法模式的优点外,其他主要优点如下。
- 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。(即同一个工厂类中可以生产不同的产品,它们属于不同等级,但不必要使用多个类来管理。)
- 当需要产品族时,抽象工厂可以保证客户端始终只使用同一个产品的产品族。
- 抽象工厂增强了程序的可扩展性,当增加一个新的产品族时,不需要修改原代码,满足开闭原则。(当需要增加新的产品族时,只需要继承抽象类,自定义实现即可,不需要修改源代码。)
缺点
- 当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。增加了系统的抽象性和理解难度。(虽然增加产品族很容易,但是增加新产品却不容易了,因为产品是由工厂生产,所以必须修改所有的工厂类。)