设计模式之工厂模式

前言

工厂模式应该是除了单例模式被听过最多的设计模式。想当年我第一次听说单例模式是因为spring的框架,但第一次听说工厂模式是看免费培训视频。其实大多数设计模式我们都在用,但是我们并没有系统的给取名,某些人给加了名字而已。当然,也有很多设计模式我们确实没用过。我的理解设计模式是一种让我们编码的某些常用抽象行为规范化而已,不可能只存在23中设计模式,可能你正在写的就是第二十四种设计模式也不一定。

分类

常见的工厂模式有简单工厂、工厂方法和抽象工厂。

以生产汽车为例 :

简单工厂,我们可以理解为一个工厂它什么牌子汽车都生产,它一个工厂把所有的生产的活都给包了。

工厂方法,我们可以理解为一个工厂它只生产一个牌子的汽车,如果需要新增一个牌子的汽车,那么就新增一个改牌子汽车的生产工厂。

抽象工厂,我们可以理解为一个工厂它不再只生产单一的汽车产品,而是生产一个系列的产品或者产品族;比如A牌汽车工厂,不再单单生产A牌的汽车,它还可以生产A牌的汽车配套的脚垫、A牌自己的轮胎共A牌汽车使用、A牌的内饰等等。那么如果需要新增B牌呢?那就增加一个B牌的抽象工厂。

代码示例

以国产的海尔、格力、美的三个品牌为例,没广告只是不想拿国外的牌子举例。

简单工厂

现在需要生产三种品牌的冰箱,当然也可以是生产不同的产品。

#定义冰箱接口

csharp 复制代码
public interface Fridge {
   void freshness();
}

#三个品牌的冰箱实现冰箱接口

csharp 复制代码
#海尔冰箱
public class HaierFridge implements Fridge{
   @Override
   public void freshness() {
       System.out.println("我是海尔冰箱~");
  }
}
#格力冰箱
public class GreeFridge implements Fridge{
   @Override
   public void freshness() {
       System.out.println("我是格力冰箱~");
  }
}
#美的冰箱
public class MideaFridge implements Fridge{
   @Override
   public void freshness() {
       System.out.println("我是美的冰箱~");
  }
}

#定义生产三种冰箱的工厂

typescript 复制代码
public class SimpleFactory {
  public Fridge createFridge(String type) throws IllegalAccessException {
      if("Haier".equalsIgnoreCase(type)){
          return new HaierFridge();
      }else if("Gree".equalsIgnoreCase(type)){
          return new GreeFridge();
      }else if("Midea".equalsIgnoreCase(type)){
          return new MideaFridge();
      }else{
          throw new IllegalAccessException("type为非法类型!");
      }
  }
}

#使用简单工厂

ini 复制代码
   public static void main(String[] args) {
       //通常我们会使用new来创建对象,但如果想要换一种接口下的其他产品就要改代码
       MideaFridge fridge1 = new MideaFridge();
       fridge1.freshness();
       //为了解决上面的问题,我们可以通过简单工厂来实现
       SimpleFactory simpleFactory = new SimpleFactory();
       Fridge f = null;
       try {
           f =  simpleFactory.createFridge("Midea");
      } catch (IllegalAccessException e) {
           throw new RuntimeException(e);
      }
       f.freshness();
  }

工厂方法

现在还是需要生产三种品牌的冰箱,但是可能因为冰箱的制作比较复杂或者零件不一样了,总之就是需要单独的工厂来生产了。这是我们就需要使用工厂方法,当然你也可以定义不同的产品,每种产品使用一个工厂。

#定义冰箱接和三种并行的实现,通简单工厂上的代码,不再复制了

#定义工厂接口

csharp 复制代码
public interface Factory {
   Fridge createFridge();
}

#三个牌子实现工厂接口拥有自己的独立工厂实体类

typescript 复制代码
#海尔工厂
public class HaierFactory implements Factory{
   @Override
   public Fridge createFridge() {
       return new HaierFridge();
  }
}
#格力工厂
public class GreeFactory implements Factory{
   @Override
   public Fridge createFridge() {
       return new GreeFridge();
  }
}
#美的工厂
public class MideaFactory implements Factory{
   @Override
   public Fridge createFridge() {
       return new MideaFridge();
  }
}

#使用工厂方法

scss 复制代码
public static void main(String[] args) {
       //需要什么品牌的冰箱就使用什么工厂
    Fridge f = new GreeFactory().createFridge();
       f.freshness();
       Fridge f1 = new MideaFactory().createFridge();
       f1.freshness();
  }

抽象工厂

上面工厂方法我们发现一个品牌的冰箱由这个品牌的工厂生产,如果这个品牌他不止一个产品呢?比如除了冰箱还有热气灶和油烟机,那他们就是一个产品族或者我们称之为系列产品。每个品牌都能生产一个套件,这个时候就需要使用抽象工厂了。

#定义冰箱接和三种并行的实现,通简单工厂上的代码,不再复制了

#定义热气灶和油烟机的接口以及实现类

csharp 复制代码
#油烟机接口
public interface RangeHood {
   void suck();
}
public class MideaRangeHood implements RangeHood{
​
   @Override
   public void suck() {
       System.out.println("美的油烟机吸吸吸~");
  }
}
public class GreeRangeHood implements RangeHood{
​
   @Override
   public void suck() {
       System.out.println("格力油烟机吸吸吸~");
  }
}
public class HaierRangeHood implements RangeHood{
​
   @Override
   public void suck() {
       System.out.println("海尔油烟机吸吸吸~");
  }
}
#燃气灶接口
public interface GasStove {
   void fire();
}
public class MideaGastStove implements GasStove{
   @Override
   public void fire() {
       System.out.println("美的燃气灶点火~");
  }
}
public class HaierGastStove implements GasStove{
   @Override
   public void fire() {
       System.out.println("海尔燃气灶点火~");
  }
}
public class GreeGastStove implements GasStove{
   @Override
   public void fire() {
       System.out.println("格力燃气灶点火~");
  }
}

#定义抽象工厂抽象类和三个品牌的抽象工厂实现类

scala 复制代码
#抽象工厂抽象类
public abstract class AbstractFactory {
   abstract GasStove createGasStove();
​
   abstract RangeHood createRangeHood();
​
   abstract Fridge createFridge();
}
public class MideaFactory extends AbstractFactory{
   @Override
   GasStove createGasStove() {
       return new MideaGastStove();
  }
​
   @Override
   RangeHood createRangeHood() {
       return new MideaRangeHood();
  }
​
   @Override
   Fridge createFridge {
       return new MideaFridge();
  }
}
public class GreeFactory extends AbstractFactory{
   @Override
   GasStove createGasStove() {
       return new GreeGastStove();
  }
​
   @Override
   RangeHood createRangeHood() {
       return new GreeRangeHood();
  }
​
   @Override
   Fridge createFridge() {
       return new GreeFridge();
  }
}
public class HaierFactory extends AbstractFactory{
   @Override
   GasStove createGasStove() {
       return new HaierGastStove();
  }
​
   @Override
   RangeHood createRangeHood() {
       return new HaierRangeHood();
  }
​
   @Override
   Fridge createFridge() {
       return new HaierFridge();
  }
}

#使用抽象工厂

ini 复制代码
   public static void main(String[] args) {
    //当你需要一个系列产品时,直接使用对应抽象工厂实现类即可,要什么产品就调用什么产品的方法
       AbstractFactory factory = new MideaFactory();
       GasStove gasStove = factory.createGasStove();
       RangeHood rangeHood = factory.createRangeHood();
       Fridge fridge = factory.createFridge();
​
       gasStove.fire();
       fridge.freshness();
       rangeHood.suck();
  }

类图

使用类图可能可以更清晰一点看出他们的结构,为了让图更简单直观省略一些重复的属性或者方法。

简单工厂

工厂方法

抽象工厂

总结

简单工厂相对而言不灵活,主要表现在每次新增产品都要改代码。工厂方法在简单工厂基础上就更加灵活,新增一个产品对应增加相应的工厂实现类就行。而抽象工厂实际上可以看成工厂方法的升级版,它将一个工厂只能生产一个产品改成实现一个产品族或者系列产品。不要问那种设计模式好,只有合适的自己的设计模式才是最好的。另外设计模式不是越多越好,学习设计模式无非是在后续编码时,多一种编码的思路。

你说你讨厌设计模式,你觉得它没什么用?对!你说的对,设计模式是非编码必须的。可以认为设计模式是一种编码思路、模板或者规范,你不用无伤大雅。

水平一般能力有限如有错误或者纰漏,望各位大佬指正。

相关推荐
P.H. Infinity1 小时前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天1 小时前
java的threadlocal为何内存泄漏
java
caridle1 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
^velpro^1 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋31 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
秋の花1 小时前
【JAVA基础】Java集合基础
java·开发语言·windows
小松学前端1 小时前
第六章 7.0 LinkList
java·开发语言·网络
Wx-bishekaifayuan2 小时前
django电商易购系统-计算机设计毕业源码61059
java·spring boot·spring·spring cloud·django·sqlite·guava
customer082 小时前
【开源免费】基于SpringBoot+Vue.JS周边产品销售网站(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·java-ee·开源
全栈开发圈2 小时前
新书速览|Java网络爬虫精解与实践
java·开发语言·爬虫