工厂模式是现实生活中常见的场景,在面向对象编程中,也是我们经常使用的,也许我们早已经接触了,只是不知道原来这也是一种设计模式,俗话说,越是平常的就越容易忽略,但是不能忽视他的作用,存在价值。
一.概述
工厂模式:顾名思义,就是生产产品,因此属于创建型设计模式,需要生成的对象就是产品,生成对象的地方叫做工厂。工厂模式实现了创建者和调用者的分离。
二.特点
定义一个用于创建的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延伸到其子类。降低耦合度
简单的说,工厂模式的核心本质就是实例化对象,用工厂方法代替new操作,将选择实现类,创建对象统一管理和控制,从而将调用者跟我们的实现类解耦。
三.分类
1.简单工厂模式(静态工厂)
2.工厂方法模式
3.抽象工厂模式
1.简单工厂模式(静态工厂)
如果你要建一个工厂,首先要确定你这个工厂究竟要生产什么产品,假如是生产手机,那先确定好方向(建一个抽象类或者接口)
public abstract class Phone {
//具体的手机型号,由子类实现
public Phone() {
}
}
知道要生产的是手机之后,还要确定生产的手机型号
public class Phone1 extends Phone {
public Phone1(){
System.out.println("生产Phone1");
}
}
public class Phone2 extends Phone {
public Phone2() {
System.out.println("生产Phone2");
}
现在有想生产的产品了,但是需要生产产品的地方,因此就要建立一个工厂。
public class SimpleFactory {
/**
* 简单工厂:这是一个具体的类,不是接口,也不是抽象类
* 工厂应该有一个创建方法,并且是静态的,因此也称为静态工厂
*/
public static final int TYPE_P1 = 1;//phone1
public static final int TYPE_P2 = 2;//pone2
public static Phone createPhone(int type) {
switch (type) {
case TYPE_P1:
return new Phone1();
case TYPE_P2:
return new Phone2();
default:
return new Phone1();//默认制造的是phone1
}
}
}
有产品,也有工厂了,那如果我们需要这个产品的话,就去工厂指定产品。
public class Customer {
public static void main(String [] args){
//需要一台Phone1
SimpleFactory simpleFactory=new SimpleFactory();
Phone phone1=simpleFactory.createPhone(SimpleFactory.TYPE_P1);
}
}
输出:
生产Phone1
到这里我们会觉得上面的代码十分熟悉,就是经常都在使用的,特点是在面向对象的多态这一点上。但是你有没有想过这样的一种情况呢?增加一个产品phone3,除了要增加一个具体的phone3产品类,还需要去修改简单工厂类的方法(新增case);而这样一来,简单工厂和每一个具体产品是联系比较密切,牵一发而动全身,这显然是不符合低耦合的,而且不同的产品需要不同额外参数的时候不支持。因此我们有另外一种简单工厂来解决**不用修改create()**代码。
2.简单工厂(反射)
public class SimpleFactory1 {
public static <T extends Phone> T createProduct(Class<T> c){
Phone phone=null;
try {
phone = (Phone) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
e.printStackTrace();
//异常处理
}
return (T)phone;
}
}
顾客类:
public class Customer {
public static void main(String [] args){
//需要一台Phone1
SimpleFactory simpleFactory=new SimpleFactory();
Phone phone1=simpleFactory.createPhone(SimpleFactory.TYPE_P1);
//需要一台Phone2,利用反射
System.out.println("利用反射机制:");
Phone phone2 = SimpleFactory1.createProduct(Phone2.class);
}
输出:
生产Phone1
利用反射机制:
生产Phone2
当你终于把反射的简单工厂看完之后,再细想一下,你会觉得欲哭无泪,因为这个和new Object()是一样的性质,当需要调用有参的构造函数时便无能为力了,这样像为了工厂而工厂。同样解决不了不同的产品需要不同额外参数的时候 不支持这个问题…看到这里是不是要崩溃了,先稳住!相信了解了工厂方法模式会赢的!
3.工厂方法模式
还记得最开始写的特点里面有这样一句话吗?——工厂方法使一个类的实例化延伸到其子类。这句话其实就是把简单工厂中具体的工厂类,划分为两层:抽象工厂+具体的工厂子类
首先:创建抽象工厂,接口也可以
interface PhoneFactory {
Phone create();
}
子类:
public class FactoryPhone1 implements PhoneFactory {
@Override
public Phone1 create() {
return new Phone1();
}
}
public class FactoryPhone2 implements PhoneFactory {
@Override
public Phone2 create() {
return new Phone2();
}
}
客户类:
//工厂方法
FactoryPhone1 factoryPhone1 = new FactoryPhone1();
Phone phone1 = factoryPhone1.create();
输出:
生产Phone1
看了这个之后是不是觉得这种更面向对象呢?并且当需求变化,只需要增删相应的类,不需要修改已有的类。更符合开闭原则。但是工厂方法模式也有弊端:对象的数量成倍增长。当产品种类非常多时,会出现大量的与之对应的工厂对象,这不是我们所希望的。所以也有另外一种多方法工厂。
4.多方法工厂
模仿Executors类。
public class MulMayFactory {
//提供共有的静态工厂方法
public static Phone createPhone1() {
return new Phone1();
}
public static Phone createPhone2() {
return new Phone2();
}
}
顾客类:
Phone phone1=MulMayFactory.createPhone1();
用静态工厂方法代替构造器的方法的优势:
1.有名称(客户端代码更易于阅读)
2.不必在每次调用它们的时候都创建一个新的对象。
3.可以返回原返回类型的任何子类型的对象
4.在创建参数化类型实例的时候,它们使代码变得更加简单
以上就是简单工厂模式,工厂方法模式,抽象工厂模式会在后面陆续学习。
学习参考:
https://blog.youkuaiyun.com/jason0539/article/details/23020989
https://blog.youkuaiyun.com/zxt0601/article/details/52798423
《Effective Java中文版第二版第二章第一条》