设计模式—创建型模式—工厂模式
文章目录
一、 工厂模式
工厂模式(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、抽象工厂模式优缺点
那么抽象工厂的优/缺点有:
优点:
-
抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易,所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。
-
当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
-
增加新的产品族很方便
,无须修改已有系统,符合“开闭原则”
。
缺点:
增加新的产品等级结构时
,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。