核心:
1、实例化对象不再用new,用工厂方法
2、选择实现类,创建对象统一管理和控制,从而将调用者跟实现类解耦。调用者不用知道实现类的细节,直接使用即可,实现细节交给工厂。
这两句话很重要,我们在后面代码中会体会到。
工厂模式又可分为三种模式:
(1)简单工厂模式
(2)工厂方法模式
(3)抽象工厂模式
所属类型:创建型模式(new对象的作用)
这里我们用消费者买车的案例,小明要买车,从大众和长安汽车选一辆,我们先用原始的接口和实现类来写,先分析有哪些对象:Consumer对象,DZCar对象,CACar对象,Car接口
public class Consumer {
public static void main(String[] args) {
Car car1 = new CACar();
Car car2 = new DZCar();
car1.name();
car2.name();
}
}
//长安
public class CACar implements Car{
@Override
public void name() {
System.out.println("长安汽车");
}
}
//大众
public class DZCar implements Car{
@Override
public void name() {
System.out.println("大众汽车");
}
}
public interface Car {
void name();
}
运行Consumer结果
但是这里还需要自己new,也就是自己要写具体实现类,如果是买车的话,消费者怎么会自己实现一个车呢,如果会造车,还要买干啥,所以造车就交给工厂,我们买的是工厂生产组装后的车,也就是具体怎么实现这个车的细节交给工厂,如下
public class CarFactory {
public static Car getCar(String carName){
if(carName.equals("长安汽车")){
return new CACar();
}else if (carName.equals("大众汽车")){
return new DZCar();
}else {
return null;
}
}
}
Consumer.java修改为如下
public class Consumer {
public static void main(String[] args) {
Car car1 = CarFactory.getCar("长安汽车");
Car car2 = CarFactory.getCar("大众汽车");
car1.name();
car2.name();
}
}
结果相同,但是这就符合工厂模式了,消费者买车,就直接说一个车名就行,具体这个车怎么造的交给工厂,消费者拿到造好的车就行,上面就是一个简单工厂模式,很容易理解,但是如果消费者又想看看其他车,那么就要新增几行代码,再加一个else if
,这明显就不符合开发的开闭原则,就是扩展时不能修改原有代码,所以简单工厂模式只是理解一下工厂模式大概是什么,接下来介绍工厂方法模式,让其符合开闭原则(对扩展开放,对修改关闭,修改是不能对原有代码修改)。
简而言之,就是每种车都有自己的工厂,而不是所有车共用一个工厂,更符合我们现在的生活,什么牌子汽车都来自自己的车工厂,所以CarFactory变成一个公共接口,创建多个车工厂实现这个接口。
//工厂方法模式
public interface CarFactory {
Car getCar();
}
//大众车工厂
public class DZFactory implements CarFactory{
@Override
public Car getCar() {
return new DZCar();
}
}
//长安车工厂
public class CAFactory implements CarFactory{
@Override
public Car getCar() {
return new CACar();
}
}
public class Consumer {
public static void main(String[] args) {
Car car1 = new CAFactory().getCar();
Car car2 = new DZFactory().getCar();
car1.name();
car2.name();
}
}
运行结果如下
相比简单工厂模式只有一个工厂,工厂方法模式有多个工厂,运行后结果相同,但是设计不同,这里就用到工厂方法模式,符合开闭原则(对扩展开放,对修改关闭),逻辑上也更符合现实情况,什么牌子车对应什么牌子车工厂制造,而不是只有一个工厂,如果消费者想再看看宝马车,那么就直接创建一个宝马类和宝马车工厂即可,无需改动原有代码。
public class BMWCar implements Car{
@Override
public void name() {
System.out.println("宝马汽车");
}
}
public class BMWFactory implements CarFactory{
@Override
public Car getCar() {
return new BMWCar();
}
}
public class Consumer {
public static void main(String[] args) {
Car car1 = new CAFactory().getCar();
Car car2 = new DZFactory().getCar();
car1.name();
car2.name();
Car car3 = new BMWFactory().getCar();
car3.name();
}
}
这样工厂方法模式确实符合了开闭原则,新增代码不会改动原来代码,但是会有一个问题,如果一直新增类,比如几十个牌子的车,那类会太多,太庞大,导致过于复杂,所以有时为了简单,虽然不符合设计原则,但也会直接设计成简单工厂模式,并且这种情况还不少。
抽象工厂就是对产品功能的抽象,上层设计只需设计有哪些功能,具体功能实现交给工厂去做。比如有两个产品接口,手机和路由器
//手机产品
public interface PhoneProduct {
void playGame();//玩游戏
void call();//打电话
void sendMsg();//发消息
}
//路由器产品
public interface RouteProduct {
void openWlan();//打开Wlan
void setWlanPwd();//设置wlan密码
}
//小米手机
public class XiaoMiPhone implements PhoneProduct{
@Override
public void playGame() {
System.out.println("小米手机玩游戏");
}
@Override
public void call() {
System.out.println("小米手机打电话");
}
@Override
public void sendMsg() {
System.out.println("小米手机发短信");
}
}
//华为手机
public class HuaWeiPhone implements PhoneProduct{
@Override
public void playGame() {
System.out.println("华为手机玩游戏");
}
@Override
public void call() {
System.out.println("华为手机打电话");
}
@Override
public void sendMsg() {
System.out.println("华为手机发短信");
}
}
//小米路由器
public class XiaoMiRoute implements RouteProduct{
@Override
public void openWlan() {
System.out.println("小米路由器连接wlan");
}
@Override
public void setWlanPwd() {
System.out.println("小米路由器设置密码");
}
}
//华为路由器
public class HuaWeiRoute implements RouteProduct{
@Override
public void openWlan() {
System.out.println("华为路由器连接wlan");
}
@Override
public void setWlanPwd() {
System.out.println("华为路由器设置密码");
}
}
这里就是一个工厂可以生产很多产品,具体怎么生产不用抽象产品工厂管,具体工厂去实现生产就行
//抽象产品工厂(抽象工厂模式,这里就是抽象的抽象,ProductFactory 是接口,内部也是接口,也就是不关注实现,自身设计有哪些功能行为即可)
public interface ProductFactory {
PhoneProduct phoneProduct();//生产手机
RouteProduct routeProduct();//生产路由器
}
//小米工厂
public class XiaoMiFactory implements ProductFactory{
@Override
public PhoneProduct phoneProduct() {
return new XiaoMiPhone();
}
@Override
public RouteProduct routeProduct() {
return new XiaoMiRoute();
}
}
//华为工厂
public class HuaWeiFactory implements ProductFactory{
@Override
public PhoneProduct phoneProduct() {
return new HuaWeiPhone();
}
@Override
public RouteProduct routeProduct() {
return new HuaWeiRoute();
}
}
public class Client {
public static void main(String[] args) {
System.out.println("=========小米系列产品=========");
PhoneProduct phoneProduct = new XiaoMiFactory().phoneProduct();//小米工厂生产手机
phoneProduct.sendMsg();
phoneProduct.call();
phoneProduct.playGame();
RouteProduct routeProduct = new XiaoMiFactory().routeProduct();//工厂生产
routeProduct.openWlan();
routeProduct.setWlanPwd();
System.out.println("=========华为系列产品=========");
PhoneProduct phoneProduct1 = new HuaWeiFactory().phoneProduct();
phoneProduct1.playGame();
phoneProduct1.call();
}
}
如果需要生产一个新的产品,比如造车,那么只要在ProductFactory新增carProduct()即可,然后交给具体工厂实现即可,不会修改原有代码,只要新增对应功能即可,但新增后可能需要其所有实现类进行实现,所以抽象工厂模式适用于长期稳定的生产某些指定产品,不会频繁变动需要生产的产品,比如设计之初就生产手机和路由器,不生产别的,那么抽象工厂就非常适合,也十分强大。
具体用哪种工厂模式,根据具体实际业务决定。
参考视频:https://www.bilibili.com/video/BV1mc411h719?p=3