设计模式---创建型模式---工厂模式

设计模式—创建型模式—工厂模式

一、 工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。它提供了一种创建对象的最佳方式。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

其中,工厂模式可以细分为一下三种:

  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式

工厂模式主要解决的是接口选择的问题,可以在明确地计划不同条件下创建不同实例时运用。其中要注意的是,在任何需要生成复杂对象的地方,都可以使用工厂方法模式,但是对于简单对象,特别是只需要new就可以完成创建的对象,无需使用工厂模式。

1、工厂模式举例

下面来看一个简单的小例子:

工厂模式的目的就是创建接口来解决问题,因而我们需要先创建一个电子产品的接口,进而来实现余下的业务逻辑

//超类
public interface Electronics {
    void sales();
}
//子类
public class Computer implements Electronics {
    @Override
    public void sales() {
        System.out.println("购买了电脑哟~");
    }
}
//子类
public class Phone implements Electronics {
    @Override
    public void sales() {
        System.out.println("购买了手机哟~");
    }
}
//业务逻辑
public class Test {
    public static void main(String[] args) {
        Electronics electronics = new Computer();
        electronics.sales();
    }
}

进而我们能看出来的此模式的优/缺点:

2、工厂模式优缺点

优点:

  • 一个调用者想创建一个对象,只需要知道他的名称即可

  • 扩展性高,当我们要增加一个产品时,我们只需要增加一个工厂类来实现超类,重写里面的方法即可

  • 可以屏蔽具体的实现,只关心接口就可以

    既然在此说到重写,那我们来说一下什么是重写??

    • 发生方法重写的两个方法返回值、方法名、参数列表必须完全一致(子类重写父类的方法)
    • 子类抛出的异常下不能超过父类相应方法抛出的异常(子类异常不能大于父类异常)
    • 子类方法的访问级别不能低于父类相应方法的访问级别(子类访问级别不能低于父类访问级别)

缺点:

  • 在上面的优点中可以看到,每增加一个产品时,都需要增加一个工厂类和具体实现,进而使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。

二、简单工厂模式(不属于23种GOF设计模式之一,但属于创建型模式)

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

我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。

简单工厂模式包含以下几种类:

  • Factory(工厂类):它是简单工厂模式的核心部分,负责实现创建所有实例的内部逻辑,工厂类可以被外界直接调用,创建所需的产品对象。
  • Product(抽象产品类):是简单工厂模式所创建的所有对象的父类,负责描述所有实例共有的公共接口,它的引入将提高系统的灵活性,是的在工厂类中只需定义一个工厂方法,因为所有创建的具体产品对象都是其子类对象。
  • ConcreteProduct(具体产品类):是简单工厂模式的创建目标,所有创建的对象都充当这个角色的某个具体类的实例。每个具体产品都继承了抽象产品类,需要实现定义在抽象产品中的抽象方法。

1、简单工厂模式的例子

下面来看一个简单的小例子:

以上我们说了,一个简单工厂模式里面要有工厂类,抽象产品和具体产品类,那我们就以购买电子产品为例子吧…

当我们想要购买电子产品时,工厂类当然就是我们人啦;抽象产品就是我们要购买电子产品,由于目前我们还不知道有什么电子产品,那么我就建立一个通用类,用来实现购买的功能;接着具体产品类就是我们具体要购买的什么产品,下面就让我们来看一下代码:

//工厂类
public class Person {
    public static Electronics getElectronics(String electronics) throws Exception
    {
        if (electronics.equalsIgnoreCase("computer")){
            return new Computer();
        }else if (electronics.equalsIgnoreCase("phone")){
            return new Phone();
        }else{
            throw new Exception("对不起,暂时没有别的电子产品...");
        }
    }
}
//工厂类的另一种写法  缺点:区分大小写
public class Person {
    public static Electronics getElectronics(String electronics) throws Exception {
        switch (electronics) {
            case "computer":
                return new Computer();
            case "phone":
                return new Phone();
            default:
                throw new Exception("对不起,暂时没有别的电子产品...");
        }
    }
}
//抽象产品类
public interface Electronics {
    void sales();  
}
//具体产品类
public class Computer implements Electronics{
    @Override
    public void sales() {
        System.out.println("购买了电脑哟~");
    }
}
public class Phone implements Electronics{
    @Override
    public void sales() {
        System.out.println("购买了手机哟~");
    }
}
//业务逻辑
public class Test {
    public static void main(String[] args) throws Exception {
        String e= "computer";
        Electronics electronics = Person.getElectronics(e);
        electronics.sales();
    }
}

但是当我们还想要领养其他动物时,我们应该怎么去添加呢???接着往下看看吧~~

//改变之后的工厂类
public class Person {
    public static Electronics getElectronics(String electronics) throws Exception {
        switch (electronics) {
            case "computer":
                return new Computer();
            case "phone":
                return new Phone();
            case "ipad":
                return new Ipad();
            default:
                throw new Exception("对不起,暂时没有别的电子产品...");
        }
    }
}
//抽象产品类不变
public interface Electronics {
    void sales();
}
//具体产品类要增加
public class Computer implements Electronics{
    @Override
    public void sales() {
        System.out.println("购买了电脑哟~");
    }
}
public class Phone implements Electronics{
    @Override
    public void sales() {
        System.out.println("购买了手机哟~");
    }
}
public class Ipad implements Electronics {
    @Override
    public void sales() {
        System.out.println("购买了平板哟~");
    }
}

通过上面的例子,我们来总结一下优/缺点吧:

2、简单工厂模式优缺点

优点:

  • 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
  • 客户端无需知道所创建具体产品的类名,只需知道参数即可。

缺点:

  • 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
  • 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度。
  • 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂。
  • 简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。

三、 工厂方法模式

工厂方法模式是定义一个创建产品对象的工厂接口,让工厂子类决定实例化那一个产品类。工厂方法使一个类的实例化延迟到其子类。“工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。即简单工厂模式+开闭原则=工厂方法模式

工厂方法模式的主要角色如下:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 getElectronics() 来创建产品。
  • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

1、工厂方法模式例子

下面来看看该如何修改上面的例子来实现工厂方法模式:

//抽象产品
public interface Electronics {
    void sales();
}
//具体产品
public class Computer implements Electronics{
    @Override
    public void sales() {
        System.out.println("购买了电脑哟~");
    }
}
public class Phone implements Electronics{
    @Override
    public void sales() {
        System.out.println("购买了手机哟~");
    }
}
//抽象工厂
public interface ElectronicsFactory {
    Electronics getElectronics();
}
//具体工厂
public class ComputerFactory implements ElectronicsFactory {
    @Override
    public Electronics getElectronics() {
        return new Computer();
    }
}
public class PhoneFactory implements ElectronicsFactory {
    @Override
    public Electronics getElectronics() {
        return new Phone();
    }
}
//业务逻辑
public class Test {
    public static void main(String[] args) throws Exception {
        ElectronicsFactory electronicsFactory = new ComputerFactory();
        Electronics electronics = electronicsFactory.getElectronics();
        electronics.sales();
    }
}

当我们需要增加新的产品时,我们只需要继承Electronics()接口,再通过工厂接口ElectronicsFactory()来实例化我们的产品。

2、工厂方法模式优缺点

那么工厂方法模式的优/缺点有:

优点:

  • 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
  • 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。
  • 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。

缺点:

  • 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
  • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度。

三、 抽象工厂模式

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

抽象工厂模式主要解决的是接口选择的问题,可以在系统的产品有多于一个的产品族,而系统只消费其中某一族的产品时使用。要注意的是:产品族难扩展,产品等级易扩展。

从上面我们可以看到,在工厂方法模式中具体工厂只负责生产具体的产品,每一个具体的工厂对应一个具体的产品,具有唯一性。但有时候我们需要一个工厂可以提供多个产品对象,如一个电子工厂,它可以生产电脑,也可以生产手机,这就需要引入抽象工厂模式,我们先来看两个概念:

  • 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电脑,其子类会有华为电脑,苹果电脑等,则抽象电脑与具体品牌的电脑直接构成了一个产品等级结构
  • 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如华为工厂生产的华为电脑、华为手机,华为电脑位于电脑产品等级结构中,华为手机位于手机产品等级结构中,华为电脑、华为手机构成了一个产品族。

1、抽象工厂模式例子

下面举一个简单的例子:

//抽象工厂类
public interface AbstractFactory {
    Computer getComputer(); //工厂方法一
    Phone getPhone();  //工厂方法二
}
public class ElectronicsFactory implements AbstractFactory {
    //工厂方法一
    @Override
    public Computer getComputer() {
        return new Computer();
    }
    //工厂方法二
    @Override
    public Phone getPhone() {
        return new Phone();
    }
}

2、抽象工厂模式优缺点

那么抽象工厂的优/缺点有:

优点:

  • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。

  • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。

  • 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”

缺点:

  • 增加新的产品等级结构时,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值