工厂方法模式
主要用于生成复杂对象,如果只通过new就可以完事,就不用该模式。这个模式看起来简单,但感觉很难理解,不晓得存在的意义是什么,都知道子类名称了为什么不直接new(或许是实际创建比较复杂,例子都偷懒使用简单的类型,所以可以直接new就完成对象创建了)都拿到Class 自己通过反射也可以直接拿到对象实例,和在工厂中使用反射生成有什么区别?
工厂一般来说都生成一类相似的产品,比如说罐头工厂,生产黄桃罐头、杨梅罐头、凤梨罐头。客户通过工厂对外的接口来获得自己想要的产品。
- 对客户而言,需要知道这个产品能干什么(抽象产品接口)已经从哪里获得(抽象工厂接口)自己想要的(传入参数表明自己意图)产品。
- 对于工厂而言,需要实现具体生产组装产品的细节,还需要了解客户意图,使用具体对应工厂,返回具体产品。
主要角色
- 抽象工厂:工厂模式的核心
- 具体工厂:实现具体逻辑
- 抽象产品:是工厂所生产产品的基类,规定了这些产品的公共特征
- 具体产品: 实现抽象产品的某个具体类
具体实现
这里有两种实现方案,第一种使用泛型,也是让我困惑的方式。第二种使用字符串或枚举实现
1.泛型方式
- 抽象产品
public abstract class AudiCar {
public abstract void drive();
public abstract void selfNavigation();
}
- 具体产品
public class AudiQ3 extends AudiCar {
@Override
public void drive() {
System.out.println("Q3 启动了");
}
@Override
public void selfNavigation() {
System.out.println("Q3 开始自动巡航!");
}
}
public class AudiQ5 extends AudiCar {
@Override
public void drive() {
System.out.println("Q5 启动了!");
}
@Override
public void selfNavigation() {
System.out.println("Q5 开启自动巡航!");
}
}
public class AudiQ7 extends AudiCar {
@Override
public void drive() {
System.out.println("Q7 启动了!");
}
@Override
public void selfNavigation() {
System.out.println("Q7 开启自动巡航!");
}
}
- 抽象工厂
public abstract class AudiFactory {
public abstract <T extends AudiCar> T createAudiCar(Class<T> T);
}
- 具体工厂
public class AudiCarFactory extends AudiFactory {
@Override
public <T extends AudiCar> T createAudiCar(Class<T> clz) {
AudiCar car=null;
try {
car= (AudiCar) Class.forName(clz.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return (T) car;
}
}
- 客户端使用
public class Client {
public static void main(String[] args) {
AudiFactory audiFactory = new AudiCarFactory();
AudiCar audiCarq3 = audiFactory.createAudiCar(AudiQ3.class);
AudiCar audiCarq5 = audiFactory.createAudiCar(AudiQ5.class);
AudiCar audiCarq7 = audiFactory.createAudiCar(AudiQ7.class);
audiCarq3.drive();
audiCarq3.selfNavigation();
audiCarq5.drive();
audiCarq5.selfNavigation();
audiCarq7.drive();
audiCarq7.selfNavigation();
}
}
这种方式客户端都已经用到“实现类.class”了,客户端都其实已经知道了具体产品类的实现细节。
2.使用约定名称或枚举
- 抽象产品
public interface Can {
void open();
String createDate();
}
- 具体产品
public class PeachCan implements Can {
public PeachCan() { }
@Override
public void open() {
System.out.println("PeachCan被打开!");
}
@Override
public String createDate() {
return null;
}
}
public class BayberryCan implements Can{
public BayberryCan() { }
@Override
public void open() {
System.out.println("Bayberry 被打开了!");
}
@Override
public String createDate() {
return null;
}
}
public class AnanasCan implements Can {
public AnanasCan() { }
@Override
public void open() {
System.out.println("Ananas被打开了!");
}
@Override
public String createDate() {
return null;
}
}
- 抽象工厂
public interface Factory {
Can getCan(String canName);
Can getCan(CanTypes type);
void doSomething();
}
- 具体工厂
public class CanFactory implements Factory {
public CanFactory() { }
@Override
public Can getCan(String canName) {
if (canName.isEmpty()) {
return null;
}
if (canName.equals("peach")) {
return new PeachCan();
} else if (canName.equals("bayberry")) {
return new BayberryCan();
} else if (canName.equals("ananas")) {
return new AnanasCan();
} else {
return null;
}
}
@Override
public Can getCan(CanTypes type) {
switch (type) {
case PEACH:
return new PeachCan();
case ANANAS:
return new AnanasCan();
case BAYBERRY:
return new BayberryCan();
default:
return null;
}
}
@Override
public void doSomething() {
System.out.println("工厂 doSomething");
}
}
- 约定枚举
public enum CanTypes {
PEACH,
BAYBERRY,
ANANAS;
}
这里使用字符串(张口说“我要个黄桃罐头”)或枚举(看着工厂给的菜单选)更符合实际情况,客户端只需要知道 抽象工厂接口、产品接口,具体产品对应的枚举类。 不需要知道任何具体实现,更符合迪米特原则。
工厂模式更侧重的是如何方便的给和客户端提供产品,而不是具体产品的组装。
Call接口提供了内部接口Factory(用于将对象的创建延迟到该工厂类的子类中进行,从而实现动态的
配置,工厂方法模式。(工厂方法模式:这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。)