设计模式(六)设计模式的常见应用

  本系列文章共分为六篇:
    设计模式(一)设计模式的分类与区别
    设计模式(二)创建型模式介绍及实例
    设计模式(三)结构型模式介绍及实例
    设计模式(四)行为型模式介绍及实例(上)
    设计模式(五)行为型模式介绍及实例(下)
    设计模式(六)设计模式的常见应用

一、Spring框架中种的设计模式

  • 1、简单工厂模式
      BeanFactory就是简单工厂模式的体现,根据传入一个唯一标识来获得Bean对象。
@Override
public Object getBean(String name) throws BeansException {
    assertBeanFactoryActive();
    return getBeanFactory().getBean(name);
}
  • 2、单例模式
      Spring中bean的默认作用域就是singleton(单例)的。
      Spring 通过 ConcurrentHashMap 实现单例注册表的特殊方式实现单例模式。Spring 实现单例的核心代码:
    // 通过 ConcurrentHashMap(线程安全) 实现单例注册表
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);
    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "'beanName' must not be null");
        synchronized (this.singletonObjects) {
            // 检查缓存中是否存在实例 
            Object singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
                //...省略了很多代码
               try {
                   singletonObject = singletonFactory.getObject();
               }
               //...省略了很多代码
               // 如果实例对象在不存在,我们注册到单例注册表中。
              addSingleton(beanName, singletonObject);
           }
           return (singletonObject != NULL_OBJECT ? singletonObject : null);
       }
   }
   
   //将对象添加到单例注册表
   protected void addSingleton(String beanName, Object singletonObject) {
       synchronized (this.singletonObjects) {
          this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
       }
   }
}
  • 3、适配器模式
      SpringMVC中的适配器HandlerAdatper 。由于应用会有多个Controller实现,如果需要直接调用Controller方法,那么需要先判断是由哪一个Controller处理请求,然后调用相应的方法。当增加新的Controller,需要修改原来的逻辑,违反了开闭原则(对修改关闭,对扩展开放)。
      为此,Spring提供了一个适配器接口,每一种Controller对应一种HandlerAdapter实现类。当请求过来,SpringMVC会调用getHandler()获取相应Controller,然后获取该Controller对应的HandlerAdapter,最后调用HandlerAdapter的 handle()方法处理请求,实际上调用的是Controller的handleRequest() 。每次添加新的Controller时,只需要增加一个适配器类就可以,无需修改原有的逻辑。
      常用的处理器适配器: SimpleControllerHandlerAdapter、HttpRequestHandlerAdapter 、AnnotationMethodHandlerAdapter 。
  • 4、代理模式
      Spring AOP就是基于动态代理的,如果要代理的对象实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象.而对于没有实现接口的对象,Spring AOP会使用Cglib,这时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理

      使用AOP之后可以把一些通用的功能抽象出来,在在需要用到的地方直接使用即可,这样大大简化了代码量。需要增加新功能时也方便,这样也提高了系统扩展性。日志功能、事务管理等等场景都用到了 AOP 。
  • 5、观察者模式
      Spring中observer模式常用的地方是listener的实现,如ApplicationListener。
  • 6、模板方法模式
      用来解决代码重复的问题。比如: JmsTemplate、HibernateTemplate。
      比如在使用JdbcTemplate时,开发者只要关注业务代码的实现(增删改查等),数据库的连接、断开等操作不用再关注。

二、JDK中的设计模式

2.1 创建型模式

  • 1、抽象工厂模式
      比如java.util.Calendar的getInstance()方法:
    public static Calendar getInstance()
    {
        return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
    }

    private static Calendar createCalendar(TimeZone zone,
                                           Locale aLocale)
    {
        CalendarProvider provider =
            LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                                 .getCalendarProvider();
        if (provider != null) {
            try {
                return provider.getInstance(zone, aLocale);
            } catch (IllegalArgumentException iae) {
            }
        }

        Calendar cal = null;

        if (aLocale.hasExtensions()) {
            String caltype = aLocale.getUnicodeLocaleType("ca");
            if (caltype != null) {
                switch (caltype) {
                case "buddhist":
                cal = new BuddhistCalendar(zone, aLocale);
                    break;
                case "japanese":
                    cal = new JapaneseImperialCalendar(zone, aLocale);
                    break;
                case "gregory":
                    cal = new GregorianCalendar(zone, aLocale);
                    break;
                }
            }
        }
        if (cal == null) {
            if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
                cal = new BuddhistCalendar(zone, aLocale);
            } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                       && aLocale.getCountry() == "JP") {
                cal = new JapaneseImperialCalendar(zone, aLocale);
            } else {
                cal = new GregorianCalendar(zone, aLocale);
            }
        }
        return cal;
    }

  可以看出,调用Calendar.getInstance方法时,调用到的createCalendar方法就是根据不同国家地区返回对应的日期子类。

  • 2、工厂方法模式
      比如java.lang.Integer的valueOf(String)方法:
    public static Integer valueOf(String s) throws NumberFormatException {
        return Integer.valueOf(parseInt(s, 10));
    }

  parseInt(s,10)方法是按10进制将传进来的字符串参数转换成int数字。因此,整个valueOf(String)方法整体上看:传进来一个参数,创建出一个对象,即是工厂方法模式。

  • 3、单例模式
      比如java.lang.Runtime的getRuntime()方法:
    private static Runtime currentRuntime = new Runtime();

    public static Runtime getRuntime() {
        return currentRuntime;
    }
  • 4、原型模式
      比如Java中的Cloneable接口。

2.2 结构型模式

  • 1、适配器模式
      比如:InputStreamReader、OutputStreamWriter。
  • 2、装饰器模式
      比如java.io.BufferedInputStream的BufferedInputStream(InputStream)方法:
    public BufferedInputStream(InputStream in) {
        this(in, DEFAULT_BUFFER_SIZE);
    }
    
    public BufferedInputStream(InputStream in, int size) {
        super(in);
        if (size <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        buf = new byte[size];
    }

  BufferedInputStream的父类是FilterInputStream,FilterInputStream的父类是InputStream。因此,BufferedInputStream的构造方法就是在不影响正常的功能的情况下,增加一些附属功能,典型的装饰模式。

  • 3、外观模式
      比如java.util.logging。
  • 4、享元模式
      比如Integer.valueOf。

2.3 行为型模式

  • 1、策略模式
      比如线程池的四种拒绝策略、java.util.Comparator的compare()方法:
    int compare(T o1, T o2);

  Comparator是个接口,继承该接口的类可以自己去定义比较元素的方法。

  • 2、模板方法模式
      InputStream、OutputStream、AQS等。
      比如java.io.InputStream的read(byte b[], int off, int len)方法:
    public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }

  该方法定义了固定的方法步骤,但是其中的read()方法是abstract的,不同的实现类可以实现自己的read方法。

  • 3、迭代器模式
      比如java.util.Iterator,通过迭代器方式进行遍历时,调用的就是该方法里声明的接口:
public interface Iterator<E> {

    boolean hasNext();

    E next();

    default void remove() {
        throw new UnsupportedOperationException("remove");
    }
    
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}
  • 4、命令模式
      如线程池中的Runnable、Callable等。
  • 5、责任链模式
      比如java.util.logging.Logger的log()方法:
    public void log(Level level, String msg) {
        if (!isLoggable(level)) {
            return;
        }
        LogRecord lr = new LogRecord(level, msg);
        doLog(lr);
    }

    private void doLog(LogRecord lr) {
        lr.setLoggerName(name);
        final LoggerBundle lb = getEffectiveLoggerBundle();
        final ResourceBundle  bundle = lb.userBundle;
        final String ebname = lb.resourceBundleName;
        if (ebname != null && bundle != null) {
            lr.setResourceBundleName(ebname);
            lr.setResourceBundle(bundle);
        }
        log(lr);
    }

    public void log(LogRecord record) {
        if (!isLoggable(record.getLevel())) {
            return;
        }
        Filter theFilter = filter;
        if (theFilter != null && !theFilter.isLoggable(record)) {
            return;
        }
		//...省略一些代码
    }

  在log(LogRecord record)里,已经看到了链式的处理。

  • 6、解释器模式
      比如java.util.regex.Pattern的compile(String regex)方法:
    public static Pattern compile(String regex) {
        return new Pattern(regex, 0);
    }

    private Pattern(String p, int f) {
        pattern = p;
        flags = f;

        // to use UNICODE_CASE if UNICODE_CHARACTER_CLASS present
        if ((flags & UNICODE_CHARACTER_CLASS) != 0)
            flags |= UNICODE_CASE;

        // Reset group index count
        capturingGroupCount = 1;
        localCount = 0;

        if (pattern.length() > 0) {
            compile();
        } else {
            root = new Start(lastAccept);
            matchRoot = lastAccept;
        }
    }

  compile()方法就是解析regex的过程。

  • 7、中介者模式
      java.util.concurrent.Executor#execute()。
      java.util.concurrent.ExecutorService#submit()。
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值