相信大家一定在开发中见过并且写过类似这样的代码:
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...
空对象模式(Null Object Pattern)是一种行为设计模式,它允许我们在不返回 null 的情况下提供默认行为。这种模式通常用于需要处理 null 对象的情况下,以避免NullPointerException 异常。 在软件设计中,我们经常...
23种java版设计模式源码案例.zip 0.目录 创建型模式(creational) 简单工厂(simplefactory) 动态工厂(dynamic) 抽象工厂(abstract) 单例模式(singleton) 建造者模式(builder) 原型模式(prototype) 结构型模式...
所以很少存在简单重复的工作,加上Java 代码的精炼性和面向对象纯洁性(设计模式是 java 的灵魂),编程工作将变成一个让你时刻 体验创造快感的激动人心的过程. 为能和大家能共同探讨"设计模式",我将自己在学习中的心得...
Java中,有23种GOF(Gang of Four)设计模式,分为创建型、结构型和行为型三大类。今天我们将聚焦于其中的三种:工厂模式、单例模式和观察者模式。 **1. 工厂模式** 工厂模式是一种创建型设计模式,它提供了一种...
在Java面试中,设计模式是衡量开发者能力的重要标准,因为它们能够提高代码的可读性、可维护性和复用性。以下是根据提供的内容对几种常见设计模式的详细说明: 1. **Singleton(单例模式)**: - 单例模式确保一个...
Java设计模式是软件开发中的一种重要思想,它是一种在特定情境下解决常见问题的模板,可以提高代码的可重用性、可维护性和灵活性。在Java中,设计模式主要分为三大类:创建型、结构型和行为型。下面将详细讨论在给定...
Java单例模式是一种常用的设计模式,它保证一个类只有一个实例,并提供全局访问点。这种模式在需要频繁创建和销毁对象的场景中,或者当对象昂贵时(如数据库连接),能够节省系统资源,提高效率。本篇文章将深入探讨...
Java设计模式中的单例模式是一种常用的创建型设计模式,它保证了类只有一个实例,并提供一个全局访问点。这种模式在很多场景下非常有用,比如控制共享资源、管理配置信息等。接下来,我们将深入探讨8种不同的单例...
总结来说,代理模式是Java设计模式中的重要一环,它提供了扩展和控制对象行为的能力。无论是静态代理还是动态代理,都能够帮助我们在不触及核心业务代码的前提下,实现功能增强和控制。理解并熟练运用代理模式,对于...
Java中的单例模式是一种常用的软件设计模式,它保证一个类只有一个实例,并提供全局访问点。在Java编程中,单例模式常用于控制资源的访问,比如数据库连接池、线程池或者日志对象等。本篇文章将深入探讨如何在Java中...
### Java操作数据库方式与设计模式应用 #### 一、Java操作数据库基础:JDBC **JDBC(Java Database Connectivity)**是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写...
总的来说,Java 代理模式是通过代理类来增强或扩展目标类功能的一种设计模式,尤其适用于需要在调用前后添加额外逻辑的场景。通过深入理解代理模式和其在房屋买卖场景中的应用,我们可以更好地掌握这一重要的设计...
设计模式 0.目录 创建型模式(creational) 简单工厂(simplefactory) 动态工厂(dynamic) 抽象工厂(abstract) 单例模式(singleton) 建造者模式(builder) 原型模式(prototype) 结构型模式(structure) 适配器模式(adaptor...
### 设计模式——通俗易懂的解读 #### 引言 设计模式是在软件工程领域内广泛应用的一种编程思想,它能够帮助开发者解决常见的编程难题,并提供一套成熟、经过验证的解决方案。设计模式通常被分为三大类:创建型...
Java设计模式中的Flyweight模式是一种结构型模式,其主要目的是减少对象的数量,通过共享大量具有相似属性的对象来节省内存和提高性能。Flyweight模式的核心思想是区分对象的内部状态(intrinsic state)和外部状态...
《设计模式:可复用面向对象软件的基础》(Design Patterns: Elements of Reusable Object-Oriented Software)是设计模式领域的经典著作,由Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides四位作者合著...
Java 监视器模式(Java Monitor Pattern)是一种用于多线程环境中的设计模式,它主要依赖于Java语言的同步机制,如`synchronized`关键字和`wait()`, `notify()`等方法,来确保线程安全和资源的有序访问。在Java中,...