在空对象模式(Null Object Pattern)中,一个空对象取代 NULL 对象实例的检查。Null 对象不是检查空值,而是反应一个不做任何动作的关系。这样的 Null 对象也可以在数据不可用的时候提供默认的行为。
在空对象模式中,我们创建一个指定各种要执行的操作的抽象类和扩展该类的实体类,还创建一个未对该类做任何实现的空对象类,该空对象类将无缝地使用在需要检查空值的地方。
private static class EmptySet<E> extends AbstractSet<E> implements Serializable { private static final long serialVersionUID = 1582296315990362920L; private EmptySet() { } public Iterator<E> iterator() { return Collections.emptyIterator(); } public int size() { return 0; } public boolean isEmpty() { return true; } public boolean contains(Object var1) { return false; } public boolean containsAll(Collection<?> var1) { return var1.isEmpty(); } public Object[] toArray() { return new Object[0]; } public <T> T[] toArray(T[] var1) { if (var1.length > 0) { var1[0] = null; } return var1; } public void forEach(Consumer<? super E> var1) { Objects.requireNonNull(var1); } public boolean removeIf(Predicate<? super E> var1) { Objects.requireNonNull(var1); return false; } public Spliterator<E> spliterator() { return Spliterators.emptySpliterator(); } private Object readResolve() { return Collections.EMPTY_SET; } }
public static final Set EMPTY_SET = new Collections.EmptySet(); public static final List EMPTY_LIST = new Collections.EmptyList(); public static final Map EMPTY_MAP = new Collections.EmptyMap(); public static final <T> List<T> emptyList() { return EMPTY_LIST; } private static class EmptyList<E> extends AbstractList<E> implements RandomAccess, Serializable { private static final long serialVersionUID = 8842843931221139166L; private EmptyList() { } public Iterator<E> iterator() { return Collections.emptyIterator(); } public ListIterator<E> listIterator() { return Collections.emptyListIterator(); } public int size() { return 0; } public boolean isEmpty() { return true; } public boolean contains(Object var1) { return false; } public boolean containsAll(Collection<?> var1) { return var1.isEmpty(); } public Object[] toArray() { return new Object[0]; } public <T> T[] toArray(T[] var1) { if (var1.length > 0) { var1[0] = null; } return var1; } public E get(int var1) { throw new IndexOutOfBoundsException("Index: " + var1); } public boolean equals(Object var1) { return var1 instanceof List && ((List)var1).isEmpty(); } public int hashCode() { return 1; } public boolean removeIf(Predicate<? super E> var1) { Objects.requireNonNull(var1); return false; } public void replaceAll(UnaryOperator<E> var1) { Objects.requireNonNull(var1); } public void sort(Comparator<? super E> var1) { } public void forEach(Consumer<? super E> var1) { Objects.requireNonNull(var1); } public Spliterator<E> spliterator() { return Spliterators.emptySpliterator(); } private Object readResolve() { return Collections.EMPTY_LIST; } }
private static class EmptyMap<K, V> extends AbstractMap<K, V> implements Serializable { private static final long serialVersionUID = 6428348081105594320L; private EmptyMap() { } public int size() { return 0; } public boolean isEmpty() { return true; } public boolean containsKey(Object var1) { return false; } public boolean containsValue(Object var1) { return false; } public V get(Object var1) { return null; } public Set<K> keySet() { return Collections.emptySet(); } public Collection<V> values() { return Collections.emptySet(); } public Set<Entry<K, V>> entrySet() { return Collections.emptySet(); } public boolean equals(Object var1) { return var1 instanceof Map && ((Map)var1).isEmpty(); } public int hashCode() { return 0; } public V getOrDefault(Object var1, V var2) { return var2; } public void forEach(BiConsumer<? super K, ? super V> var1) { Objects.requireNonNull(var1); } public void replaceAll(BiFunction<? super K, ? super V, ? extends V> var1) { Objects.requireNonNull(var1); } public V putIfAbsent(K var1, V var2) { throw new UnsupportedOperationException(); } public boolean remove(Object var1, Object var2) { throw new UnsupportedOperationException(); } public boolean replace(K var1, V var2, V var3) { throw new UnsupportedOperationException(); } public V replace(K var1, V var2) { throw new UnsupportedOperationException(); } public V computeIfAbsent(K var1, Function<? super K, ? extends V> var2) { throw new UnsupportedOperationException(); } public V computeIfPresent(K var1, BiFunction<? super K, ? super V, ? extends V> var2) { throw new UnsupportedOperationException(); } public V compute(K var1, BiFunction<? super K, ? super V, ? extends V> var2) { throw new UnsupportedOperationException(); } public V merge(K var1, V var2, BiFunction<? super V, ? super V, ? extends V> var3) { throw new UnsupportedOperationException(); } private Object readResolve() { return Collections.EMPTY_MAP; } }
package com.bumptech.glide.test; import com.bumptech.glide.annotation.GlideModule; import com.bumptech.glide.module.LibraryGlideModule; @GlideModule public final class EmptyLibraryModule1 extends LibraryGlideModule {}
package com.bumptech.glide.test; import com.bumptech.glide.annotation.GlideModule; import com.bumptech.glide.module.LibraryGlideModule; @GlideModule public final class EmptyLibraryModule2 extends LibraryGlideModule {}
/** Tests adding a single {@link com.bumptech.glide.module.LibraryGlideModule} in a project. */ @RunWith(JUnit4.class) public class EmptyLibraryGlideModuleTest implements CompilationProvider {
private static final DecodeCallbacks EMPTY_CALLBACKS = new DecodeCallbacks() { @Override public void onObtainBounds() { // Do nothing. } @Override public void onDecodeComplete(BitmapPool bitmapPool, Bitmap downsampled) { // Do nothing. } };
package com.bumptech.glide.test; import com.bumptech.glide.annotation.GlideModule; import com.bumptech.glide.module.AppGlideModule; @GlideModule public final class EmptyAppModule extends AppGlideModule {}
private static class EmptyModelLoader implements ModelLoader<Object, Object> { @Synthetic EmptyModelLoader() {} @Nullable @Override public LoadData<Object> buildLoadData( @NonNull Object o, int width, int height, @NonNull Options options) { return null; } @Override public boolean handles(@NonNull Object o) { return false; } }
package com.bumptech.glide.test; import com.bumptech.glide.annotation.GlideModule; import com.bumptech.glide.module.AppGlideModule; @GlideModule public final class EmptyAppModule extends AppGlideModule {}
空对象模式的使用很是贯彻了面向对象编程的理念。
在使用逻辑上也很贴近业务的表达
什么是面向对象编程
答:举例空对象模式回答即可。即高级的回答了面向对象编程的内涵,又侧面的凸显出对设计模式的理解和认识。比较好的加分项。当然如果技术面试官听得有些懵,那你还是老老实实把面向对象编程的定义进行教科书式的背诵。相信我你会碰到对设计模式不了解的面试官的。当然这也能从侧面探知到这家公司的技术实力在哪个层次。碰到这样的公司不用客气直接把预期待遇提高一个档次。