设计模式-装饰器模式

1. 装饰器模式 模式的本质是在不改变原有对象的基础上对原有的基础上进行方法或属性的增强。

例如 实现 使用装饰器模式实现 remove List 元素的记录 , HistorySet中只加了remove方法的处理逻辑,其他的方法没有动,使用的依然是Set原来的方法。体现出装饰器模式对原有对象增强的作用。

java 复制代码
import java.util.*;

///  装饰器模式

public class HistorySet<E> implements Set<E> {

    private List<E> removeList = new ArrayList<E>();

    // 代理对象
    private final Set<E> delegate ;

    // 代理对象
    public HistorySet(Set<E> sets) {
        this.delegate = sets;
    }


    @Override
    public int size() {
        return 0;
    }

    @Override
    public boolean isEmpty() {
        return false;
    }

    @Override
    public boolean contains(Object o) {
        return false;
    }

    @Override
    public Iterator<E> iterator() {
        return null;
    }

    @Override
    public Object[] toArray() {
        return new Object[0];
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return null;
    }

    @Override
    public boolean add(E e) {
        return delegate.add(e);
    }

    @Override
    public boolean remove(Object o) {
        Boolean remove = delegate.remove(o);
        if(remove){
            removeList.add( (E)o );
            return true;
        }

        return false;
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return false;
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        return false;
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return false;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return false;
    }

    @Override
    public void clear() {

    }

    @Override
    public String toString() {
        return "HistorySet{" +
                "removeList=" + removeList +
                ", sets=" + delegate +
                '}';
    }
}
  1. 示例代码

例如 实现 使用装饰器模式实现 remove List 元素的记录 , HistorySet中只加了remove方法的处理逻辑,其他的方法没有动,使用的依然是Set原来的方法。体现出装饰器模式对原有对象增强的作用。

java 复制代码
import java.lang.reflect.Array;
import java.util.*;

public class Main {

    public static void main(String[] args) {

        Set<String> historySet = new HistorySet<>(new HashSet<>());
         // 记录 remove 的 元素的方法
        Set<String> set = new HistorySet<>(historySet);
       
        set.add("a");
        set.add("b");
        set.add("c");
        set.add("d");

        set.remove("a");
        set.remove("b");
        set.remove("c");
  System.out.println(set);
    }

}

代码运行结果:

HistorySet{removeList=[a, b, c], sets=HistorySet{removeList=[a, b, c], sets=[d]}}

2. JDK中的实现 装饰器模式

java 复制代码
 // 将普通的list 包装成 线程安全的 List    
Collection<Object> synchronizedList = Collections.synchronizedCollection(new ArrayList<>());

可以看到其底层是对代码的实现进行线程安全的增强(Synchronized 锁的增强),并没有改变原有的集合的方法实现。

java 复制代码
        SynchronizedCollection(Collection<E> c, Object mutex) {
            this.c = Objects.requireNonNull(c);
            this.mutex = Objects.requireNonNull(mutex);
        }

        public int size() {
            synchronized (mutex) {return c.size();}
        }
        public boolean isEmpty() {
            synchronized (mutex) {return c.isEmpty();}
        }
        public boolean contains(Object o) {
            synchronized (mutex) {return c.contains(o);}
        }
        public Object[] toArray() {
            synchronized (mutex) {return c.toArray();}
        }
        public <T> T[] toArray(T[] a) {
            synchronized (mutex) {return c.toArray(a);}
        }
        public <T> T[] toArray(IntFunction<T[]> f) {
            synchronized (mutex) {return c.toArray(f);}
        }

        public Iterator<E> iterator() {
            return c.iterator(); // Must be manually synched by user!
        }

        public boolean add(E e) {
            synchronized (mutex) {return c.add(e);}
        }
        public boolean remove(Object o) {
            synchronized (mutex) {return c.remove(o);}
        }

        public boolean containsAll(Collection<?> coll) {
            synchronized (mutex) {return c.containsAll(coll);}
        }
        public boolean addAll(Collection<? extends E> coll) {
            synchronized (mutex) {return c.addAll(coll);}
        }
        public boolean removeAll(Collection<?> coll) {
            synchronized (mutex) {return c.removeAll(coll);}
        }
        public boolean retainAll(Collection<?> coll) {
            synchronized (mutex) {return c.retainAll(coll);}
        }
        public void clear() {
            synchronized (mutex) {c.clear();}
        }
        public String toString() {
            synchronized (mutex) {return c.toString();}
        }
        // Override default methods in Collection
        @Override
        public void forEach(Consumer<? super E> consumer) {
            synchronized (mutex) {c.forEach(consumer);}
        }
        @Override
        public boolean removeIf(Predicate<? super E> filter) {
            synchronized (mutex) {return c.removeIf(filter);}
        }
        @Override
        public Spliterator<E> spliterator() {
            return c.spliterator(); // Must be manually synched by user!
        }
        @Override
        public Stream<E> stream() {
            return c.stream(); // Must be manually synched by user!
        }
        @Override
        public Stream<E> parallelStream() {
            return c.parallelStream(); // Must be manually synched by user!
        }
        @java.io.Serial
        private void writeObject(ObjectOutputStream s) throws IOException {
            synchronized (mutex) {s.defaultWriteObject();}
        }
    }

    /**
     * Returns a synchronized (thread-safe) set backed by the specified
     * set.  In order to guarantee serial access, it is critical that
     * <strong>all</strong> access to the backing set is accomplished
     * through the returned set.<p>
     *
     * It is imperative that the user manually synchronize on the returned
     * collection when traversing it via {@link Iterator}, {@link Spliterator}
     * or {@link Stream}:
     * <pre>
     *  Set s = Collections.synchronizedSet(new HashSet());
     *      ...
     *  synchronized (s) {
     *      Iterator i = s.iterator(); // Must be in the synchronized block
     *      while (i.hasNext())
     *          foo(i.next());
     *  }
     * </pre>
     * Failure to follow this advice may result in non-deterministic behavior.
     *
     * <p>The returned set will be serializable if the specified set is
     * serializable.
     *
     * @param  <T> the class of the objects in the set
     * @param  s the set to be "wrapped" in a synchronized set.
     * @return a synchronized view of the specified set.
     */
    public static <T> Set<T> synchronizedSet(Set<T> s) {
        return new SynchronizedSet<>(s);
    }

    static <T> Set<T> synchronizedSet(Set<T> s, Object mutex) {
        return new SynchronizedSet<>(s, mutex);
    }

    /**
     * @serial include
     */
    static class SynchronizedSet<E>
          extends SynchronizedCollection<E>
          implements Set<E> {
        @java.io.Serial
        private static final long serialVersionUID = 487447009682186044L;

        SynchronizedSet(Set<E> s) {
            super(s);
        }
        SynchronizedSet(Set<E> s, Object mutex) {
            super(s, mutex);
        }

        public boolean equals(Object o) {
            if (this == o)
                return true;
            synchronized (mutex) {return c.equals(o);}
        }

BufferReader 封装的Read 等方法,实现 文件从缓存区里面读取。

java 复制代码
 
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 从缓冲区中读取数据
 */
public class BufferedFileInputStream extends InputStream {

    private final byte[] buffer = new byte[8192];

    private final FileInputStream fileInputStream;

    private int position = -1;

    private int capacity = -1;

    public BufferedFileInputStream(FileInputStream fileInputStream) {
        this.fileInputStream = fileInputStream;
    }

    @Override
    public int read() throws IOException {

        if ( bufferCanRead() ) {
         return readFromBuffer() ;
        }
        refreshBuffer();

        if(!bufferCanRead()){
            return -1;
        }

        return readFromBuffer() ;
    }

    private int readFromBuffer() {
        //                          去掉符号位
        return buffer[position++] & 0xFF ;
    }

    private void refreshBuffer() throws IOException {
        // 读取 的大小
        capacity  = this.fileInputStream.read(buffer);
        position  = 0;
        // 置位读取
    }

    private boolean bufferCanRead() {
        if(capacity == -1||position == capacity){
            return false;
        }
        // position在 capacity 前
        return true;
    }

    @Override
    public void close() throws IOException {
        super.close();
    }
}

3. SpringBoot 中装饰器模式的使用 和 封装

首先会进入到 InvocableHandlerMethod 方法中 其中的 resolvers 是进行真正的参数解析逻辑,

java 复制代码
public class InvocableHandlerMethod extends HandlerMethod {

	private static final Object[] EMPTY_ARGS = new Object[0];

	private static final Class<?>[] EMPTY_GROUPS = new Class<?>[0];


	private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();

	private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

	@Nullable
	private WebDataBinderFactory dataBinderFactory;

	@Nullable
	private MethodValidator methodValidator;

	private Class<?>[] validationGroups = EMPTY_GROUPS;

这个Composite 是一个经典的组合模式,里面有一个HandlerMethodArgumentResolver 的List ,通过这个list找到真正的解析方法,对参数进行解析。

java 复制代码
/*
 * Copyright 2002-2023 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.web.method.support;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;

/**
 * Resolves method parameters by delegating to a list of registered
 * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}.
 * Previously resolved method parameters are cached for faster lookups.
 *
 * @author Rossen Stoyanchev
 * @author Juergen Hoeller
 * @since 3.1
 */
public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgumentResolver {

	private final List<HandlerMethodArgumentResolver> argumentResolvers = new ArrayList<>();

	private final Map<MethodParameter, HandlerMethodArgumentResolver> argumentResolverCache =
			new ConcurrentHashMap<>(256);


	/**
	 * Add the given {@link HandlerMethodArgumentResolver}.
	 */
	public HandlerMethodArgumentResolverComposite addResolver(HandlerMethodArgumentResolver resolver) {
		this.argumentResolvers.add(resolver);
		return this;
	}

	/**
	 * Add the given {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}.
	 * @since 4.3
	 */
	public HandlerMethodArgumentResolverComposite addResolvers(
			@Nullable HandlerMethodArgumentResolver... resolvers) {

		if (resolvers != null) {
			Collections.addAll(this.argumentResolvers, resolvers);
		}
		return this;
	}

	/**
	 * Add the given {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}.
	 */
	public HandlerMethodArgumentResolverComposite addResolvers(
			@Nullable List<? extends HandlerMethodArgumentResolver> resolvers) {

		if (resolvers != null) {
			this.argumentResolvers.addAll(resolvers);
		}
		return this;
	}

	/**
	 * Return a read-only list with the contained resolvers, or an empty list.
	 */
	public List<HandlerMethodArgumentResolver> getResolvers() {
		return Collections.unmodifiableList(this.argumentResolvers);
	}

	/**
	 * Clear the list of configured resolvers and the resolver cache.
	 * @since 4.3
	 */
	public void clear() {
		this.argumentResolvers.clear();
		this.argumentResolverCache.clear();
	}


	/**
	 * Whether the given {@linkplain MethodParameter method parameter} is
	 * supported by any registered {@link HandlerMethodArgumentResolver}.
	 */
	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		return getArgumentResolver(parameter) != null;
	}

	/**
	 * Iterate over registered
	 * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}
	 * and invoke the one that supports it.
	 * @throws IllegalArgumentException if no suitable argument resolver is found
	 */
	@Override
	@Nullable
	public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
			NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {

		HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
		if (resolver == null) {
			throw new IllegalArgumentException("Unsupported parameter type [" +
					parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
		}
		return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
	}

	/**
	 * Find a registered {@link HandlerMethodArgumentResolver} that supports
	 * the given method parameter.
	 */
	@Nullable
	public HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
		HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
		if (result == null) {
			for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
				if (resolver.supportsParameter(parameter)) {
					result = resolver;
					this.argumentResolverCache.put(parameter, result);
					break;
				}
			}
		}
		return result;
	}

}

实现真正意义上的参数的map形成。

java 复制代码
	public HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
		HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
		if (result == null) {
			for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
				if (resolver.supportsParameter(parameter)) {
					result = resolver;
					this.argumentResolverCache.put(parameter, result);
					break;
				}
			}
		}
		return result;
	}

而在 RequestResponseBodyMethodProcessor 这个类 (这个类继承了上面的ArugmentRsolver ) 中 必然会有相应的两个方法,以下下就是

java 复制代码
    public boolean supportsReturnType(MethodParameter returnType) {
        return AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class);
    }


    @Nullable
    public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
        parameter = parameter.nestedIfOptional();
        Object arg = this.readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
        if (binderFactory != null) {
            String name = Conventions.getVariableNameForParameter(parameter);
            ResolvableType type = ResolvableType.forMethodParameter(parameter);
            WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name, type);
            if (arg != null) {
                this.validateIfApplicable(binder, parameter);
                if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {
                    throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
                }
            }

            if (mavContainer != null) {
                mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
            }
        }

        return this.adaptArgumentIfNecessary(arg, parameter);
    }

因此我们实现继承 HanlderMethodArgumentResolver类 ,实现这两个方法

java 复制代码
public class TimestmpRequestBodyMethodProcesor implements HandlerMethodArgumentResolver {


    private RequestResponseBodyMethodProcessor processor;


    private ApplicationContext applicationContext;

    public TimestmpRequestBodyMethodProcesor(ApplicationContext applicationContext ) {
     this.applicationContext = applicationContext;
    }


    public TimestmpRequestBodyMethodProcesor(RequestResponseBodyMethodProcessor processor) {
        this.processor = processor;
    }

    // 装饰器
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(TimestampRequestBody.class);
    }
    //
    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {
        
        setupProcessor();

        Object result = processor.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
        if( !(result instanceof Map<?,?>) ) {
            return result;
        }
       // 装饰器的本质
        ((Map) result).put("timestamp", System.currentTimeMillis());


        return result;
    }

    private void setupProcessor() {

        if(this.processor != null) {
         return;
        }
            RequestMappingHandlerAdapter adapter = this.applicationContext.getBean(RequestMappingHandlerAdapter.class);

            List<HandlerMethodArgumentResolver> argumentResolvers = adapter.getArgumentResolvers();

            for (HandlerMethodArgumentResolver argumentResolver : argumentResolvers) {
                if(argumentResolver instanceof RequestResponseBodyMethodProcessor) {
                    this.processor = (RequestResponseBodyMethodProcessor) argumentResolver;
                    return;
                }
            }
        }

}

实现自定义注解

java 复制代码
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TimestampRequestBody {

}