新闻资讯

新闻资讯 行业动态

Spring框架中的设计模式(三)——原型模式 对象池 观察者

编辑:008     时间:2020-02-27

原型模式

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

  1. publicclassPrototypeTest{


  2.  @Test

  3.  publicvoidtest(){

  4.    RobotfirstRobot=newRobot("Droid#1");

  5.    RobotsecondRobot=(Robot)firstRobot.clone();

  6.    assertTrue("Cloned robot's instance can't be the same as the"

  7.      +" source robot instance",

  8.      firstRobot!=secondRobot);

  9.    assertTrue("Cloned robot's name should be '"+firstRobot.getName()+"'"

  10.      +" but was '"+secondRobot.getName()+"'",

  11.      secondRobot.getName().equals(firstRobot.getName()));

  12.  }


  13. }



  14. classRobotimplementsCloneable{

  15.  privateStringname;


  16.  publicRobot(Stringname){

  17.    this.name=name;

  18.  }


  19.  publicStringgetName(){

  20.    returnthis.name;

  21.  }


  22.  protectedObjectclone()throwsCloneNotSupportedException{

  23.    returnsuper.clone();

  24.  }

  25. }

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

  1. <beanid="shoppingCart"class="com.waitingforcode.data.ShoppingCart"scope="prototype">

  2.  <propertyname="id"value="9"></property>

  3. </bean>

  1. @RunWith(SpringJUnit4ClassRunner.class)

  2. @ContextConfiguration(locations={"applicationContext-test.xml"})

  3. publicclassSpringPrototypeTest{


  4.  @Autowired

  5.  privateBeanFactorybeanFactory;


  6.  @Test

  7.  publicvoidtest(){

  8.    ShoppingCartcart1=(ShoppingCart)beanFactory.getBean("shoppingCart");

  9.    assertTrue("Id of cart1 should be 9 but was "+cart1.getId(),

  10.      cart1.getId()==9);

  11.    cart1.setId(100);

  12.    ShoppingCartcart2=(ShoppingCart)beanFactory.getBean("shoppingCart");

  13.    assertTrue("Id of cart2 should be 9 but was "+cart2.getId(),

  14.      cart2.getId()==9);

  15.    assertTrue("Id of second cart ("+cart2.getId()+") shouldn't be the same as the first one: "+cart1.getId(),

  16.      cart1.getId()!=cart2.getId());

  17.    cart2.setId(cart1.getId());

  18.    assertTrue("Now (after cart2.setId(cart1.getId())), the id of second cart ("+cart2.getId()+") should be the same as the first one: "

  19.      +cart1.getId(),cart1.getId()==cart2.getId());

  20.    assertTrue("Both instance shouldn't be the same",cart1!=cart2);

  21.  }


  22. }

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

对象池

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

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

观察者

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

  1. publicclassObserverTest{


  2.  @Test

  3.  publicvoidtest(){

  4.    ObserverpageOpener=newPageOpener();

  5.    Observerregister=newRegister();

  6.    Buttonbtn=newButton();

  7.    btn.addListener(pageOpener);

  8.    btn.addListener(register);

  9.    btn.clickOn();

  10.    assertTrue("Button should be clicked but it wasn't",

  11.      btn.wasClicked());

  12.    assertTrue("Page opener should be informed about click but it wasn't",

  13.      pageOpener.wasInformed());

  14.    assertTrue("Register should be informed about click but it wasn't",

  15.      register.wasInformed());

  16.  }


  17. }


  18. classButton{


  19.  privatebooleanclicked;

  20.  privateList<observer>listeners;


  21.  publicList<observer>getListeners(){

  22.    if(this.listeners==null){

  23.      this.listeners=newArrayList<observer>();

  24.    }

  25.    returnthis.listeners;

  26.  }


  27.  publicvoidaddListener(Observerobserver){

  28.    getListeners().add(observer);

  29.  }


  30.  publicbooleanwasClicked(){

  31.    returnthis.clicked;

  32.  }


  33.  publicvoidclickOn(){

  34.    this.clicked=true;

  35.    informAll();

  36.  }


  37.  privatevoidinformAll(){

  38.    for(Observerobserver:getListeners()){

  39.      observer.informAboutEvent();

  40.    }

  41.  }


  42. }


  43. abstractclassObserver{

  44.  protectedbooleaninformed;


  45.  publicvoidinformAboutEvent(){

  46.    this.informed=true;

  47.  }


  48.  publicbooleanwasInformed(){

  49.    returnthis.informed;

  50.  }

  51. }


  52. classPageOpenerextendsObserver{


  53.  @Override

  54.  publicvoidinformAboutEvent(){

  55.    System.out.println("Preparing download of new page");

  56.    super.informAboutEvent();

  57.  }


  58. }


  59. classRegisterextendsObserver{


  60.  @Override

  61.  publicvoidinformAboutEvent(){

  62.    System.out.println("Adding the action to register");

  63.    super.informAboutEvent();

  64.  }

  65. }

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

  1. publicabstractclassAbstractApplicationContextextendsDefaultResourceLoader

  2.  implementsConfigurableApplicationContext,DisposableBean{

  3.  /** Statically specified listeners */

  4.  privateSet<applicationlistener<?>>applicationListeners=newLinkedHashSet<applicationlistener<?>>();


  5.  // some other fields and methods

  6.  @Override

  7.  publicvoidaddApplicationListener(ApplicationListener<?>listener){

  8.    if(this.applicationEventMulticaster!=null){

  9.      this.applicationEventMulticaster.addApplicationListener(listener);

  10.    }

  11.    else{//新版本这里直接咔嚓掉,上面的applicationEventMulticaster一旦为空,就会报错的

  12.      this.applicationListeners.add(listener);

  13.    }

  14.  }


  15.  /**

  16.    * Return the list of statically specified ApplicationListeners.

  17.    */

  18.  publicCollection<applicationlistener<?>>getApplicationListeners(){

  19.    returnthis.applicationListeners;

  20.  }


  21.  /**

  22.    * Add beans that implement ApplicationListener as listeners.

  23.    * Doesn't affect other listeners, which can be added without being beans.

  24.    */

  25.  protectedvoidregisterListeners(){

  26.    // Register statically specified listeners first.

  27.    for(ApplicationListener<?>listener:getApplicationListeners()){

  28.      getApplicationEventMulticaster().addApplicationListener(listener);

  29.    }

  30.    // Do not initialize FactoryBeans here: We need to leave all regular beans

  31.    // uninitialized to let post-processors apply to them!

  32.    String[]listenerBeanNames=getBeanNamesForType(ApplicationListener.class,true,false);

  33.    for(StringlisName:listenerBeanNames){

  34.      getApplicationEventMulticaster().addApplicationListenerBean(lisName);

  35.    }

  36.  }

  37. }

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

  1. publicclassSimpleApplicationEventMulticasterextendsAbstractApplicationEventMulticaster{

  2.    privateExecutortaskExecutor;

  3.    privateErrorHandlererrorHandler;


  4.    publicSimpleApplicationEventMulticaster(){

  5.    }


  6.    publicSimpleApplicationEventMulticaster(BeanFactorybeanFactory){

  7.        this.setBeanFactory(beanFactory);

  8.    }


  9.    publicvoidsetTaskExecutor(ExecutortaskExecutor){

  10.        this.taskExecutor=taskExecutor;

  11.    }


  12.    protectedExecutorgetTaskExecutor(){

  13.        returnthis.taskExecutor;

  14.    }


  15.    publicvoidsetErrorHandler(ErrorHandlererrorHandler){

  16.        this.errorHandler=errorHandler;

  17.    }


  18.    protectedErrorHandlergetErrorHandler(){

  19.        returnthis.errorHandler;

  20.    }


  21.    publicvoidmulticastEvent(ApplicationEventevent){

  22.        this.multicastEvent(event,this.resolveDefaultEventType(event));

  23.    }

  24.    //发布事件:通过池执行任务的方式来做并发处理,这样就把之前的对象池模式给利用上了

  25.    publicvoidmulticastEvent(finalApplicationEventevent,ResolvableTypeeventType){

  26.        ResolvableTypetype=eventType!=null?eventType:this.resolveDefaultEventType(event);

  27.        Iteratorvar4=this.getApplicationListeners(event,type).iterator();


  28.        while(var4.hasNext()){

  29.            finalApplicationListener<?>listener=(ApplicationListener)var4.next();

  30.            Executorexecutor=this.getTaskExecutor();

  31.            if(executor!=null){

  32.                executor.execute(newRunnable(){

  33.                    publicvoidrun(){

  34.                        SimpleApplicationEventMulticaster.this.invokeListener(listener,event);

  35.                    }

  36.                });

  37.            }else{

  38.                this.invokeListener(listener,event);

  39.            }

  40.        }


  41.    }

  42. ...

  43. }

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



原文链接:https://mp.weixin.qq.com/s/wsTqmXSSM0ixMlk_2af0FA

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

回复列表

相关推荐