【设计模式】工厂模式

工厂模式分为简单工厂(Simple Factory Pattern)模式、工厂方法模式、抽象工厂模式三种形态。

1.简单工厂模式(Simple Factory Pattern)

又称为静态工厂方法模型,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

1.1简单工厂模式结构图

  1.2 简单工厂模式包含以下角色(原文链接:https://blog.csdn.net/ningcci/article/details/124165916)

(1)Factory(工厂角色)

工厂角色即工厂类,它是简单工厂模式的核心,负责实现创建所有实例的内部逻辑;工厂类可以直接被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方法factoryMethod(),它返回一个抽象产品类Product,所有的具体产品都是抽象产品的子类。

(2)Product(抽象产品角色)

抽象产品角色是简单工厂模式所创建的所有对象的父类,负责描述所有实例所共有的公共接口,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个工厂方法,因为所有创建的具体产品对象都是其子类对象。

(3)ConcreteProduct(具体产品类)

具体产品角色是简单工厂模式的创建目标,所有创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现定义在抽象产品中的抽象方法 。

 1.3简单示例

Car.java

package SimpleFactoryMode;

public abstract class Car {
   public abstract void drive();
}

BMW.java

package SimpleFactoryMode;

public class BMW extends Car{

    @Override
    public void drive() {
        System.out.println("宝马");
    }
  
}

Benz.java

package SimpleFactoryMode;

public class BenZ extends Car{

    @Override
    public void drive() {
        System.out.println("奔驰");
    }
  }

Honda.java

package SimpleFactoryMode;

public class Honda extends Car{

    @Override
    public void drive() {
        System.out.println("本田");
    }
  
}

CarFactory.java

package SimpleFactoryMode;

public class CarFactory {
   public Car getCar(String carName)
   {
       if(carName.equalsIgnoreCase("BenZ"))
       {
           return new BenZ();
       }
       else if(carName.equalsIgnoreCase("BMW"))
       {
           return new BMW();
       }
       else if(carName.equalsIgnoreCase("Honda"))
       {
           return new Honda();
       }
       else{
            return null;
           }
    }
 }

CarTest.java

package SimpleFactoryMode;

public class CarTest {

    public static void main(String[] args) {
        CarFactory factory = new CarFactory();
        Car bmw = factory.getCar("bmw");
        bmw.drive();
        Car benz = factory.getCar("benz");
        benz.drive();
        Car honda = factory.getCar("honda");
        honda.drive();
    }
}

运行结果:

 1.4简单工厂模式的优缺点(原文链接:https://www.cnblogs.com/ygsworld/p/10649491.html)

优点:(1)工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责
    (2)客户端无需知道所创建具体产品的类名,只需知道参数即可
    (3)也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。

 缺点:(1)工厂类集中了所有产品的创建逻辑,职责过重,一旦异常,整个系统将受影响
    (2)使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
    (3)系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
    (4)简单工厂模式使用了static工厂方法,造成工厂角色无法形成基于继承的等级结构。

 1.5简单工厂模式的适用环境

(1)工厂类负责创建对的对象比较少,因为不会造成工厂方法中的业务逻辑过于复杂

(2)客户端只知道传入工厂类的参数,对如何创建对象不关心

 

 1.7解耦合的简单工厂模式(转自:https://www.cnblogs.com/kubixuesheng/p/10344427.html#_label2)

虽然简单工厂模式分离了产品的创建者和消费者,有利于软件系统结构的优化,但是由于一切产品创建的业务逻辑都集中在一个工厂类中,导致了没有很高的内聚性,同时也违背了开闭原则。另外,简单工厂模式的方法一般都是静态的,而静态工厂方法让子类继承是可能被隐藏的,因此,简单工厂模式无法形成基于基类的继承树结构。

到了这里,其实又要想,不要过度的优化,不要为了使用设计模式而使用设计模式,如果是业务比较简单的场景,这样的简单工厂模式还是非常好用的。但无论如何,繁琐的if-else判断还是不太好,一旦判断条件稍微多点儿,if-else写起来就非常繁琐。

观察一些开源框架实现类似场景的代码,发现它们使用了 Java 的反射机制省去了判断的步骤,比之前的繁琐的 if-else 判断要好一些,如下代码。

修改工厂类CarFactory.java的代码如下所示:

package SimpleFactoryReflection;

import SimpleFactory.BMW;
import SimpleFactory.BenZ;
import SimpleFactory.Honda;

public class CarFactory {
    public static Car getCar(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException
    {
        Class Car =Class.forName(type);
        return (Car) Car.newInstance();
    }
}

 修改测试类CarTest.java的代码如下所示:

package SimpleFactoryReflection;

public class CarTest {

    public static void main(String[] args) throws ReflectiveOperationException, IllegalAccessException, ClassNotFoundException {
        Car benz = CarFactory.getCar("SimpleFactoryReflection.BenZ");
        Car bmw = CarFactory.getCar("SimpleFactoryReflection.BMW");
        Car honda = CarFactory.getCar("SimpleFactoryReflection.Honda");
        bmw.drive();
benz.drive();
honda.drive();
    }
}

运行结果:

 

2.抽象工厂模式(转自:https://blog.csdn.net/qq_42337558/article/details/115149620)

抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。为了更好地理解抽象工厂模式,我们先引入两个概念:

(1) 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。

(2) 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族。

产品等级结构与产品族示意图如图所示:

在图中,不同颜色的多个正方形、圆形和椭圆形分别构成了三个不同的产品等级结构,而相同颜色的正方形、圆形和椭圆形构成了一个产品族,每一个形状对象都位于某个产品族,并属于某个产品等级结构。上图中一共有五个产品族,分属于三个不同的产品等级结构。我们只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一确定这个产品.

当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式。抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、更有效率。抽象工厂模式示意图如图所示:

2.1在抽象工厂模式中,每一个具体工厂都提供了多个工厂方法用于产生多种不同类型的产品,这些产品构成了一个产品族,抽象工厂模式结构如图所示: 

 2.2抽象工厂模式包含如下角色:

● AbstractFactory(抽象工厂):它声明了一组用于创建一族产品的方法,每一个方法对应一种产品。

● ConcreteFactory(具体工厂):它实现了在抽象工厂中声明的创建产品的方法,生成一组具体产品,这些产品构成了一个产品族,每一个产品都位于某个产品等级结构中。

● AbstractProduct(抽象产品):它为每种产品声明接口,在抽象产品中声明了产品所具有的业务方法。

● ConcreteProduct(具体产品):它定义具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法。
在抽象工厂中声明了多个工厂方法,用于创建不同类型的产品,抽象工厂可以是接口,也可以是抽象类或者具体类。
2.3简单示例

第一步:创建抽象产品

Noodles.java 

package AbstractFactoryMode;

public abstract class Noodles {
    public abstract void produce();
}

Water.java

package AbstractFactoryMode;

public abstract class Water {
    public abstract void produce();
}

第二步:创建具体产品

TongyiNoodles.java

package AbstractFactoryMode;

public class TongyiNoodles extends Noodles{
    @Override
    public void produce() {
        System.out.println("生产统一方便面");
    }
}

TongyiWater.java

package AbstractFactoryMode;

public class TongyiWater extends Water{
    @Override
    public void produce() {
        System.out.println("生产统一矿泉水");
    }
}

Kongshifunoddles.java

package AbstractFactoryMode;

public class Kongshifunoddles extends Noodles{

    @Override
    public void produce() {
        System.out.println("生产康师傅方便面");
    }
}

KongshifuWater.java

package AbstractFactoryMode;

public class KongshifuWater extends Water{
    @Override
    public void produce() {
        System.out.println("生产康师傅矿泉水");
    }
}

第三步:创建抽象工厂

AbstractFactory.java

package AbstractFactoryMode;

public abstract class AbstractFactory {
   public abstract Noodles MakeNoodles(String brand);
   public abstract Water MakeWater(String brand);  
}

第四步:创建具体工厂

TongyiFactory.java

package AbstractFactoryMode;

public class TongyiFactory extends AbstractFactory{
    @Override
    public Noodles MakeNoodles(String brand) {
         if(brand==null)
         {
             return null;
         }else if(brand.equalsIgnoreCase("tongyi")){
             return new TongyiNoodles();
          } else {
                  return null;
          }
    }

    @Override
    public Water MakeWater(String brand) {
         if(brand==null)
         {
             return null;
         }else if(brand.equalsIgnoreCase("tongyi")){
             return new TongyiWater();
          } else {
                  return null;
          }
    }
}

KongshifuFactory.java

package AbstractFactoryMode;

public class KongshifuFactory extends AbstractFactory{

    @Override
    public Noodles MakeNoodles(String brand) {
         if(brand==null)
         {
             return null;
         }else if(brand.equalsIgnoreCase("Kongshifu")){
             return new Kongshifunoddles();
          } else {
                  return null;
          }
    }

    @Override
    public Water MakeWater(String brand) {
         if(brand==null)
         {
             return null;
         }else if(brand.equalsIgnoreCase("Kongshifu")){
             return new KongshifuWater();
          } else {
                  return null;
          }
    }

}

第五步:创建一个工厂选择类,通过传递品牌来选择工厂

FactoryChoose.java

package AbstractFactoryMode;

public class FactoryChoose {
    public static AbstractFactory getFactory(String brand)
    {
        if(brand.equalsIgnoreCase("tongyi")){
            return new TongyiFactory();
         } else if(brand.equalsIgnoreCase("kongshifu")){
            return new KongshifuFactory();
         }else {
             return null;
        }
    }
}

第六步:创建一个用户类,用于测试

Client.java

package AbstractFactoryMode;
public class Client {
    public static void main(String[] args) {

       FactoryChoose.getFactory("tongyi").MakeNoodles("tongyi").produce();
       FactoryChoose.getFactory("tongyi").MakeWater("tongyi").produce();
       
       FactoryChoose.getFactory("kongshifu").MakeNoodles("kongshifu").produce();
       FactoryChoose.getFactory("kongshifu").MakeWater("kongshifu").produce();
   }

}

运行结果:

 2.4抽象工厂的优缺点(转自:https://www.cnblogs.com/imreW/p/16944003.html)

优点:

一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象(将一个系列的产品统一一起创建);

缺点:

(1)产品族扩展非常困难,要增加一个系列的某一产品,既要修改工厂抽象类里加代码,又修改具体的实现类里面加代码;

(2)增加了系统的抽象性和理解难度;

2.5抽象工厂模式的使用场景(原文链接:https://blog.csdn.net/qq_42337558/article/details/115149620)

(1) 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是很重要的,用户无须关心对象的创建过程,将对象的创建和使用解耦。

(2) 系统中有多于一个的产品族,而每次只使用其中某一产品族。可以通过配置文件等方式来使得用户可以动态改变产品族,也可以很方便地增加新的产品族。

(3) 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。同一个产品族中的产品可以是没有任何关系的对象,但是它们都具有一些共同的约束,如同一操作系统下的按钮和文本框,按钮与文本框之间没有直接关系,但它们都是属于某一操作系统的,此时具有一个共同的约束条件:操作系统的类型。

(4) 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。
2.6抽象工厂区别与简单工厂模式的区别

工厂方法模式:

  • 一个抽象产品类,可以派生出多个具体产品类。

  • 一个抽象工厂类,可以派生出多个具体工厂类。

  • 每个具体工厂类只能创建一个具体产品类的实例。

抽象工厂模式:

  • 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。

  • 一个抽象工厂类,可以派生出多个具体工厂类。

  • 每个具体工厂类可以创建多个具体产品类的实例,也就是创建的是一个产品线下的多个产品。

其他区别:

  • 工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个;

  • 工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个;

  • 抽象工厂更像工厂,可以生产不同类的产品。而工厂方法则更像是工厂的一种产品生产线,生产同类不同规格的产品。

 

参考文章:

https://www.cnblogs.com/ygsworld/p/10649491.html

https://blog.csdn.net/qq_42337558/article/details/115149620

 

posted @ 2023-03-09 14:32  YorkShare  阅读(188)  评论(0编辑  收藏  举报