工厂模式
-
作用:
- 实现了创建者和调用者的分离
- 详细分类:
- 简单工厂模式
- 工厂方法模式
- 抽象工厂模式
-
OOP七大原则
- 开闭原则:一个软件的实体应当对扩展开放
- 依赖倒转原则:要针对接口编程,不要准对实现编程
- 迪米特法则:只与你直接的朋友通信,而避免和陌生人通信
-
核心本质:
- 实例化对象不使用new,用工厂方法替代
- 将选择实现类,创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。
-
三种模式:
- 简单工厂模式
- 用来生产同一等级结构中的任意产品(对于增加新的产品,需要覆盖已有代码)
- 工厂方法模式
- 用来生产同一等级结构中的固定产品(支持增加任意产品)
- 抽象工厂模式
- 围绕一个超级工厂创建其它工厂。该超级工厂又称为其它工厂的工厂。
- 简单工厂模式
简单工厂模式
同一等级结构,就比如说我们的车,无论是五菱还是宝马,都属于同一等级结构,我们先来实现它。
public interface Car {
void name();
}
public class WulinCar implements Car {
public void name() {
System.out.println("五菱!!!");
}
}
public class BaomaCar implements Car {
public void name() {
System.out.println("宝马!");
}
}
通常我们获取对象的方法为:
public class Consumer {
public static void main(String[] args) {
Car car1 = new WulinCar();
Car car2 = new BaomaCar();
car1.name();
car2.name();
}
}
接下来我们使用简单工厂或来获取对象:
public class CarFactory {
public static Car getCar(String car){
if("wulin".equals(car)){
return new WulinCar();
}else if ("Baoma".equals(car)){
return new BaomaCar();
}
return null;
}
}
public class Consumer {
public static void main(String[] args) {
Car car1 = CarFactory.getCar("wulin");
Car car2 = CarFactory.getCar("Baoma");
car1.name();
car2.name();
}
}
到这里,简单工厂就已经完成了。
工厂方法模式
简单工厂模式违背了开闭原则,如果我们需要增加一个奔驰,这时候我们就需要对工厂的代码进行修改,违背了我们对内关闭修改的原则,而工厂方法模式,则是对这一问题的解决。
我们首先将车工厂抽取成接口:
public interface CarFactory {
Car getCar();
}
我们对每种车,都创建一个车工厂来获取实例:
public class BaomaFactory implements CarFactory {
public Car getCar() {
return new BaomaCar();
}
}
public class WulinFactory implements CarFactory {
public Car getCar() {
return new WulinCar();
}
}
接下来,我们创建对象
public class Consumer {
public static void main(String[] args) {
Car car1 = new WulinFactory().getCar();
Car car2 = new BaomaFactory().getCar();
car1.name();
car2.name();
}
}
完美遵循了开闭原则,我们添加一个奔驰的时候,无需对原有代码做任何修改,只需要为它创建一个工厂类实现工厂接口即可。
两种工厂的比较
无论从哪种方面来比较,简单工厂的复杂度都低于我们的工厂方法模式。
但是我们的工厂方法模式更加遵循设计原则。
真正使用时,大部分情况下我们都使用简单工厂,尽管它并没有完美遵循设计原则,但是它简单。
抽象工厂模式
-
定义:抽象工厂模式提供了一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类。
-
适用场景:
- 客户端(应用层)不依赖于产品类实例如何被创建,实现等细节。
- 强调一系列相关的产品对象(数与同一产品族)一起使用创建对象需要大量的重复代码。
- 提供一个产品类的库,所有的产品以同样的接口出现,从而使得客户端不依赖于具体的实现。
-
优点:
- 具体产品在应用层的代码隔离,无需关系创建细节。
- 将一个系列的产品统一到一起创建。
-
缺点:
- 规定了所有可能被创建的产品集合,产品簇中扩展新的产品困难;
- 增加了系统的抽象性和理解难度
我们使用一个简单的例子来说明一下抽象工厂模式。
这里我们有两个产品分别是手机和路由器,接口定义如下:
public interface IPhone {
void name();
}
public interface IRouter {
void name();
}
有两大厂商分别实现了这两种产品:
小米公司:
public class XiaoMiPone implements IPhone {
public void name() {
System.out.println("小米手机");
}
}
public class XiaoMiRouter implements IRouter {
public void name() {
System.out.println("小米路由器");
}
}
华为公司:
public class HuaWeiPhone implements IPhone {
public void name() {
System.out.println("华为手机");
}
}
public class HuaWeiRouter implements IRouter {
public void name() {
System.out.println("华为路由器");
}
}
我们定义一个抽象工厂,分别由两大厂商去实现:
public abstract class Factory {
abstract IPhone getIPhone();
abstract IRouter getIRouter();
}
小米公司:
public class XiaoMiFactory extends Factory {
IPhone getIPhone() {
return new XiaoMiPone();
}
IRouter getIRouter() {
return new XiaoMiRouter();
}
}
华为公司:
public class HuaWeiFactory extends Factory {
IPhone getIPhone() {
return new HuaWeiPhone();
}
IRouter getIRouter() {
return new HuaWeiRouter();
}
}
此时我们便可以借助不同厂商的工厂获取不同厂商的不同产品了
public class Consumer {
public static void main(String[] args) {
Factory huaWeiFactory = new HuaWeiFactory();
Factory xiaoMiFactory = new XiaoMiFactory();
IPhone phone1 = huaWeiFactory.getIPhone();
IPhone phone2 = xiaoMiFactory.getIPhone();
IRouter router1 = huaWeiFactory.getIRouter();
IRouter router2 = huaWeiFactory.getIRouter();
phone1.name();
phone2.name();
router1.name();
router2.name();
}
}
总结
-
小结:
- 简单工厂模式(静态工厂模式)
- 虽然某种程度上不符合设计原则,但实际使用最多!
- 工厂方法模式
- 不修改已有类的前提下,通过增加新的工厂类实现扩展。
- 抽象工厂模式
- 不可以增加产品,可以增加产品族!
- 简单工厂模式(静态工厂模式)
-
应用场景:
- JDK中Calendar的getInstance方法
- JDBC中的Connection对象的获取
- Spring中IOC容器创建管理bean对象
- 反射中Class对象的newInstance方法
关注微信公众号:危机很菜呀