http://www.cnblogs.com/softidea/p/5716870.html

什么是ApplicationContext? 
它是Spring的核心,Context我们通常解释为上下文环境,但是理解成容器会更好些。 
ApplicationContext则是应用的容器。

Spring把Bean(object)放在容器中,需要用就通过get方法取出来。

ApplicationEvent

是个抽象类,里面只有一个构造函数和一个长整型的timestamp。

ApplicationListener

是一个接口,里面只有一个onApplicationEvent方法。

所以自己的类在实现该接口的时候,要实装该方法。

 

如果在上下文中部署一个实现了ApplicationListener接口的bean,

那么每当在一个ApplicationEvent发布到 ApplicationContext时,
这个bean得到通知。其实这就是标准的Oberver设计模式。

一个Demo:

package com;import org.springframework.context.ApplicationEvent;/*** Created by MyWorld on 2016/7/31.*/
public class DemoEvent extends ApplicationEvent{public DemoEvent(Object source) {super(source);}
}

package com;import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;/*** Created by MyWorld on 2016/7/31.*/
@Component
public class DemoObserver1 implements ApplicationListener<DemoEvent> {@Overridepublic void onApplicationEvent(DemoEvent demoEvent) {System.out.println(this.getClass().getCanonicalName() + " receive: " + demoEvent.getSource());}
}

package com;import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;/*** Created by MyWorld on 2016/7/31.*/
@Component
public class DemoObserver2 implements ApplicationListener<DemoEvent> {@Overridepublic void onApplicationEvent(DemoEvent demoEvent) {System.out.println(this.getClass().getCanonicalName() + " receive: " + demoEvent.getSource());}
}

package com;import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;/*** Created by MyWorld on 2016/7/31.*/
@Component
public class DemoSubject implements ApplicationEventPublisherAware {private ApplicationEventPublisher eventPublisher;@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {this.eventPublisher = applicationEventPublisher;}public void publish() {eventPublisher.publishEvent(new DemoEvent("Hello world!"));}
}

测试类:

package com;import com.DemoConfig;
import com.DemoSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;/*** Created by MyWorld on 2016/7/31.*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {DemoConfig.class})
public class DemoSubjectTest {@Autowiredprivate DemoSubject demoSubject;@Testpublic void testPublish() throws Exception {demoSubject.publish();}
}

执行结果:

"C:\Program Files\Java\jdk1.8.0_65\bin\java" -ea -Didea.launcher.port=7535 "-Didea.launcher.bin.path=D:\Program Files\JetBrains\IntelliJ IDEA 14.1.6\bin" -Dfile.encoding=GBK -classpath "D:\Program Files\JetBrains\IntelliJ IDEA 14.1.6\lib\idea_rt.jar;D:\Program Files\JetBrains\IntelliJ IDEA 14.1.6\plugins\junit\lib\junit-rt.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\rt.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\access-bridge.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_65\jre\lib\ext\zipfs.jar;D:\source\git\EventDemo\target\test-classes;D:\source\git\EventDemo\target\classes;G:\java\repository\org\springframework\spring-context\4.1.6.RELEASE\spring-context-4.1.6.RELEASE.jar;G:\java\repository\org\springframework\spring-aop\4.1.6.RELEASE\spring-aop-4.1.6.RELEASE.jar;G:\java\repository\aopalliance\aopalliance\1.0\aopalliance-1.0.jar;G:\java\repository\org\springframework\spring-beans\4.1.6.RELEASE\spring-beans-4.1.6.RELEASE.jar;G:\java\repository\org\springframework\spring-core\4.1.6.RELEASE\spring-core-4.1.6.RELEASE.jar;G:\java\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;G:\java\repository\org\springframework\spring-expression\4.1.6.RELEASE\spring-expression-4.1.6.RELEASE.jar;G:\java\repository\org\springframework\spring-test\4.1.6.RELEASE\spring-test-4.1.6.RELEASE.jar;G:\java\repository\junit\junit\4.12\junit-4.12.jar;G:\java\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.intellij.rt.execution.application.AppMain com.intellij.rt.execution.junit.JUnitStarter -ideVersion5 com.DemoSubjectTest
七月 31, 2016 1:50:40 下午 org.springframework.test.context.support.DefaultTestContextBootstrapper getDefaultTestExecutionListenerClassNames
信息: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
七月 31, 2016 1:50:40 下午 org.springframework.test.context.support.DefaultTestContextBootstrapper instantiateListeners
信息: Could not instantiate TestExecutionListener [org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttribute]
七月 31, 2016 1:50:40 下午 org.springframework.test.context.support.DefaultTestContextBootstrapper instantiateListeners
信息: Could not instantiate TestExecutionListener [org.springframework.test.context.transaction.TransactionalTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [org/springframework/transaction/interceptor/TransactionAttributeSource]
七月 31, 2016 1:50:40 下午 org.springframework.test.context.support.DefaultTestContextBootstrapper instantiateListeners
信息: Could not instantiate TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener]. Specify custom listener classes or make the default listener classes (and their required dependencies) available. Offending class: [javax/servlet/ServletContext]
七月 31, 2016 1:50:40 下午 org.springframework.test.context.support.DefaultTestContextBootstrapper getTestExecutionListeners
信息: Using TestExecutionListeners: [org.springframework.test.context.support.DependencyInjectionTestExecutionListener@17246de, org.springframework.test.context.support.DirtiesContextTestExecutionListener@f67ac7]
七月 31, 2016 1:50:40 下午 org.springframework.context.support.GenericApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.GenericApplicationContext@1b6a447: startup date [Sun Jul 31 13:50:40 CST 2016]; root of context hierarchy
com.DemoObserver1 receive: Hello world!
com.DemoObserver2 receive: Hello world!Process finished with exit code 0

代码:https://github.com/helloworldtang/EventDemo.git

首先,什么是观察者模式:多个观察者去监听主题,当主题发生变化的时候,主题会通知所有的观察者。 
盗用网上的一个图:

从上图的结构可以看出,主题维护了一个观察者类型的链表,每当主题变化的时候,就会循环调用各个观察者的对应方法(这就是通知)。 
在观察者模式中,又分为 推模型 和 拉模型

  • 推模型:主题向观察者推送详细信息。
  • 拉模型:主题把自身作为一个参数发送给观察者,观察者需要什么信息,那么就 主题.getXX() 。

Java中的观察者模式


再来看看 Java中的观察者模式,最后再提一下 个人在 SpringBoot 中对于观察者模式的实际使用。

Java 提供了 Observer接口(观察者接口) 和 Observable 接口(被观察者接口 / 主题接口)。源码如下:

Observable 接口(被观察者接口 / 主题接口):

public class Observable {  private boolean changed = false; private Vector<Observer> obs; public Observable() { obs = new Vector<>(); } public synchronized void addObserver(Observer o) { if (o == null) throw new NullPointerException(); if (!obs.contains(o)) { obs.addElement(o); } } public synchronized void deleteObserver(Observer o) { obs.removeElement(o); } public void notifyObservers() { notifyObservers(null); } public void notifyObservers(Object arg) { Object[] arrLocal; synchronized (this) { if (!changed) return; arrLocal = obs.toArray(); · clearChanged(); } for (int i = arrLocal.length-1; i>=0; i--) ((Observer)arrLocal[i]).update(this, arg); } public synchronized void deleteObservers() { obs.removeAllElements(); } protected synchronized void setChanged() { changed = true; } protected synchronized void clearChanged() { changed = false; } public synchronized boolean hasChanged() { return changed; } public synchronized int countObservers() { return obs.size(); } } 

如上代码:通过 Vector 维护一个 观察者类型的数组。通过调用 notifyObeservers(Object arg) 方法 来通过观察者。在实现中,也是通过for 循环 通知。 
Ps:注意:从代码上看,需要先设changed。

Observer接口(观察者接口):

public interface Observer {  void update(Observable o, Object arg);
} 

这两个参数的含义为:

* @param   o     the observable object.
* @param   arg   an argument passed to the <code>notifyObservers</code> 

所以,此时即实现了 推模型,也实现了 拉模型。如果我们使用,那么分别实现这两个接口即可。

SpringBoot事件机制对于观察者模式的运用


那么在个人的实际运用中,做的是一个记账的服务,让别人来调用。当然,可以让别人直接在他们的业务处理后面,例如购买了XX东西,马上就直接调用我的记账服务,但是这样其实是一个紧耦合,由于是两个不同的业务,所以紧耦合感觉不太好。那么 观察者模式就有利于解耦

对于Spring Boot 的事件机制,同样离不开 这2个东西-主题,观察者。 但是 ,spring boot 把 之前所说的通知,包装成了一个 Event。下面分析这三者。

SpringBoot的主题

Spring boot 的主题 可以 由 ApplicationContext 来充当。ApplicaitonContext 继承于 ApplicationEventPublisher。ApplicaiotnEventPublisher 源码如下:

public interface ApplicationEventPublisher {  /** * Notify all listeners registered with this application of an application * event. Events may be framework events (such as RequestHandledEvent) * or application-specific events. * @param event the event to publish * @see org.springframework.web.context.support.RequestHandledEvent */ void publishEvent(ApplicationEvent event); } 

其实该接口就是我们 发布事件的接口。

SpringBoot 的观察者

Spring Boot 的观察者由 ApplicationListener 来进行充当。源码如下:

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { /** * Handle an application event. * @param event the event to respond to */ void onApplicationEvent(E event); } 

可以看到, onApplicaiton(E event) 方法即 上文所说的 update 方法。

SpringBoot的Event

自定义事件 继承ApplicationEvent抽象类

是Subject和Object传递消息的介质。因为这个类型的特殊性、唯一性,可以作为标识的依据。

就像Button按钮的点击事件、Move事件

上文所说的 主题 和 观察者 都有体现,传输的消息 Spring Boot 使用了一个 ApplicationEvent 进行了封装
源码如下:

public abstract class ApplicationEvent extends EventObject { /** use serialVersionUID from Spring 1.2 for interoperability */ private static final long serialVersionUID = 7099057708183571937L; /** System time when the event happened */ private final long timestamp; public ApplicationEvent(Object source) { super(source); this.timestamp = System.currentTimeMillis(); } public final long getTimestamp() { return this.timestamp; } } 

EventObject 源码:

public class EventObject implements java.io.Serializable { private static final long serialVersionUID = 5516075349620653480L; /** * The object on which the Event initially occurred. */ protected transient Object source; public EventObject(Object source) { if (source == null) throw new IllegalArgumentException("null source"); this.source = source; } public Object getSource() { return source; } public String toString() { return getClass().getName() + "[source=" + source + "]"; } } 

由上面的代码 可知,其实 ApplicationEvent 就是 把需要传输的消息 封装起来。这个消息并没有想 Java 的实现那样推拉模型都实现了,而是 只实现了 拉模型 

最后,我们程序中只需要 注入ApplicaitonContext (Subject)发送消息publishEvent;
实现 ApplicationListener 接口的Observer进行相应的处理即可。

注册事件监听器,我们只需要把它配置成一个Bean即可,ApplicationContext容器会自动将其注册

总结


观察者模式实质是 有两个 东西:

  • 一个是 主题
  • 一个是观察者

主题中维护了 观察者列表的引用。当主题有变更的时候,循环调用观察者,通知其做相应的处理。另外,不论是 Java,还是 Spring ,都是利用这个原理,只是有不同的类充当 主题 和 观察者。 
另外,观察者模式有一个好处:解耦

http://blog.csdn.net/allen215902/article/details/50747438

有事件,即有事件监听器. 有人问你spring监听器有哪些你看了下文即也知道了。
事件传播
ApplicationContext基于Observer模式(java.util包中有对应实现),提供了针对Bean的事件传播功能。
通过Application. publishEvent方法,我们可以将事件通知系统内所有的ApplicationListener。
事件传播的一个典型应用是,当Bean中的操作发生异常(如数据库连接失败),则通过事件传播机制通知异常监听器进行处理。在笔者的一个项目中,就曾经借助事件机制,较好的实现了当系统异常时在监视终端上报警,同时发送报警SMS至管理员手机的功能。

ApplicationContext容器提供了容器内部事件发布功能,是继承自JavaSE标准自定义事件类而实现的。

JavaSE标准自定义事件结构不在此详细描述,一张图很直观的描述清楚:

EventObject,为JavaSE提供的事件类型基类,任何自定义的事件都继承自该类,例如上图中右侧灰色的各个事件。Spring中提供了该接口的子类ApplicationEvent。

EventListener为JavaSE提供的事件监听者接口(Observer),任何自定义的事件监听者都实现了该接口,如上图左侧的各个事件监听者。
Spring中提供了该接口的子类ApplicationListener接口。

JavaSE中未提供事件发布者这一角色类,由各个应用程序自行实现事件发布者这一角色。Spring中提供了ApplicationEventPublisher接口作为事件发布者,并且ApplicationContext(Subject)实现了这个接口,担当起了事件发布者这一角色。
但ApplicationContext在具体实现上有所差异,Spring提供了ApplicationEventMulticaster接口,负责管理ApplicationListener和发布ApplicationEvent。ApplicationContext会把相应的事件相关工作委派给ApplicationEventMulticaster接口实现类来做。
类图如下所示:

事件发布时序图如下:

-------------------------------------------------------------------------------------------------

Spring中提供一些Aware相关的接口,BeanFactoryAware、 ApplicationContextAware、ResourceLoaderAware、ServletContextAware等等,其中最常用到的是ApplicationContextAware。
实现ApplicationContextAware的Bean,在Bean被初始后,将会被注入ApplicationContext的实例
ApplicationContextAware提供了publishEvent()方法,实现Observer(观察者)设计模式的事件传播机,提供了针对Bean的事件传播功能。
通过Application.publishEvent方法,我们可以将事件通知系统内所有的ApplicationListener。

Spring事件处理一般过程:

◆定义Event类(Subject和Observer传递消息的介质),继承org.springframework.context.ApplicationEvent。
◆编写发布事件类Publisher(Subject),实现org.springframework.context.ApplicationContextAware接口。
◆覆盖方法setApplicationContext(ApplicationContext applicationContext)和发布方法publish(Object obj)。
◆定义时间监听类EventListener(Observer),实现ApplicationListener接口,实现方法onApplicationEvent(ApplicationEvent event)。

1.发布

1.1事件的发布者需要实现的接口
org.springframework.context.ApplicationEventPublisherAware
1.2 代码示例  
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;/*** * @author zq**/
public class HelloWorld implements ApplicationEventPublisherAware{private String word;private ApplicationEventPublisher tradeEventPublisher;public void setWord(String w){this.word = w;}public void say(){System.out.println("say : "+ this.word);//construct a TradeEvent instance and publish itTradeEvent tradeEvent = new TradeEvent(new String("tradeEvent"));this.tradeEventPublisher.publishEvent(tradeEvent);}@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {// TODO Auto-generated method stubthis.tradeEventPublisher = applicationEventPublisher;}
}

2.接受事件

2.1需要实现的接口org.springframework.context.ApplicationListener
2.2代码示例
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStartedEvent;public class TradeContextListener implements ApplicationListener{@Overridepublic void onApplicationEvent(ApplicationEvent e) {System.out.println(e.getClass().toString());// TODO Auto-generated method stubif (e instanceof ContextStartedEvent){System.out.println("it was contextStartedEvent");}if (e instanceof TradeEvent){System.out.println(e.getSource());}}}

3配置文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans><bean name="helloWorld" class="study.HelloWorld"><property name="word" value="hello world"/></bean><bean id="tradeContextListener" class="study.TradeContextListener"/>
</beans>

4.测试代码

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import study.HelloWorld;
public class TestHelloWorld {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubApplicationContext applicationContext = new ClassPathXmlApplicationContext("study-context.xml");HelloWorld bean = (HelloWorld)applicationContext.getBean("helloWorld");bean.say();}}

Spring中ApplicationContext的事件机制--- 内定事件)
在Spring中已经定义了五个标准事件,分别介绍如下:

1)      ContextRefreshedEvent:当ApplicationContext初始化或者刷新时触发该事件。

2)      ContextClosedEvent:当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。

3)      RequestHandleEvent:在Web应用中,当一个http请求(request)结束触发该事件。

ContestStartedEvent:Spring2.5新增的事件,当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。

5) ContestStopedEvent:Spring2.5新增的事件,当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。

下面通过一个例子展示如何处理Spring内定的事件(例程3.8)。创建一个Java工程,添加Spring开发能力后,新建ioc.test包。在包中新建ApplicationEventListener类,实现ApplicationListener接口,在onApplicationEvent()方法中添加事件处理代码,如下:

1 package ioc.test;

3 //Import省略
4 publicclass ApplicationEventListenerimplements ApplicationListener {

6 publicvoid onApplicationEvent(ApplicationEvent event) {

8 //如果是容器刷新事件
9 if(eventinstanceof ContextClosedEvent ){
10             System.out.println(event.getClass().getSimpleName()+" 事件已发生!");   
11         }elseif(eventinstanceof ContextRefreshedEvent ){//如果是容器关闭事件
12             System.out.println(event.getClass().getSimpleName()+" 事件已发生!");   
13         }elseif(eventinstanceof ContextStartedEvent ){
14             System.out.println(event.getClass().getSimpleName()+" 事件已发生!");
15         }elseif(eventinstanceof ContextStoppedEvent){
16             System.out.println(event.getClass().getSimpleName()+" 事件已发生!");
17         }else{
18             System.out.println("有其它事件发生:"+event.getClass().getName());
19         }
20                    
21     }
22 
23 }
24 

在Spring配置文件中定义一个Bean,类为ApplicationEventListener,代码如下:

1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans…………   

4    <bean id="ApplicationEventListener" class="ioc.test.ApplicationEventListener"/>

6 </beans>
7

添加含有主方法的TesMain类,在主方法中,调用容器的相应方法,触发Spring内定事件,代码如下:

1 package ioc.test;

3 //import省略
4 publicclass TesMain {

6 publicstaticvoid main(String[] args) {
7         AbstractApplicationContext ac=newClassPathXmlApplicationContext("applicationContext.xml");
8         

10 //    ac.refresh();//触发ContextRefreshedEvent事件           
11         ac.start();//触发ContextStartedEvent事件
12         ac.stop(); //触发ContextStoppedEvent事件       
13         ac.close();//关闭容器,触发ContextClosedEvent事件
14 
15     }
16 }
17

运行主类,控制台输出如下:

从例子中可以知道,要注册事件监听器,我们只需要把它配置成一个Bean即可,ApplicationContext容器会自动将其注册。

转载于:https://www.cnblogs.com/yuluoxingkong/p/9953061.html

设计模式:java及spring观察者模式(有利于代码解耦)相关推荐

  1. 设计模式:观察者模式(有利于代码解耦)

    什么是ApplicationContext?  它是Spring的核心,Context我们通常解释为上下文环境,但是理解成容器会更好些.  ApplicationContext则是应用的容器. Spr ...

  2. 【Java设计模式 规范与重构】 六 代码重构小结

    最近趁着学习劲头足,如饥似渴的把代码重构部分也学习完了,可以说9月份属实非常充实,貌似也只有学习才能导致生活没有那么无聊. 代码重构博客目录 序号 文章列表 1 [Java设计模式 规范与重构] 一 ...

  3. Java和Spring的六边形架构:在代码中体现“六角形建筑”

    前言: 术语"六角形建筑"已经存在很长时间了.足够长的时间,这个主题的主要资源已经脱机了一段时间,并且直到最近才从档案中解救出来. 但是,我发现关于如何以这种体系结构样式实际实现应 ...

  4. java轻量级框架_轻量级的Java 开发框架 Spring

    Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development a ...

  5. 《大话设计模式(C#实现)》(Yanlz+VR云游戏+Unity+SteamVR+云技术+5G+AI+设计模式+GoF+UML+单例模式+观察者模式+抽象工厂+代理模式+框架编程+立钻哥哥++OK+)

    <大话设计模式(C#实现)> 版本 作者 参与者 完成日期 备注 YanlzFramework_GoF_V01_1.0 严立钻 2020.02.10 ##<大话设计模式(C#实现)& ...

  6. 视频教程-全新150集通俗易懂的Java设计模式-Java

    全新150集通俗易懂的Java设计模式 张长志技术全才.擅长领域:区块链.大数据.Java等.10余年软件研发及企业培训经验,曾为多家大型企业提供企业内训如中石化,中国联通,中国移动等知名企业.拥有丰 ...

  7. 设计模式(行为型)之观察者模式(Observer Pattern)

    PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbob ...

  8. 设计模式(二)————观察者模式

    引言 观察者模式可以说是JDK中使用最多的模式之一,这个模式可以让你的对象随时随地的了解想要知道的情况,你还可以让某个对象在运行时决定是否要继续通知:观察者模式的定义为: 定义对象间一种一对多的依赖关 ...

  9. spring观察者模式_Spring事件的观察者模式

    spring观察者模式 介绍 观察者模式的本质是"定义对象之间的一对多依赖关系,以便当一个对象改变状态时,其所有依赖关系都会被通知并自动更新". GoF. 观察者模式是发布/订阅模 ...

最新文章

  1. Ubuntu 14.04 64bit上安装Intel官方集显更新驱动程序
  2. windows核心编程学习笔记(六)动态链接库
  3. Activity应用场景解析
  4. 连续八个季度双位数增长,这家公司业务成功得不像技术派
  5. leetcode解题报告:198 House Robber
  6. 观百工堰竹筏竞技比赛有感
  7. 前端要给力之:代码可以有多烂?
  8. boost::geometry::util::calculation_type用法的测试程序
  9. 一个AI设计的思考过程(旧文)
  10. java输出变量_Java笔记1: 输入输出与变量常量
  11. Spring Cloud微服务之业务物理删除(十)
  12. 并发框架Disruptor
  13. Ztree加载完成后显示勾选节点
  14. 爬取微博的数据时别人用的是FM.view方法传递html标签那么jsoup怎么解析呢
  15. Docfetcher
  16. 移动APP测试用例设计的关注点
  17. Java信息管理系统模板思维导图
  18. 信号处理之CFAR恒虚警检测
  19. windows server2012R2 apache+mod_wsgi+django
  20. 喜茶门店总数超过650家,深圳单城市突破100家店

热门文章

  1. stm32中断优先级_浅谈STM32串口USART1的使用
  2. osg 镜面_浙江天梭手表镜面抛光
  3. android java代码打印系统日志_Java快速开发平台源码
  4. java 怎么获取object的数据_自学java,想将来从事大数据工作,现实吗?怎么学?...
  5. java 多线程 信号量_Java核心-多线程(7)-并发控制器-Semaphore信号量
  6. HTTP Get POST方式请求数据
  7. Helm 3 完整教程(六):在模板中使用 Helm 函数
  8. android 圆点指示器,ViewPager加上小圆点指示器效果
  9. logback为日志配置颜色
  10. 德鲁伊druid数据库明文密码加密