相信大家一定在开发中见过并且写过类似这样的代码:
public Book getBook(int id) { if (id < 0) { return null; } return new Book(1, "Design Pattern", 100);
Book book = getBook(-1); if (book != null) { }
系统在使用对象的相关功能时,总要检查对象是否为null,如果不为null,我们才会调用它的相关方法,完成某种逻辑。这样的检查在一个系统中出现很多次,相信任何一个设计者都不愿意看到这样的情况。为了解决这种问题,我们可以可以引入空对象,这样,我们就可以摆脱大量程式化的代码,对代码的可读性也是一个飞跃。
等等,空对象是什么?它和null什么关系?
空对象是一个没有实质性内容的对象,但他并不为null。你可以把空对象理解为一个空箱子,这个物品还是存在的,只不过仅仅是一个壳,没有实质性的东西。
我们需要对原有的代码进行重构,把所有返回null的地方都替换成返回一个与之对应的空对象,然后再客户端调用时不再使用book==null这种方式判断是否为空,而是替换成book.isNull()的方式。下面我们就一步一步来实现这种模式。
首先,我们需要定义一个Nullable接口:
public interface Nullable { /** * 对象是否为空 * @return */ public boolean isNull(); }
这个接口定义了一个isNull()的方法,来表示一个对象是否为空。
然后我们让Book实现此接口:
public class Book implements Nullable { private int id; private String name; private double price; public Book() { } public Book(int id, String name, double price) { this.id = id; this.name = name; this.price = price; } @Override public boolean isNull() { return false; } /** * 创建一个NullBook实例代表空对象 * @return */ public static Book createNullBook() { return new NullBook(); } /** * setters & getters */ }
在Book中实现了isNull()方法,并返回false;另外Book还定义了一个静态的createNullBook方法,返回了一个NullBook的实例,NullBook是什么呢,我们来看一下:
public class NullBook extends Book { @Override public boolean isNull() { return true; } }
NullBook继承了Book,并在isNull()方法中返回true,这个NullBook其实就是我们上面提到的空对象,仅仅是个空箱子而已。
然后我们定义一个BookService类,用以模拟获取Book的接口方法:
public class BookService { public Book getBook(int id) { if (id < 0) { //返回一个空对象 return Book.createNullBook(); } return new Book(id, "Design Pattern", 100); } }
在getBook(int id)中,如果id<0时,则返回一个NullBook的实例,在客户端调用isNull()方法时则返回true,表示是空对象;如果id>=0时,则返回一个Book的实例,在客户端调用isNull()方法时则返回false,表示对象不为空,可以调用相关方法取得数据。对于我们的客户端来讲,返回的都是一个Book类型的对象,我们并不清楚返回的到底是真正的Book实例还是空对象NullBook实例,但是我们并不担心,因为有一点可以肯定的是,我们都可以放心的调用isNull()方法,因为它会根据运行期对象的类型返回一个正确的值。
多态的最根本好处在于:你不必再向对象询问“你是什么类型”而后根据得到的答案调用对象的某个行为,你只管调用该行为就是了,其他的一切事情多态机制会为你妥善处理。
最后再来看一下客户端是如何实现对象为空的判断的:
public class Client { public static void main(String[] args) { BookService service = new BookService(); Book book = service.getBook(-1); if (book.isNull()) { System.out.println("not found!"); } else { System.out.println("name:" + book.getName()); System.out.println("price:" + book.getPrice()); } } }
除了定义isNull()之外,我们还可以使用另外一种方式来完成“检查对象是否为null”的功能。
我们需要先定义一个Null接口,这个接口不需要定义任何方法,仅仅是标志着对象是否为空对象:
public interface Null { }
然后我们的Book类现在不再需要实现任何接口了,它仅仅是一个普通的JavaBean,我们只需新增一个这样的NullBook类:
public class NullBook extends Book implements Null{ }
修改相应的方法:
public Book getBook(int id) { if (id < 0) { //返回一个空对象 return new NullBook(); } return new Book(id, "Design Pattern", 100); }
然后在客户端这样使用:
if (book instanceof NullBook) { }
通常,不在万不得已的情况下,我们应该尽量避免使用instanceof操作符,但在这种情况下,我们也提倡使用它,因为这种做法有一个好处就是,不需要修改Book源码,这么一来,即使无法修改Book,我们也可以使用空对象。
相关推荐
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。 工厂模式(Factory Pattern) 抽象工厂模式...
用Java实现23种设计模式 1. 创建型模式 工厂模式(Factory Pattern) 抽象工厂模式(Abstract Factory Pattern) 单例模式(Singleton Pattern) 建造者模式(Builder Pattern) 原型模式(Prototype Pattern)...
java常用设计模式及JDK与CGLIB实现动态代理区别(源码) /** * 使用cglib动态代理 * @author * */ public class BookFacadeProxy implements MethodInterceptor{ private Object target; @Override public...
23种java版设计模式源码案例.zip 0.目录 创建型模式(creational) 简单工厂(simplefactory) 动态工厂(dynamic) 抽象工厂(abstract) 单例模式(singleton) 建造者模式(builder) 原型模式(prototype) 结构型模式...
工厂模式是我们最常用的模式了,著名的Jive论坛 ,就大量使用了工厂模式,工厂模式在Java程序系统可以说是随处可见。 为什么工厂模式是如此常用?因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成...
NULL 博文链接:https://stelin.iteye.com/blog/933147
设计模式 0.目录 创建型模式(creational) 简单工厂(simplefactory) 动态工厂(dynamic) 抽象工厂(abstract) 单例模式(singleton) 建造者模式(builder) 原型模式(prototype) 结构型模式(structure) 适配器模式(adaptor...
Java 中的设计模式在 Java 中实现各种设计模式。结构设计模式结构设计模式是定义不同对象和类如何组合以形成更大结构的蓝图。[复合] (复合/)[享元] (享元/) [私有类数据] (PrivateClassData/) [代理] (代理/)创造性...
所以很少存在简单重复的工作,加上Java 代码的精炼性和面向对象纯洁性(设计模式是 java 的灵魂),编程工作将变成一个让你时刻 体验创造快感的激动人心的过程. 为能和大家能共同探讨"设计模式",我将自己在学习中的心得...
第21章 COMMAND模式和ACTIVE OBJECT模式:多功能与多任务 第22章 TEMPLATE METHOD模式和STRATEGY模式:继承和委托 第23章 FACADE模式和MEDIATOR模式 第24章 SINGLETON模式和MONOSTATE模式 第25章 NULL OBJECT模式 ...
1. 以下代码是某种设计模式的一种实现方式: public class LazyModel { private static LazyModel instance =null; private static Object lock = new Object(); private LazyModel(){ } public static ...
第17章 NULL OBJECT模式 第18章 薪水支付案例研究:第一次迭代开始 第19章 薪水支付案例研究:实现 第四部分 打包薪水支付系统 第20章 包的设计原则 第21章 FACTORY模式 第22章 薪水支付案例研究(第2部分) 第五...
在空对象模式(Null Object Pattern)中,一个空对象取代 NULL 对象实例的检查。Null 对象不是检查空值,而是反应一个不做任何动作的关系。这样的 Null 对象也可以在数据不可用的时候提供默认的行为。 在空对象模式...
第17章 NULL OBJECT模式 第18章 薪水支付案例研究:第一次迭代开始 第19章 薪水支付案例研究:实现 第四部分 打包薪水支付系统 第20章 包的设计原则 第21章 FACTORY模式 第22章 薪水支付案例研究(第2部分) 第...
创意设计模式 -- Abstract Factory - Done -- Builder - Done -- Factory Method -- Object Pool -- Prototype - Done -- Singleton - Done 结构设计模式 -- Adapter -- Bridge -- Composite -- Decorator - Done ...
第十七章 NULL OBJECT模式 第十八章 薪水支付案例研究:第一次迭代开始 第十九章 薪水支付案例研究:实现 第Ⅳ部分 打包薪水支付系统 第二十章 包的设计原则 第二十一章 FACTORY模式 第二十二章 薪水支付案例研究...
JAVA相关基础知识 1、面向对象的特征有哪些方面 1.抽象: 抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地注意与当前目标有关的方面。抽象并不打算了解全部问题,而只是选择其中的一部分,暂时不用...
第6章 Java的类(Class)和对象(Object) 132 教学视频:59分钟 6.1 驾驶汽车向类(Class)的世界进发 132 6.1.1 汽车带来的问题 132 6.1.1 类的组成 134 6.1.3 使用自定义的Car类 136 6.1.4 类和对象 139 ...