博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式 原型模式 | 对象池模式 | 观察者模式
阅读量:5977 次
发布时间:2019-06-20

本文共 8091 字,大约阅读时间需要 26 分钟。

hot3.png

原型模式

这篇文章的第一个设计模式是原型。可以通过官方文档查找有关Spring作用域中的bean作用域的文章中介绍了类似的概念(prototype)。原型设计模式与有用相同名称的(prototype)作用域有点相似。此设计模式允许通过复制已存在的对象来创建一个对象的实例。副本应该是真正的副本。这意味着新对象的所有属性应与复制对象的属性相同。如果不清楚,比一个简单的 JUnit案例更好的说明:

  1. public class PrototypeTest { @Test public void test() {   Robot firstRobot = new Robot("Droid#1");   Robot secondRobot = (Robot) firstRobot.clone();   assertTrue("Cloned robot's instance can't be the same as the"     +" source robot instance",     firstRobot != secondRobot);   assertTrue("Cloned robot's name should be '"+firstRobot.getName()+"'"     +" but was '"+secondRobot.getName()+"'",     secondRobot.getName().equals(firstRobot.getName())); }}class Robot implements Cloneable { private String name; public Robot(String name) {   this.name = name; } public String getName() {   return this.name; } protected Object clone() throws CloneNotSupportedException {   return super.clone(); }}

     

     

在 Spring中,在org.springframework.beans.factory.support.AbstractBeanFactory中使用一种特定的原型设计模式,它将初始化 bean原型作用域。新对象基于配置文件中的bean定义。我们可以看到,在给定的例子中:

  1.  

     

    @RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations={"applicationContext-test.xml"})public class SpringPrototypeTest { @Autowired private BeanFactory beanFactory; @Test public void test() {   ShoppingCart cart1 = (ShoppingCart) beanFactory.getBean("shoppingCart");   assertTrue("Id of cart1 should be 9 but was "+cart1.getId(),     cart1.getId() == 9);   cart1.setId(100);   ShoppingCart cart2 = (ShoppingCart) beanFactory.getBean("shoppingCart");   assertTrue("Id of cart2 should be 9 but was "+cart2.getId(),     cart2.getId() == 9);   assertTrue("Id of second cart ("+cart2.getId()+") shouldn't be the same as the first one: "+cart1.getId(),     cart1.getId() != cart2.getId());   cart2.setId(cart1.getId());   assertTrue("Now (after cart2.setId(cart1.getId())), the id of second cart ("+cart2.getId()+") should be the same as the first one: "     +cart1.getId(), cart1.getId() == cart2.getId());   assertTrue("Both instance shouldn't be the same", cart1 != cart2); }}

     

 

从前面的例子可以看出, ShoppingCart实例是直接从bean定义创建的。最初,cart1和 cart2对象的 id值为 9.它在测试结束时被修改,以证明两个引用都属于两个不同的对象。

对象池

Spring中使用的另一个模型是对象池设计模式。其主要目的在于在一个池中保存特定数量的对象,并根据需要重新使用。通过它,我们可以改善我们想要使用 巨型对象的响应时间。 巨型意味着这些对象的构造需要很多时间(例如:持有数据库连接的对象),最好重用已经存在的和未获取的对象,而不是创建新对象。

Spring还使用线程池来管理其调度部分。一些示例位于org.springframework.scheduling.concurrent中。我们检索数据库( SpringJDBC)项目中的对象池的想法。数据库连接池不是由 Spring直接实现的,而是适用于 Spring工作方式的项目,如 C3P0或 JakartaCommonsDBCP连接池。

观察者

这里呈现的最后一个设计模式是观察者。当一个或几个课程正在等待具体事件时可以使用它。观察者模式由一个科目和观察员名单组成。一个很好的例子就是 GUI界面,其中点击按钮(按钮是主题)会引起听众(观察者)启动的一些操作(再说的直白点就是电影院一场电影这个 subject,需要 观众(也就是观察者咯),电影产生的一些画面产生的事件,比如恐怖 电影给男人女人带来的不同的感官的感受,传播到观察者也就是观众的眼里所带来的不一样的反应,这个中间一般会添加一个 事件传播者,在后面解释 Spring的例子的时候会说到),例如:打开一个新页面这个动作。可以参考下面的例子:

  1. public class ObserverTest { @Test public void test() {   Observer pageOpener = new PageOpener();   Observer register = new Register();   Button btn = new Button();   btn.addListener(pageOpener);   btn.addListener(register);   btn.clickOn();   assertTrue("Button should be clicked but it wasn't",     btn.wasClicked());   assertTrue("Page opener should be informed about click but it wasn't",     pageOpener.wasInformed());   assertTrue("Register should be informed about click but it wasn't",     register.wasInformed()); }}class Button { private boolean clicked; private List
    listeners; public List
    getListeners() {   if (this.listeners == null) {     this.listeners = new ArrayList
    ();   }   return this.listeners; } public void addListener(Observer observer) {   getListeners().add(observer); } public boolean wasClicked() {   return this.clicked; } public void clickOn() {   this.clicked = true;   informAll(); } private void informAll() {   for (Observer observer : getListeners()) {     observer.informAboutEvent();   } }}abstract class Observer { protected boolean informed; public void informAboutEvent() {   this.informed = true; } public boolean wasInformed() {   return this.informed; }}class PageOpener extends Observer { @Override public void informAboutEvent() {   System.out.println("Preparing download of new page");   super.informAboutEvent(); }}class Register extends Observer { @Override public void informAboutEvent() {   System.out.println("Adding the action to register");   super.informAboutEvent(); }}

     

     

可以看到,关于我们的 Button实例点击的事件被发送到所有的观察者对象。从这些对象开始下载页面内容,第二个将在事件的信息保存在注册表中。在 Spring中,观察者设计模式用于将与应用程序上下文相关的事件传输到org.springframework.context.ApplicationListener的实现。要了解它们的实现方法,我们来看一下 AbstractApplicationContext类(老版本的代码,新版本的请自行对照):

  1. public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean { /** Statically specified listeners */ private Set
    > applicationListeners = new LinkedHashSet
    >(); // some other fields and methods @Override public void addApplicationListener(ApplicationListener
    listener) {   if (this.applicationEventMulticaster != null) {     this.applicationEventMulticaster.addApplicationListener(listener);   }   else {//新版本这里直接咔嚓掉,上面的applicationEventMulticaster一旦为空,就会报错的     this.applicationListeners.add(listener);   } } /**   * Return the list of statically specified ApplicationListeners.   */ public Collection
    > getApplicationListeners() {   return this.applicationListeners; } /**   * Add beans that implement ApplicationListener as listeners.   * Doesn't affect other listeners, which can be added without being beans.   */ protected void registerListeners() {   // Register statically specified listeners first.   for (ApplicationListener
    listener : getApplicationListeners()) {     getApplicationEventMulticaster().addApplicationListener(listener);   }   // Do not initialize FactoryBeans here: We need to leave all regular beans   // uninitialized to let post-processors apply to them!   String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);   for (String lisName : listenerBeanNames) {     getApplicationEventMulticaster().addApplicationListenerBean(lisName);   } }}

    在提供的代码中,监听器在内部添加到应用程序上下文类中,并且在 registerListeners()方法之后,它们被注册到由接口org.springframework.context.event.ApplicationEventMulticaster表示的适当的事件多路广播器(因为有很多listeners)。 EventMulticaster负责管理不同的 listener和向他们发布事件。

  2. public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {   private Executor taskExecutor;   private ErrorHandler errorHandler;   public SimpleApplicationEventMulticaster() {   }   public SimpleApplicationEventMulticaster(BeanFactory beanFactory) {       this.setBeanFactory(beanFactory);   }   public void setTaskExecutor(Executor taskExecutor) {       this.taskExecutor = taskExecutor;   }   protected Executor getTaskExecutor() {       return this.taskExecutor;   }   public void setErrorHandler(ErrorHandler errorHandler) {       this.errorHandler = errorHandler;   }   protected ErrorHandler getErrorHandler() {       return this.errorHandler;   }   public void multicastEvent(ApplicationEvent event) {       this.multicastEvent(event, this.resolveDefaultEventType(event));   }   //发布事件:通过池执行任务的方式来做并发处理,这样就把之前的对象池模式给利用上了   public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {       ResolvableType type = eventType != null?eventType:this.resolveDefaultEventType(event);       Iterator var4 = this.getApplicationListeners(event, type).iterator();       while(var4.hasNext()) {           final ApplicationListener
    listener = (ApplicationListener)var4.next();           Executor executor = this.getTaskExecutor();           if(executor != null) {               executor.execute(new Runnable() {                   public void run() {                       SimpleApplicationEventMulticaster.this.invokeListener(listener, event);                   }               });           } else {               this.invokeListener(listener, event);           }       }   }...}

    这次我们讲3种设计模式:用于在同一个调用作用域内创建 bean的原型,避免重新创建巨型对象的对象池,以及将应用程序的上下文事件分派给适当的监听器的观察者。

转载于:https://my.oschina.net/garlicts/blog/2236634

你可能感兴趣的文章
终结符、非终结符
查看>>
Node.js刷新session过期时间
查看>>
详解Javascript中的Array对象
查看>>
【Zookeeper】源码分析之服务器(二)之ZooKeeperServer
查看>>
【转】 [置顶] Android 通知栏Notification的整合 全面学习 (一个DEMO让你完全了解它)...
查看>>
缓存技术PK:选择Memcached还是Redis?
查看>>
MXPlayer ac3音轨支持问题
查看>>
iOS:即时通讯之<了解篇 SocKet>
查看>>
SQL Tuning 基础概述10 - 体会索引的常见执行计划
查看>>
kibana.yml(中文配置详解)
查看>>
Office文档如何转换 PDF 转 DOC XLS
查看>>
图解JAVA参数传递
查看>>
算法-插值查找
查看>>
mongodb 关闭服务 mongod -f /root/mongodb/bin/xx.conf --shutdown
查看>>
从零开始学习OpenCL开发(一)架构【转】
查看>>
Android实现点击通知栏后,先启动应用再打开目标Activity
查看>>
Java 之 POI各Jar包作用
查看>>
【AngularJS】解决ng-if中的ng-model值无效的问题(转)
查看>>
span中内容随着数字长度的添加而增大
查看>>
git配置文件读取顺序
查看>>