Q:什么是工厂模式
A:工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
Q:工厂模式有哪些优点
A:用户将创建对象的权利交给工厂,用户自己不用关心工厂的流水线操作是怎样进行的,用户只需要使用工厂对象便可以得到产品对象,换句话说上层不必知道底层的具体实现原理和过程,只需更多的关注自己的业务逻辑即可
Q:工厂模式有哪些方式
A:工厂方法模式和抽象工厂模式,严格意义上来说,简单工厂属于工厂方法模式的特例。
代码实现,这是一道华丽的分割线
写在开头,在阅读代码前,所有关于工厂的代码均理解为第三方作者写的jar包或者底层封装好的类,“我”(请理解成正在看这篇文章的你,或者是使用者)无法修改工厂相关类的代码,Client类中才是“我”(作为使用者)写的代码,这样方便理解。
简单工厂
智能电子产品接口Product,默认实现有Phone类,Computer类两个基类,Factory类用于构建具体基类的对象。
//产品接口类
public interface Product {
//屏幕 智能电子产品均需要生产屏幕
void screen();
//电池 智能电子产品均需要生产电池
void battery();
}
//具体产品基类 手机
public class Phone implements Product{
@Override
public void screen() {
System.out.println("生产手机屏幕");
}
@Override
public void battery() {
System.out.println("生产手机电池");
}
}
//具体产品基类 电脑
public class Computer implements Product{
@Override
public void screen() {
System.out.println("生产电脑屏幕");
}
@Override
public void battery() {
System.out.println("生产电脑电池");
}
}
//工厂类
public class Factory {
static Product createProduct(int i) {
Product product = null;
switch (i) {
case 1:
product = new Phone();
break;
case 2:
product = new Computer();
break;
}
return product;
}
}
//模拟类
public class Client {
public static void main(String[] args) {
//我们不需要关心Factory类以及其子类的内部逻辑与实现,
//我们只需记住1对应手机,2对应电脑即可,传入1或2便可得到具体产品
Factory.createProduct(1).battery();
}
}
UML图
简单工厂总结
优点:将创建对象的权利交给工厂类,利于代码解耦,符合面向接口编码,符合迪米特法则(最少知道原则,不知道设计模式七大原则的请先去看一下,等我看完设计模式会单独写一篇)。
缺点:只能针对某一特性产品,需要使用者记住相应基类的对应值,本例中使用者需要记住1对应手机,2对应电脑,如果产品较多,代码将会臃肿,且如果特性增加,比如我需要新增一个产品基类Watch,那么需要改动底层代码Factory类中,switch对应Watch的数值,这也违背类OCP原则。
工厂方法模式
工厂方法便是针对简单工厂继续进行优化,对产品基类进行扩容增加,而且要符合OCP原则。
//产品接口类
public interface Product {
//屏幕 智能电子产品均需要生产屏幕
void screen();
//电池 智能电子产品均需要生产电池
void battery();
}
这里我们不再使用单纯的像简单工厂方式那样直接由Factory去生产具体基类,我们将工厂进行抽象,不同的工厂负责不同的基类实现,比如PhoneFactory只负责Phone的创建,ComputerFactory只负责Computer的创建,这也符合类单一职责原则,同时也降低了代码的耦合度
//工厂接口类
public interface Factory {
Product getProduct();
}
//具体产品基类 手机
public class Phone implements Product{
@Override
public void screen() {
System.out.println("生产手机屏幕");
}
@Override
public void battery() {
System.out.println("生产手机电池");
}
}
//具体产品基类 电脑
public class Computer implements Product{
@Override
public void screen() {
System.out.println("生产电脑屏幕");
}
@Override
public void battery() {
System.out.println("生产电脑电池");
}
}
//手机工厂 负责生产手机
public class PhoneFactory implements Factory{
@Override
public Product getProduct() {
System.out.println("这是手机基类");
return new Phone();
}
}
//电脑工厂 负责生产电脑
public class ComputerFactory implements Factory{
@Override
public Product getProduct() {
System.out.println("这是电脑基类");
return new Computer();
}
}
//流水线加工操作 等会解释这个类
public class Work {
//组装
static String assemble() {
return "组装";
}
//打包
static String box() {
return "打包";
}
//销售
static String sale() {
return "销售";
}
static void product(Factory factory) {
factory.getProduct().battery();
factory.getProduct().screen();
System.out.println("产品开始"+Work.assemble());
System.out.println("产品开始"+Work.box());
System.out.println("产品开始"+Work.sale());
}
}
//模拟类
public class Client {
public static void main(String[] args) {
Work.product(new ComputerFactory());
}
}
UML
总结
简单工厂的弊端前面已经描述,其可扩展性非常的糟糕,书写工厂代码的作者他也无法考虑到所有的情况,比如“我”使用者今天需要新增一个新产品Watch,明天要增加一个新产品MP4,在简单工厂中,这些新增的产品只能让作者去修改源码更新,但很显然这是不现实也不科学的。为此工厂方法中,作者将工厂抽象为工厂接口,你需要新产品,首先去实现作者的Product类比如Watch,然后在使用WatchFactory类去实现Factory接口,很多人可能不太理解为什么要这么麻烦和负责,我直接写一个Watch类他不香吗,然后直接new他不好吗,其实不然,工厂作者所写的代码肯定不会只有这么简单的创建对象,还会有一些列的操作,比如Work类的一些列方法,其中product方法,作者只能做约定,传入Factory对象,作者并不知道你使用什么Factory,WatchFactory也好,MP4Factory也好,只要是你的产品基类符合Product,那么ProductFactory传入都可以执行product方法,所以我们也需要遵守作者的约定传入具体的Factory即可调用后续方法。
优点:仍然具备简单工厂的优点,扩展相对方便(扩展一个MP4产品),仅需扩展产品以及对应产品的工厂即可,本质也是将工厂和类交由客户端(使用者)创建,符合OCP原则。
缺点:如果有多个同级产品,需要建造很多工厂和基类,工厂类和基类会呈现出爆炸式增长,不利于维护。
抽象工厂
这个东西理解稍微有点复杂,抽象工厂并不比工厂方法高级或者说优秀,抽象工厂所解决的案例是有局限性的,抽象工厂的案例需要有其内在的联系,这里需要引入"级"和"簇"这两个个概念。一个簇所属的级均为平等关系,一个簇可以实现多个不相同的级的基类。具体的说在本例中,级为各种电子产品包括不限于手机、电脑、手表等基类,簇包括但不限于华为、苹果、小米等工厂基类。举例,苹果工厂(簇)可以生产苹果手机(级),苹果电脑(级),华为工厂可以生产华为手机(级),华为电脑(级),华为手机、华为电脑、苹果手机、苹果电脑他们共性就是作为级的手机和电脑都可以被作为簇的苹果或者华为工厂进行生产。一个工厂只能生产一个簇的产品,苹果工厂只能生产苹果(簇)的手机(级),电脑(级)以直角坐标系为例,X轴为级,Y轴为簇,如图所示。
//产品接口类 级概念 一个级作为产品,不同簇的级应该具有相同属性
public interface Product {
//屏幕
void screen();
//芯片
void chip();
//电池
void battery();
//描述
String info();
}
//抽象工厂类 簇概念,一个簇作为工厂,可以生产多个级的产品
public interface AbstractFactory {
//抽象手表
Product makeWatch();
//抽象手机
Product makePhone();
//抽象电脑
Product makeComputer();
}
//电脑基类
public abstract class Computer implements Product {
//键盘 电脑特有
public abstract void keyboard();
}
//手机基类
public abstract class Phone implements Product{
//SIM卡槽 手机特有
public abstract void sim();
}
//苹果电脑基类
public class AppleComputer extends Computer {
@Override
public void keyboard() {}
@Override
public void screen() {}
@Override
public void chip() {}
@Override
public void battery() {}
@Override
public String info() {
return "苹果生产的电脑";
}
}
//华为电脑基类
public class HuaweiComputer extends Computer {
@Override
public void keyboard() {}
@Override
public void screen() {}
@Override
public void chip() {}
@Override
public void battery() {}
@Override
public String info() {
return "华为生产的电脑";
}
}
//苹果手机基类
public class ApplePhone extends Phone {
@Override
public void sim() {
}
@Override
public void screen() {
}
@Override
public void chip() {
}
@Override
public void battery() {
}
@Override
public String info() {
return "苹果生产的手机";
}
}
//华为手机基类
public class HuaweiPhone extends Phone {
@Override
public void sim() {
}
@Override
public void screen() {
}
@Override
public void chip() {
}
@Override
public void battery() {
}
@Override
public String info() {
return "华为生产的手机";
}
}
//苹果工厂
public class Apple implements AbstractFactory {
@Override
//生产苹果手表
public Product makeWatch() {
Product product=new AppleWatch();
System.out.println(product.info());
return product;
}
@Override
//生产苹果手机
public Product makePhone() {
Product product=new ApplePhone();
System.out.println(product.info());
return product;
}
@Override
//生产苹果电脑
public Product makeComputer() {
Product product=new AppleComputer();
System.out.println(product.info());
return product;
}
}
//华为工厂
public class Huawei implements AbstractFactory {
@Override
//生产华为手表
public Product makeWatch() {
Product product=new HuaweiWatch();
System.out.println(product.info());
return product;
}
@Override
//生产华为手机
public Product makePhone() {
Product product=new HuaweiPhone();
System.out.println(product.info());
return product;
}
@Override
//生产华为电脑
public Product makeComputer() {
Product product=new HuaweiWatch();
System.out.println(product.info());
return product;
}
}
//模拟类
public class Client {
static Product makeProduct(AbstractFactory abstractFactory) {
Product product = abstractFactory.makeComputer();
return product;
}
public static void main(String[] args) {
Client.makeProduct(new Huawei());
}
}
UML
代码生成的UML图有点乱,将就一下
总结:
优点:仍具有工厂方法的优点,并且同簇可替换性很强,方便业务框架转型,符合OCP原则。
缺点:如果要新增级,比如新增一个Watch产品,需要修改源码,首先需要修改AbstracFactory中的方法,然后Apple工厂簇和Huawei工厂簇均需要改动,不满足OCP原则。