项目中用到的设计模式-工厂模式

前言

我们项目是一个电商项目,我被分配到商品模块的开发任务。其中,涉及到创建商品这个功能,第一个版本比较简单就只有单纯的商品,我的实现也非常简单,直接new一个对象然后设置值就行。但是,后来因为业务需求,各个种类的商品,各个功能的商品逐渐加入到版本迭代中,如果还是这么简单粗暴的处理方式其实也行,但是由于不断修改原始代码增加了犯错的几率,也让测试小伙伴多次重复测试,降低效率。

这个时候,我就意识到了问题的严重性,决定重构代码。

简单工厂模式

第一个版本比较简单,具体可以看下面

public class Product{
  String name;
}

public class ProductA extends Product{
  //轮播图
  String[] imgs;
}

public class ProductB extends Product{
  //轮播视频
  String[] videos;
}

public class ProductFactory{
  pubic static Product produce(int type){
      if(type ==1) new ProductA();
    if(type ==2) new ProductB();
    return null;
  }
}

优点:

  • 这个模式优点是将各个不同商品分开,逻辑分离,老代码不做更改,新代码只需继承Product,比较容易实现

缺点:

  • 如果说我在增加一个虚拟商品(比如积分卡)/实物商品(比如手机)的维度,如果只是增加一个属性字段的话,又会陷入没有使用设计模式之前的困境(可以参考下面),会有大量重复代码,这个设计模式就没有意义

    if(type ==1){
      //重复代码
      if("纬度"== 虚拟) ...;
      if("纬度"== 实体) ...;
    }
    if(type ==2){
      if("纬度"== 虚拟) ...;
      if("纬度"== 实体) ...;
    }
    

工厂方法模式

如果增加了维度我们该怎么办?

简单,我们可以对工厂抽象一层分为实体工厂/虚拟工厂专门用来处理维度属性,具体实现如下:

//商品基类
public class Product{
  String name;
}
//虚拟商品
public class ProductXuni extends Product{
  //轮播图
  String[] imgs;
}
//实体商品
public class ProductShiti extends Product{
  //轮播视频
  String[] videos;
}
//生产不同商品的工厂的抽象类
public interface AbstractFactory{
  Product produce();
}
//虚拟工厂
public class XuniFactory implements AbstractFactory{
  Product produce(){
    return new ProductXuni();
  }
}
//实体工厂
public class ShitiFactory implements AbstractFactory{
  Product produce(){
    return new ProductShiti();
  }
}
//这样省略了大量的重复代码
public class Demo {
    public static void main(String[] arg) {
        AbstractFactory xuniF = new XuniFactory();
        AbstractFactory shitiF = new ShitiFactory();
        xuniF.produce(); //虚拟商品
        shitiF.produce(); //实体商品
    }
}

这样看来,好像是完美的解决了目前的问题。但是,产品经理的需求是不断进化的。他又提出一个需求,我们现在创建的都是商品(这里特指自己平台的),下个版本要将我们的商品、赠品、地推物料、三方商品...这个几个分类全部整合到一起。

SHIT!!!

抽象工厂模式

没办法,生活还要继续。上面的模式生产的都是一类产品,虽然分成多个维度但是还是属于商品这一个大类下面,如果想新建一个分类(比如:地推物料、淘宝商品、京东商品…)最简单粗暴的方式就是每一个分类就将上面的工厂方法复制一份(实际上前两次我就是这么干的😄),但是会带来大量重复代码—cv是真的爽

于是,我决定采用抽象工厂方法将代码进行重构,具体实现如下:

public interface Item {
    Item produce();
}
//商品
public class Product implements Item{
        public Product() {
        produce();
    }
    public Item produce(){
      return new Product();
    }
}
//淘宝商品
public class TBProduct implements Item{
    public TBProduct() {
        produce();
    }
        public Item produce(){
      return new TBProduct();
    }
}
//抽象工厂
public interface AbstractFactory{
        Item produce();
}
//商品工厂
public class ProductFactory implements AbstractFactory(){
  public Product produce() {
          return new Product();
  }
}
//淘宝商品工厂
public class TBProductFactory implements AbstractFactory(){
  public TBProduct produce() {
          return new TBProduct();
  }
}

public class Client {
   public static void main(String[] args) {
     //生产商品
     AbstractFactory productF = new ProductFactory();
     Product keyboard = productF.produce();
   
          //生产淘宝商品
     AbstractFactory tabaoF = new TBProductFactory();
     TBProduct keyboard = tabaoF.produce();
   }
}

咋看一下好像解决了问题,我们以后增加JD商品的时候只需要在增加一个工厂,一个产品就行了。但是,有个问题。比如说,我想要在淘宝工厂方法里面在增加一个动作,叫destroy()。那么,所有的工厂都会重写这个方法,改动非常之大。这个问题,也是抽象工厂模式的缺陷。对此,我又增加了一层抽像来解决这个问题,具体如下:

//抽象工厂
public interface AbstractFactory{
        Item produce();
    Item destroy();
}
//抽象工厂基础类
public abstract class BaseAbstractFactory implements AbstractFactory{
        public Item produce() {
        return null;
    }
      //默认实现
      public Item destroy() {
        return null;
    }
}
//商品工厂
public class ProductFactory extends BaseAbstractFactory{}
//淘宝商品
public class TBProductFactory extends BaseAbstractFactory{}

以上,通过增加一个基础抽象类,默认实现抽象工厂的方法,后面的实际工厂继承这个类来根据实际情况选择是否重写,算是比较完美的重构了我们当前的代码。

感言

经过这一次的代码重构,我越发觉得以前写的代码是真的垃圾,只是无脑的将业务逻辑进行堆砌,耦合及其严重,导致很多时候牵一发而动全身。看来,设计模式是真的很有必要好好学习,当谨记!!!