工厂模式 (Factory)Pattern 隶属于创建型设计模式,是一种将对象创建过程在原有代码抽离,交于工厂类实现管理的设计模式。很多情况下,我们创建一个对象要维护大量的重复代码,针对这种情况我们就可以将对象的创建过程进行抽离,使用工厂对象达到复用的目的。
当然,工厂模式并不是只有一种,在《Design Patterns》一书中提到了两种不同的工厂模式:
其实对于上述两种工厂模式外,还有一种工厂方法模式的衍生模式:简单工厂 (Simple Method)。既然说是衍生模式,他和工厂方法在某种程度上还是存在些许异同。
最近小龙同学很是崇拜罗布斯,觉得既然罗布斯可以造锤子,那我也可以造一个榔头手机。于是小龙同学在朋友圈发出广告,接受定榔头手机。
榔头手机的亮点在于他搭载了一颗高性能的国产自研芯片晓龙666,并且拥有一颗10亿像素的摄像头,采用了4K,240HZ高清屏幕。并且榔头手机最大的亮点就是使用了一种自研系统洪荒。洪荒系统号称不会被任何病毒攻克,使用十年绝无卡顿!现在在朋友圈订购只要999!!!
如果此时有朋友觉得小龙同学创业不易,于是下了一单支持下小龙的国产原创,小龙同学接到订单并且开始定制手机,那么这个业务场景如果不使用工厂模式我们来模拟一下:
public class HammerPhone {
// 芯片
private String chip;
// 屏幕
private String screen;
// 摄像头
private String camera;
// 系统
private String system;
public void photograph() {
System.out.println("榔头手机独家十亿摄像头为您服务!清晰到你可以看见您爱人的每一个雀斑!");
}
public HammerPhone() {
System.out.println("欢迎使用榔头手机");
}
public HammerPhone(String chip, String screen, String camera, String system) {
super();
this.chip = chip;
this.screen = screen;
this.camera = camera;
this.system = system;
System.out.println("欢迎使用榔头手机");
}
}
public class PhoneOrder {
public static void main(String[] args) {
HammerPhone hammerPhone01 = new HammerPhone("晓龙666芯片", "4K,240HZ高清屏幕", "10亿像素摄像头", "洪荒系统");
HammerPhone hammerPhone02 = new HammerPhone("晓龙666芯片", "4K,240HZ高清屏幕", "10亿像素摄像头", "洪荒系统");
HammerPhone hammerPhone03 = new HammerPhone("晓龙666芯片", "4K,240HZ高清屏幕", "10亿像素摄像头", "洪荒系统");
HammerPhone hammerPhone04 = new HammerPhone("晓龙666芯片", "4K,240HZ高清屏幕", "10亿像素摄像头", "洪荒系统");
HammerPhone hammerPhone05 = new HammerPhone("晓龙666芯片", "4K,240HZ高清屏幕", "10亿像素摄像头", "洪荒系统");
}
}
榔头手机已经推出就受到了用户的喜爱,于是小龙同学趁热打铁,推出了榔头手机2.0版本,将芯片优化为晓龙888芯片,于此同时榔头手机1.0版本并不会停产。
如果我们在不使用工厂模式的情况下,会考虑修改下面的代码达到目的:
但是作为一个逼格很高的程序员,上面的代码明显存在三个问题:
工厂方法(Factory Method) 是指定义一个创建对象的接口,但是需要子类通过实现这个接口来决定具体实例化的是哪个类,工厂方法让对象的实例化延迟到了子类中进行。在工厂方法模式中,用户只需要关心所需产品对应的工厂,无需关心创建细节,而且加入新的产品时可拓展性好,不会违反开闭原则。
当然说了这么多,我们还是要具体的看下工厂方法模式该如何实现。
通过工厂方法模式生产一个榔头一代手机:
public abstract class Phone {
// 芯片
protected String chip;
// 屏幕
protected String screen;
// 摄像头
protected String camera;
// 系统
protected String system;
// 照相
abstract void photograph();
// 打电话
abstract void call();
// 装逼
abstract void likeB();
}
public interface PhoneFactory {
Phone makePhone();
}
public class HammerPhone_1st extends Phone {
public HammerPhone_1st() {
chip = "晓龙666芯片";
screen = "4K";
system = "240HZ高清屏幕";
camera = "10亿像素摄像头";
}
@Override
public void photograph() {
System.out.println("十亿像素摄像头让一切雀斑无可逃避!");
}
@Override
public void call() {
System.out.println("性感荷官在线呼叫");
}
@Override
public void likeB() {
System.out.println("榔头一代手机,逼格就是高!");
}
@Override
public String toString() {
return "HammerPhone_1st [chip=" + chip + ", screen=" + screen + ", camera=" + camera + ", system=" + system
+ "]";
}
}
public class HammerPhoneFactory implements PhoneFactory {
@Override
public Phone makePhone() {
Phone hammerPhone_1st = new HammerPhone_1st();
System.out.println(hammerPhone_1st.toString());
return hammerPhone_1st;
}
}
public class Order {
public static void main(String[] args) {
PhoneFactory hammerPhoneFactory = new HammerPhoneFactory();
Phone makePhone = hammerPhoneFactory.makePhone();
}
}
运行结果:
这里我们看到榔头一代手机已经可以正常量产了,那么如果我要新增一个手机类别榔头二代我应该如何做呢?很简单,我只需要增加对应的手机子类和手机工厂即可。
实现一个榔头二代手机
public class HammerPhone_2nd extends Phone {
public HammerPhone_2nd() {
chip = "晓龙888芯片";
screen = "4K,240HZ高清屏幕";
system = "洪荒二代系统";
camera = "15亿像素摄像头";
}
@Override
public void photograph() {
System.out.println("15亿像素摄像头让一切雀斑无可逃避!");
}
@Override
public void call() {
System.out.println("性感荷官在线呼叫");
}
@Override
public void likeB() {
System.out.println("榔头二代手机,逼格就是高!");
}
@Override
public String toString() {
return "HammerPhone_1st [chip=" + chip + ", screen=" + screen + ", camera=" + camera + ", system=" + system
+ "]";
}
}
public class HammerPhoneFactory_2nd implements PhoneFactory {
@Override
public Phone makePhone() {
Phone hammerPhone_2nd = new HammerPhone_2nd();
System.out.println(hammerPhone_2nd.toString());
return hammerPhone_2nd;
}
}
public class Order {
public static void main(String[] args) {
PhoneFactory hammerPhoneFactory_2nd = new HammerPhoneFactory_2nd();
hammerPhoneFactory_2nd.makePhone();
}
}
首先我们可以将上面的代码做一个简单的归类:
简单概括下工厂方法的创建步骤:
这里解释下为什么我喜欢使用抽象类:Java语言是对现实世界的一种映射,那么抽象类和接口就是对现实世界的行为进行一种抽象描述,抽象类更偏向于去映射名词类也就是客观存在的实物,而接口更加适合来描述某种行为或规律。这个区分是为了让Java的语义更加明确!
优点:
缺点:
简单工厂模式(simple factory) 实际上是针对工厂方法模式的一种简化,在我们谈到工厂方法的特点的时候,提到了每次新增一个产品就需要维护一个具体的产品实体和对应的实体工厂,这样的话在开发过程中创建了过多的类,增加了代码的复杂度。简单工厂模式就是用来解决过多的创建实体工厂的问题,他采用将所有实体工厂聚集到一个类或方法中,由业务选择具体需要创建哪种实体。
public interface SimpleFactory {
Phone makePhone(Integer type);
}
public class SimplePhoneFactory implements SimpleFactory {
private final static Integer hammerPhone_1st = 1;
private final static Integer hammerPhone_2nd = 2;
@Override
public Phone makePhone(Integer type) {
Phone phone = null;
if (type.equals(hammerPhone_1st)) {
phone = new HammerPhone_1st();
} else if (type.equals(hammerPhone_2nd)) {
phone = new HammerPhone_2nd();
}
System.out.println(phone.toString());
return phone;
}
}
public class Order {
public static void main(String[] args) {
SimpleFactory simplePhoneFactory = new SimplePhoneFactory();
Phone makePhone01 = simplePhoneFactory.makePhone(SimplePhoneFactory.hammerPhone_1st);
Phone makePhone02 = simplePhoneFactory.makePhone(SimplePhoneFactory.hammerPhone_2nd);
}
}
其实相较于工厂方法模式,简单工厂就是将工厂方法的创建结合到了一个简单工厂中,如果不明白的小伙伴可以对比下两种结构图就可以看出来区别。
优点:
缺点:
抽象工厂(abstract factory): 是指提供一个创建一系列产品组的接口,通过子类实现接口来达到生产不同产品组的目的。业务调用方只需要关注使用的工厂子类就可以分别创建不同的产品组。
抽象工厂模式与工厂方法模式最大的不同就是抽象工厂模式关注的是一整个产品家族的管理,而工厂方法模式关注的是单一产品的创建。这里我们对上面的手机相关业务做一个需求拓展来讲述什么是抽象工厂模式。
小龙同学的榔头手机最近卖的很火,很受市场的欢迎。于是小龙同学准备布局下一步产业:智能汽车。此时榔头这个企业下已经有了两种类别的产品分别是手机和汽车。
如果使用工厂方法模式来实现,我们需要对应的创建智能汽车相关的实体和工厂方法,并不便于我们统一管理维护,这个时候我们就可以采用抽象工厂的方式来实现。
public abstract class Car {
// 车轱辘
protected String tyre;
abstract void run();
}
public class HammersCar extends Car {
@Override
void run() {
System.out.println("榔头汽车开起来就是贼拉快!");
}
public HammersCar() {
System.out.println("榔头汽车已经创建");
}
}
public interface AbstractFactory {
Car makeCar();
Phone makePhone();
}
public class HammersAbstractFactory implements AbstractFactory {
@Override
public Car makeCar() {
Car hammersCar = new HammersCar();
return hammersCar;
}
@Override
public Phone makePhone() {
Phone hammerPhone_1st = new HammerPhone_1st();
System.out.println(hammerPhone_1st.toString());
return hammerPhone_1st;
}
}
public class Orders {
public static void main(String[] args) {
HammersAbstractFactory hammersAbstractFactory = new HammersAbstractFactory();
Car makeCar = hammersAbstractFactory.makeCar();
Phone makePhone = hammersAbstractFactory.makePhone();
}
}
老规矩,我们还是通过一个类的关系图进行描述
其实通过类图我们也可以看出抽象工厂和工厂方法主要区别就是在于抽象工厂是一个一对多的关系,他维护了一个产品的整个产品家族,可以通过一个抽象工厂获得你想要的相关产品的所有实例。
优点:
缺点:
总的来说,工厂方法和抽象工厂的创建过程相似,不过维护的对象粒度不同。工厂方法更适合单一对象的维护而抽象工厂跟适合一个产品系列的维护。
相同点:
不同点:
好了,今天的内容到此结束,如果还有疑问的同学可以私信我或在评论区留言,我会在第一时间为你解答。觉得有收获的小伙伴请记得一键三连,关注博主不要走丢,拒当白嫖党~