Spring之设计模式2

个人专题目录


9、原型模式

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

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定义。我们可以看到,在给定的例子中:

`<bean id="shoppingCart" class="com.waitingforcode.data.ShoppingCart" scope="prototype">  <property name="id" value="9"></property></bean>`
@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定义创建的。最初,cart1cart2对象的id值为9.它在测试结束时被修改,以证明两个引用都属于两个不同的对象。

10、对象池

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

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

11、观察者

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

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<observer> listeners;
   
  public List<observer> getListeners() {
    if (this.listeners == null) {
      this.listeners = new ArrayList<observer>();
    }
    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类(老版本的代码,新版本的请自行对照):

public abstract class AbstractApplicationContext extends DefaultResourceLoader
        implements ConfigurableApplicationContext, DisposableBean {
    /**
     * Statically specified listeners
     */
    private Set<applicationlistener<?>> applicationListeners = new LinkedHashSet<applicationlistener<?>>();

    // 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<applicationlistener<?>> 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和向他们发布事件。

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);
            }
        }

    }
...
}

12、适配器

当我们需要在给定场景下(也就是给定接口)想要不改变自身行为而又想做到一些事情的情况下(就是我给电也就是接口了,你来做事也就是各种电器),使用适配器设计模式(这里再说一点,就相当于我们再一个规章制度的环境下,如何去适应并达到我们期待的效果,放在架构设计这里,可以拿一个php系统和一个Java系统来说,假如两者要互相调用对方的功能,我们可以设计一套对外的api来适配)。这意味着在调用此对象之前,我们将更改使用对象而不改变机制。拿一个现实中的例子进行说明,想象一下你想要用电钻来钻一个洞。要钻一个小洞,你会使用小钻头,钻一个大的需要用大钻头。可以看下面的代码:

public class AdapterTest {
    public static void main(String[] args) {
        HoleMaker maker = new HoleMakerImpl();
        maker.makeHole(1);
        maker.makeHole(2);
        maker.makeHole(30);
        maker.makeHole(40);
    }
}

interface HoleMaker {
    void makeHole(int diameter);
}

interface DrillBit {
    void makeSmallHole();

    void makeBigHole();
}

// Two adaptee objects
class BigDrillBit implements DrillBit {
    @Override
    public void makeSmallHole() {
        // do nothing
    }

    @Override
    public void makeBigHole() {
        System.out.println("Big hole is made byt WallBigHoleMaker");
    }
}

class SmallDrillBit implements DrillBit {
    @Override
    public void makeSmallHole() {
        System.out.println("Small hole is made byt WallSmallHoleMaker");
    }

    @Override
    public void makeBigHole() {
        // do nothing
    }
}

// Adapter class
class Drill implements HoleMaker {
    private DrillBit drillBit;

    public Drill(int diameter) {
        drillBit = getMakerByDiameter(diameter);
    }

    @Override
    public void makeHole(int diameter) {
        if (isSmallDiameter(diameter)) {
            drillBit.makeSmallHole();
        } else {
            drillBit.makeBigHole();
        }
    }

    private DrillBit getMakerByDiameter(int diameter) {
        if (isSmallDiameter(diameter)) {
            return new SmallDrillBit();
        }
        return new BigDrillBit();
    }

    private boolean isSmallDiameter(int diameter) {
        return diameter < 10;
    }
}

// Client class
class HoleMakerImpl implements HoleMaker {
    @Override
    public void makeHole(int diameter) {
        HoleMaker maker = new Drill(diameter);
        maker.makeHole(diameter);
    }
}
还有 70% 的精彩内容
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,647评论 18 139
  • 1.1 Spring IoC容器和bean简介 本章介绍了Spring Framework实现的控制反转(IoC)...
    起名真是难阅读 2,580评论 0 8
  • 1.1 spring IoC容器和beans的简介 Spring 框架的最核心基础的功能是IoC(控制反转)容器,...
    simoscode阅读 6,709评论 2 22
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,801评论 6 342
  • 5月大事记 5月1日 见南昌趁早读书会会长亭亭羊,见周馨 5月2日 南昌趁早多多视频 5月5日 出发山东,参...
    姑娘好好过阅读 286评论 3 4