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

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

1、设计模式是什么,设计模式有什么作用?

  设计模式是一套被反复使用的、多数人知晓的优秀代码设计经验的总结,是一种特定环境下特定问题的处理方法。

 设计模式的作用:

  1. 重用设计和代码
     重用设计比重用代码更有意义,自动带来代码重用;
  2. 提高扩展性
     大量使用面向接口编程,预留扩展插槽,新的功能或特性很容易加入到系统中来;
  3. 提高灵活性
     通过组合提高灵活性,可允许代码修改平稳发生,对一处修改不会波及到其他模块;
  4. 提高开发效率
     正确使用设计模式,可以节省大量的时间。

2、基本的Java编程设计应遵循的规则?

  1. 面向接口编程(提高扩展性);
  2. 优先使用依赖、组合、聚合等方式,不用继承(降低耦合性)。

关于依赖、组合、聚合等方式,可参考设计模式(一)设计模式的分类与区别

3、Spring 框架中都用到了哪些设计模式?

 Spring框架中使用到了大量的设计模式,下面列举了比较有代表性的:

  • 1、代理模式
      Spring AOP就是基于动态代理的,如果要代理的对象实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,Spring AOP会使用Cglib,这时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理
    在这里插入图片描述
      使用AOP之后可以把一些通用的功能抽象出来,在在需要用到的地方直接使用即可,这样大大简化了代码量。需要增加新功能时也方便,这样也提高了系统扩展性。日志功能、事务管理等等场景都用到了 AOP 。
  • 2、单例模式
      Spring 中 bean 的默认作用域就是 singleton(单例)的。
  • 3、模板方法模式
      用来解决代码重复的问题。比如: JmsTemplate、HibernateTemplate。
      比如在使用JdbcTemplate时,开发者只要关注业务代码的实现(增删改查等),数据库的连接、断开等操作不用再关注。
  • 4、工厂模式
      用BeanFactory、ApplicationContext来创建对象的实例。
  • 5、观察者模式
      Spring 事件驱动模型就是观察者模式很经典的一个应用,比如,ContextStartedEvent 就是 ApplicationContext 启动后触发的事件。
  • 6、适配器模式
      Spring MVC 中也是用到了适配器模式适配 Controller。

4、请列举出在 JDK 中几个常用的设计模式?

4.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方法就是根据不同国家地区返回对应的日期子类。

4.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)方法整体上看:传进来一个参数,创建出一个对象,即是工厂方法模式。

4.3 单例模式

  比如java.lang.Runtime的getRuntime()方法:

    private static Runtime currentRuntime = new Runtime();

    public static Runtime getRuntime() {
    
    
        return currentRuntime;
    }

4.4 装饰模式

  比如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的构造方法就是在不影响正常的功能的情况下,增加一些附属功能,典型的装饰模式。

4.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)里,已经看到了链式的处理。

4.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的过程。

4.7 迭代器模式

  比如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.8 策略模式

  比如java.util.Comparator的compare()方法:

    int compare(T o1, T o2);

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

4.9 模板方法模式

  比如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方法。

猜你喜欢

转载自blog.csdn.net/m0_37741420/article/details/110133201