Glide源码阅读之空对象模式【EmptyModelLoader】【EmptyList<E>】
定义
在空对象模式(Null Object Pattern)中,一个空对象取代 NULL 对象实例的检查。Null 对象不是检查空值,而是反应一个不做任何动作的关系。这样的 Null 对象也可以在数据不可用的时候提供默认的行为。
在空对象模式中,我们创建一个指定各种要执行的操作的抽象类和扩展该类的实体类,还创建一个未对该类做任何实现的空对象类,该空对象类将无缝地使用在需要检查空值的地方。
已发现的空对象模式如下列表:
- EmptySet
- EmptyList
- EmptyMap<K, V>
- EmptyLibraryModule1
- EmptyLibraryModule2
- EmptyLibraryGlideModuleTest
- EMPTY_CALLBACKS
- EmptyAppModule
- EmptyModelLoader
EmptySet
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;
}
}
EmptyList
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;
}
}
EmptyMap<K, V>
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;
}
}
EmptyLibraryModule1
package com.bumptech.glide.test;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.LibraryGlideModule;
@GlideModule
public final class EmptyLibraryModule1 extends LibraryGlideModule {}
EmptyLibraryModule2
package com.bumptech.glide.test;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.LibraryGlideModule;
@GlideModule
public final class EmptyLibraryModule2 extends LibraryGlideModule {}
EmptyLibraryGlideModuleTest
/** Tests adding a single {@link com.bumptech.glide.module.LibraryGlideModule} in a project. */
@RunWith(JUnit4.class)
public class EmptyLibraryGlideModuleTest implements CompilationProvider {
EMPTY_CALLBACKS
private static final DecodeCallbacks EMPTY_CALLBACKS =
new DecodeCallbacks() {
@Override
public void onObtainBounds() {
// Do nothing.
}
@Override
public void onDecodeComplete(BitmapPool bitmapPool, Bitmap downsampled) {
// Do nothing.
}
};
EmptyAppModule
package com.bumptech.glide.test;
import com.bumptech.glide.annotation.GlideModule;
import com.bumptech.glide.module.AppGlideModule;
@GlideModule
public final class EmptyAppModule extends AppGlideModule {}
EmptyModelLoader
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 {}
总结
空对象模式的使用很是贯彻了面向对象编程的理念。
在使用逻辑上也很贴近业务的表达
面试
什么是面向对象编程
答:举例空对象模式回答即可。即高级的回答了面向对象编程的内涵,又侧面的凸显出对设计模式的理解和认识。比较好的加分项。当然如果技术面试官听得有些懵,那你还是老老实实把面向对象编程的定义进行教科书式的背诵。相信我你会碰到对设计模式不了解的面试官的。当然这也能从侧面探知到这家公司的技术实力在哪个层次。碰到这样的公司不用客气直接把预期待遇提高一个档次。
更多
单例模式
Glide设计模式之单例模式
空对象模式
Glide设计模式之空对象模式【EmptyModelLoader】【EmptyList<E>
建造者模式
Glide多种组合使用方式记录–没有全部亲测,大家可以根据实际需要选用
Glide设计模式之建造者(builder)模式1【GlideBuilder】
Glide设计模式之建造者(builder)模式2【RequestBuilder】
Glide设计模式之建造者(builder)模式3【RequestOptions】【BaseRequestOptions】
Glide设计模式之建造者(builder)模式4总结【MemorySizeCalculator】【GlideExecutor】【PreFillType】【LazyHeaders】
工厂模式
Glide设计模式之工厂模式1【ModelLoaderFactory】
Glide设计模式之工厂模式2【DiskCache.Factory】
Glide工厂模式3【TransitionFactory】【Transition】
Glide设计模式之工厂模式4总结
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?