定义
空对象用于创建一个代表空或无效对象的实例,而无需使用 null。这个模式允许在对象不存在或不可用时提供默认行为,同时避免了对空引用的检查。
意图
大多数面向对象的编程语言(如Java或C#)中,引用可能为null。在调用任何方法之前,需要检查这些引用确保它们不是null,因为通常无法在null引用上调用方法。而不是使用null引用来表示对象的缺失(例如,一个不存在的客户),可以使用实现了期望接口但其方法体为空的对象。这种方法的优势在于相比于一个工作中的默认实现,空对象是非常可预测的,没有任何副作用:它什么都不做。
参与者(角色)
-
抽象类或接口(Abstract Class or Interface): 定义了具体实现对象的接口或抽象类。
-
具体对象(Concrete Objects): 实现了抽象类或接口的具体类。
-
空对象(Null Object): 实现了抽象类或接口,但其方法体为空。通常在需要引用对象但不想或不能使用实际对象时使用空对象,以确保不会出现Null引用异常。
举例
已创建订单为例
类图:

这个例子中对应类的角色如下:
-
抽象类或接口(Abstract Class or Interface): Order
-
具体对象(Concrete Objects): RealOrder
-
空对象(Null Object): NullOrder
Order类 ,抽象类
public abstract class Order {
String orderId;
void process(String orderId) {
}
}
RealOrder类
@Slf4j
public class RealOrder extends Order{
public RealOrder(String orderId) {
this.orderId=orderId;
}
@Override
public void process(String orderId) {
log.info("订单处理成功,订单id:{}",orderId);
}
}
NullOrder空对象类
@Slf4j
public class NullOrder extends Order{
public NullOrder(String orderId) {
this.orderId=orderId;
}
@Override
public void process(String orderId) {
log.info("订单不存在,订单id:{}",orderId);
}
}
OrderFactory订单工厂
public class OrderFactory {
static List datas = List.of("1","3","5","6");
static Order getOrder(String orderId){
boolean match = datas.stream().anyMatch(o -> o.equals(orderId));
if(match)
return new RealOrder(orderId);
else
return new NullOrder(orderId);
}
}
测试
对与不存在订单也可以和存在的定义一样处理,而不用单独做判断
public class App {
public static void main(String[] args) {
List<Order> orders = new ArrayList();
orders.add(OrderFactory.getOrder("1"));
orders.add(OrderFactory.getOrder("3"));
orders.add(OrderFactory.getOrder("7"));
orders.forEach(o -> o.process(o.orderId));
}
}

优点
-
避免空引用异常: 空对象确保在需要对象引用但没有实际对象时不会出现空引用异常。
-
简化代码: 可以减少在代码中进行空值检查的需求,简化了对空对象的处理。
-
预测性: 空对象的行为是明确的且无副作用,因此在使用空对象时更可预测。
-
隐藏实现细节: 可以隐藏在特定情况下的空对象实现细节,使使用者无需关注特定对象是否为空。
-
默认行为: 可以提供默认行为,使系统在没有实际对象时有一个可行的默认实现。
缺点
- 引入了更多的类,可能导致系统变得复杂
空对象模式的应用
java Optional
public static void main(String[] args) {
Person person =null;
Optional<Person> optional = Optional.ofNullable(person);
log.info("option is null:{}",optional.isEmpty());
log.info("option is persent:{}",optional.isPresent());
Person person1 = optional.orElse(new Person());
person1.setName("zlennon");
log.info("defalut value:{}",person1.toString());
}
分享到: