ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

几种设计模式

2021-10-24 12:57:58  阅读:106  来源: 互联网

标签:对象 创建 模式 几种 设计模式 public 模板


设计模式
为什么学习设计模式
应对面试中的设计模式相关问题;告别写被人吐槽的烂代码;提高复杂代码的设计和开发能力;让读源码、学框架事半功倍;为你的职场发展做铺垫。

设计模式作用
解耦
创建型设计模式
将创建和使用代码解耦

单例模式
一个类只允许创建一个实例,这个类就是单例类

为什么使用单例(why,when)
控制对于共享资源的顺序访问
降低内存、文件句柄等资源的开销
有些数据在系统中只应保存一份
如何实现单例(hwo)
懒汉(延迟加载)
饿汉(预先加载,早失败,早发现)
双重检查机制(减少锁的冲突)
静态类(懒加载 Holder里实例化)
枚举(最简单优雅)
单例有什么问题
如何理解单例唯一性
指进程内的唯一实例,进程间是不唯一的。
实现线程唯一实例
思路是用ConcurrentHashMap,key:线程ID,value为要创建的实例
java中有ThreadLoca实现线程唯一实例
实现集群唯一实例
进程间唯一,其实就是分布式唯一
多例模式
一个类可以创建多个对象,但是个数是有限制的
使用静态块+hashMap定义
使用concurrentHashMap定义
工厂模式
分类
简单工厂
创建一个工厂类,根据类型来返回不同对象
每次创建一个新对象
每次创建
类比:某手机店1个橱柜,摆放各式手机
工厂方法
创建多个工厂类,负责创建对应的对象
类比:某手机店n个橱柜,每个橱柜摆放对应款式手机
抽象工厂
创建一个综合工厂,创建多种类型的对象
类比:大型商超,里面有手机店,有电脑店,有家电店。
何时使用
当创建逻辑比较复杂,考虑使用工厂模式,封装对象的创建过程,将对象的创建和使用相分离。
如规则配置解析,存在多个if-else,根据不同的类型创建不同对象,将if-else创建对象的逻辑放到工厂类中
如果创建对象的逻辑不复杂,考虑简单工厂
如果创建对象的逻辑复杂,考虑工厂方法
单个对象本身创建较为复杂,需要组合其他类对象,做各种初始化操作
是否要使用工厂模式
封装变化:创建逻辑有可能变化,封装成工厂类之后,创建逻辑的变更对调用者透明。
代码复用:创建代码抽离到独立的工厂类之后可以复用。
隔离复杂性:封装复杂的创建逻辑,调用者无需了解如何创建对象。
控制复杂度:将创建代码抽离出来,让原本的函数或类职责更单一,代码更简洁。
建造者模式builder
可以把校验逻辑放置到 Builder 类中,先创建建造者,并且通过 set() 方法设置建造者的变量值,然后在使用 build() 方法真正创建对象之前,做集中的校验,校验通过之后才会创建对象

为什么使用建造者模式 why
避免过度参数导致的可读性和易用性
容易执行约束条件,校验逻辑
实现类对象不可变
避免对象的无效状态
工厂模式与建造者模式区别
工厂模式是用来创建不同但是相关类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创建哪种类型的对象。建造者模式是用来创建一种类型的复杂对象,可以通过设置不同的可选参数,“定制化”地创建不同的对象。
原型模式
如果对象的创建成本比较大,而同一个类的不同对象之间差别不大(大部分字段都相同),在这种情况下,我们可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新对象,以达到节省创建时间的目的

基于原型来创建对象的方式就叫作原型设计模式(Prototype Design Pattern),简称原型模式。

何为“对象的创建成本比较大”?
对象中的数据需要经过复杂的计算才能得到(比如排序、计算哈希值),或者需要从 RPC、网络、数据库、文件系统等非常慢速的 IO 中读取
结构型设计模式
将不同功能代码解耦

行为型设计模式
将不同行为代码解耦

行为型设计模式解决的就是“类或对象之间的交互”问题。

观察者模式
模板模式
作用
复用
所有子类可以复用父类中提供的模板方法的代码
扩展
框架通过模板模式提供功能扩展点,让框架用户可以在不修改框架源码情况下,基于扩展点定制化框架功能
回调 vs 模板模式
回调的优势

像 Java 这种只支持单继承的语言,基于模板模式编写的子类,已经继承了一个父类,不再具有继承的能力。
回调可以使用匿名类来创建回调对象,可以不用事先定义类;而模板模式针对不同的实现都要定义不同的子类。
如果某个类中定义了多个模板方法,每个方法都有对应的抽象方法,那即便我们只用到其中的一个模板方法,子类也必须实现所有的抽象方法。而回调就更加灵活,我们只需要往用到的模板方法中注入回调对象即可。
策略模式
职责链模式
在职责链模式中,多个处理器依次处理同一个请求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。

职责链模式常用在框架开发中,用来实现框架的过滤器、拦截器功能

三种职责链常用的应用场景:过滤器(Servlet Filter)、拦截器(Spring Interceptor)、插件(MyBatis Plugin)。

Servlet Filter 采用递归来实现拦截方法前后添加逻辑

Spring Interceptor 的实现比较简单,把拦截方法前后要添加的逻辑放到两个方法中实现

MyBatis Plugin 采用嵌套动态代理的方法来实现,实现思路很有技巧。

状态模式
迭代器模式
访问者模式
备忘录模式
命令模式
解释器模式
中介模式
JDK中的设计模式
Calendar建造者模式和工厂模式
既然已经有了 getInstance() 工厂方法来创建 Calendar 类对象,为什么还要用 Builder 来创建 Calendar 类对象呢

建造者模式用于定制化创建复杂的对象,而工厂模式用于创建不同但相关类型的对象。本身不冲突。我们点了特级牛排,依然可以随心搭配喜欢的酱。

从 Calendar 这个例子,我们也能学到,不要过于死板地套用各种模式的原理和实现,不要不敢做丝毫的改动。模式是死的,用的人是活的。在实际上的项目开发中,不仅各种模式可以混合在一起使用,而且具体的代码实现,也可以根据具体的功能需求做灵活的调整。

Collections装饰器模式和适配器模式
为什么说 UnmodifiableCollection 类是 Collection 类的装饰器类呢?

UnmodifiableCollection 类可以算是对 Collection 类的一种功能增强,但这点还不具备足够的说服力来断定 UnmodifiableCollection

UnmodifiableCollection 的构造函数接收一个 Collection 类对象,然后对其所有的函数进行了包裹(Wrap):重新实现(比如 add() 函数)或者简单封装(比如 stream() 函数)。而简单的接口实现或者继承,并不会如此来实现 UnmodifiableCollection 类。所以,从代码实现的角度来说,UnmodifiableCollection 类是典型的装饰器类。

java.util.Collections#enumeration方法体现了适配器模式。Enumeration是适配器接口,Iterator是其适配实现。Enumeration类和enumeration方法存在的意义在于兼容旧版本的jdk代码升级到新版本时的兼容。

public static <T> Enumeration<T> enumeration(final Collection<T> c) {
    return new Enumeration<T>() {
        private final Iterator<T> i = c.iterator();

        public boolean hasMoreElements() {
            return i.hasNext();
        }

        public T nextElement() {
            return i.next();
        }
    };
}

Collections.sort模板模式,策略模式
sort方法传入comparator可以认为是模板方法的实现,同时也可以认为是一种算法,策略

    List<Student> students = new ArrayList<>();
    students.add(new Student("Alice", 19, 89.0f));
    students.add(new Student("Peter", 20, 78.0f));
    students.add(new Student("Leo", 18, 99.0f));

    Collections.sort(students, new AgeAscComparator());

最终调用模板方法compare的地方

private static <T> int countRunAndMakeAscending(T[] a, int lo, int hi,
                                                Comparator<? super T> c) {
    assert lo < hi;
    int runHi = lo + 1;
    if (runHi == hi)
        return 1;

    // Find end of run, and reverse range if descending
    if (c.compare(a[runHi++], a[lo]) < 0) { // Descending
        while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) < 0)
            runHi++;
        reverseRange(a, lo, runHi);
    } else {                              // Ascending
        while (runHi < hi && c.compare(a[runHi], a[runHi - 1]) >= 0)
            runHi++;
    }

    return runHi - lo;
}

观察者模式

jdk中的观察者模式实现。有可能新加入的观察者会miss通知,参看notifyObservers方法
Observer/Observable
调用notifyObservers前先调用setChanged,否则不会通知,why?
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an Observable object’s
* notifyObservers method to have all the object’s
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the notifyObservers
* method.
*/
void update(Observable o, Object arg);
}
private boolean changed = false;
protected synchronized void setChanged() {
changed = true;
}

public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;

    synchronized (this) {
        /* We don't want the Observer doing callbacks into
         * arbitrary code while holding its own Monitor.
         * The code where we extract each Observable from
         * the Vector and store the state of the Observer
         * needs synchronization, but notifying observers
         * does not (should not).  The worst result of any
         * potential race-condition here is that:
         * 1) a newly-added Observer will miss a
         *   notification in progress
         * 2) a recently unregistered Observer will be
         *   wrongly notified when it doesn't care
         */
        if (!changed)
            return;
        arrLocal = obs.toArray();
        clearChanged();
    }

    for (int i = arrLocal.length-1; i>=0; i--)
        ((Observer)arrLocal[i]).update(this, arg);
}

单例模式

Runtime.getRuntime

  • Every Java application has a single instance of class
  • Runtime that allows the application to interface with
  • the environment in which the application is running. The current
  • runtime can be obtained from the getRuntime method.
  • An application cannot create its own instance of this class.
    private static Runtime currentRuntime = new Runtime();
    public static Runtime getRuntime() {
    return currentRuntime;
    }
    private Runtime() {}

模板模式

Java Servlet
Junit TestCase
Java InputStream
Java AbstractList
享元模式

Integer -128~127
String常量池
职责链模式

Servlet Filter
Spring interceptor
迭代器模式

Iterator
Guava 中的设计模式
建造者模式CacheBuilder

Wrapper模式(代理模式、装饰器、适配器模式)

缺省的Wrapper实现,如com.google.common.collect.ForwardingCollection等,这样用户类继承这些缺省类后,只需实现接口中的少量方法。
Immutable模式

一个对象的状态在对象创建之后就不再改变,这就是所谓的不变模式
对应的是不变类,不变对象
java中String是不变类
普通不变模式,内部引用对象可变
深度不变模式,内部引用对象也不可变
构建
所有成员变量通过构造函数一次性设置好,不暴露set等修改成员变量的方法
不变模式常用在多线程环境下,因为不存在并发安全问题,所以避免加锁
Guava不变集合类ImmutableCollection、ImmutableList、ImmutableSet、ImmutableMap
与Jdk的不变类区别是jdk中对原集合修改会体现在早先创建的不变集合中,而guava的则会拷贝出新的集合,拷贝后对原集合的改动不会体现在新的集合中
Spring框架中的设计模式
经典设计思想或原则
框架的作用:利用框架的好处有:解耦业务和非业务开发、让程序员聚焦在业务开发上;隐藏复杂实现细节、降低开发难度、减少代码 bug;实现代码复用、节省开发时间;规范化标准化项目开发、降低学习和维护成本等等。简言之:简化开发

约定优于配置
使用默认配置,对于偏离默认配置的项目显式配置

低侵入松耦合
IOC容器替换,利用AOP技术来做非业务功能

模块化,轻量级
模块划分做得好,低耦合,可单独引入其中的模块,非常轻量级。

再封装、再抽象
Spring Data , Spring JDBC,Spring Cache DataAccessException

支持可扩展的2种设计模式
观察者模式 使用IOC容器的publishEvent特性

在监听者程序中使用异步,以防阻塞事件发布者

public class DemoEvent extends ApplicationEvent {
private String message;

public DemoEvent(Object source, String message) {
    super(source);
    this.message = message;
}

public String getMessage() {
    return this.message;
}

}

@Component
public class DemoPublisher {
@Autowired
private ApplicationContext applicationContext;

public void publishEvent(DemoEvent demoEvent) {
    this.applicationContext.publishEvent(demoEvent);
}

}

@Component
public class DemoListener implements ApplicationListener {
@Override
public void onApplicationEvent(DemoEvent demoEvent) {
String message = demoEvent.getMessage();
System.out.println(message);
}
}
模板模式, 回调式的模板模式

将要执行的函数封装成对象(比如,初始化方法封装成 InitializingBean 对象),传递给模板(BeanFactory)来执行。

Spring bean生命周期图

Spring框架用到的11种设计模式
适配器模式 Spring web mvc中对于多种Controller实现,采用适配器模式,统一处理接口

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	if (this.handlerAdapters != null) {
		for (HandlerAdapter adapter : this.handlerAdapters) {
			if (adapter.supports(handler)) {
				return adapter;
			}
		}
	}
	throw new ServletException("No adapter for handler [" + handler +
			"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

public class SimpleServletHandlerAdapter implements HandlerAdapter {

@Override
public boolean supports(Object handler) {
	return (handler instanceof Servlet);
}

@Override
@Nullable
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {

	((Servlet) handler).service(request, response);
	return null;
}

@Override
public long getLastModified(HttpServletRequest request, Object handler) {
	return -1;
}

}

标签:对象,创建,模式,几种,设计模式,public,模板
来源: https://blog.csdn.net/qq_35911118/article/details/119312792

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有