zoukankan      html  css  js  c++  java
  • 设计模式实战应用之一:策略模式

            策略模式的定义
            策略模式是应用最普遍的设计模式之一。Gof 把策略模式归类到对象行为型模式,《 设计模式:可复用面向对象软件的基础》对策略模式做出了明确的定义:“ Define a family of algorithms, encapsulate each one, and make theminterchangeable.Strategy lets the algorithm vary independently fromclients that use it.”,翻译过来就是:“ 定义了一族算法,将每个算法分别封装起来,并且互相之间可以替换。策略模式可以使算法的变化独立于使用算法的客户”。
            why 策略模式?

    • 客户端程序直接包含业务算法代码的话会变的复杂,这样会使客户程序庞大且难以维护,尤其是需要支持多种业务算法时。
    • 不同的时候需要不同的算法,我们不想支持我们并不使用的业务算法。
    • 当业务功能是客户程序的一个难以分割的成分时,增加新的业务算法或改变现有算法将十分困难。

            策略模式定义一些类来封装不同的业务算法,从而避免上述问题。
            策略模式的使用场合

    • 许多相关类仅仅是行为不同。
    • 需要使用一个算法的不同实现。
    • 算法使用了客户不应该知道的数据。策略模式可以避免暴露复杂的、与算法相关的数据结构。
    • 一个类定义了很多行为,而且这些行为在这个类里的操作以多个条件语句的形式出现。策略模式将相关的条件分支移入它们各自的 Strategy 类中以代替这些条件语句。

             sql 性能测试需求
            在一个 jee 项目中,有一张表,单表千万数据,有五条 sql 语句可能需要优化,现在处于上线前紧张的 coding 阶段,为了避免产品上线后因数据量暴涨而造成 sql 性能下降,现在需要一个程序来模拟真实场景下的 jee 数据库操作,通过这些操作用时分析 sql 性能和潜在问题,进而优化。
            sql 性能测试分析
            为了模拟真实场景,数据库、框架产品项目保持一致自不必说。数据库单表也需要制造模拟数据到上千万条,记录之间尽量遵循真实场景。
            数据制造好以后,需要模拟不同用户进行操作。比如有用户模拟插入操作,有用户模拟查询操作。模拟操作的数量、执行频率最好也根据真实场景得出。
            sql 性能测试类设计
            jee 用了 spring mvc + spring IOC + iBatis 框架,为了便于理解我们模拟程序也分出 dao、service。为了不和 service 产生混淆,我们具体的“策略”算法封装在了 user 类里头(user 相当于 Gof《设计模式:可复用面向对象软件的基础》中的 Strategy 接口),runner 作为使用算法的客户(即 Gof《设计模式:可复用面向对象软件的基础》中的 Context 对象)。具体类图如下:

            sql 性能测试时序图
    时序图
            sql 性能测试源码实现

            Strategy 角色 User 源代码:

    package com.defonds.mysql.user;
    
    public interface User {
    	// 策略模式的应用:把具体做法让每个 User 分别封装起来,做法独立于调用 User 的 thread
    	public void doMyThing();
    }

            ConcreteStrategy 角色之一 RawAddUser 源代码:

    package com.defonds.mysql.user.raw;
    
    import com.defonds.mysql.raw.service.RawService;
    import com.defonds.mysql.user.User;
    
    public class RawAddUser implements User {
    	private RawService rawService;
    	private int numCountor = 1; // 记录次数
    	public void setRawService(RawService rawService) {
    		this.rawService = rawService;
    	}
    
    	@Override
    	public void doMyThing() {
    		long uid = 111;
    		long did = 1111;
    		long fileId = 11111;
    		long sectionId = 111111;
    		long startTime = System.currentTimeMillis();
    		String s3RawHeaderPath = "/usr/home/df/wefd.txt" + numCountor;
    		String channelId = "1";
    		if (numCountor >= 20) {
    			numCountor = 1;
    		}
    		uid += numCountor;
    		did += numCountor;
    		fileId += numCountor;
    		sectionId += numCountor;
    		rawService.addTimeLineRaw(uid, did, fileId, sectionId, startTime, startTime + 15000, s3RawHeaderPath, channelId);
    		numCountor ++;
    	}
    
    }

            Context 角色 Runner 源代码:

    package com.defonds.mysql.runner;
    
    import java.util.Date;
    
    import com.defonds.mysql.user.User;
    import com.defonds.mysql.util.dao.RecordDao;
    
    public abstract class Runner implements Runnable {
    	protected RecordDao recordDao;
    	protected User user;
    	protected String sceneDesc;
    	protected String type;
    	protected String requestDesc;
    	protected long interval;
    	public void setRecordDao(RecordDao recordDao) {
    		this.recordDao = recordDao;
    	}
    	public void setUser(User user) {
    		this.user = user;
    	}
    	
    	/**
    	 * 
    	 * @param sceneDesc // 场景名
    	 * @param type // 操作类型 [insert、delete、update、select]
    	 * @param requestDesc // 对应  timeline.xml 文件中的语句 id
    	 * @param interval // 两次执行之间的时间间隔
    	 */
    	public Runner(String sceneDesc, String type, String requestDesc, long interval) {
    		this.sceneDesc = sceneDesc;
    		this.type = type;
    		this.requestDesc = requestDesc;
    		this.interval = interval;
    	}
    
    	@Override
    	public void run() {
    		while (true) {
    			try {
    				Thread.sleep(this.interval);
    			} catch (InterruptedException e) {
    				// TODO Auto-generated catch block
    				e.printStackTrace();
    			}
    			Date startTime = new Date();
    			long startTimeL = System.currentTimeMillis();
    			this.user.doMyThing();
    			Date endTime = new Date();
    			long endTimeL = System.currentTimeMillis();
    			this.record(this.sceneDesc, this.type, startTime, endTime, endTimeL - startTimeL, this.requestDesc, null);
    		}
    	}
    	
    	protected void record(String sceneDesc, String type, Date startTime, Date endTime, long extendTime, String requestDesc, String requestDetail) {
    		this.recordDao.addRecord(sceneDesc, type, startTime, endTime, extendTime, requestDesc, requestDetail);
    	}
    
    }

            sql 性能测试结果分析
            使用压力程序将 DB Server 负载到真实上线后的比例。然后模拟程序 19 * 5 个用户并发,TestMysql 跑起来,E7500 CPU 负载到 0.2%,4 G 内存负载 0%。可以参考《 关于一个具有配置文件的 Java Project 项目(非 web 项目)在服务器上的一个便捷部署》的做法将本模拟程序部署在测试服务器。根据本模拟程序运行两天,五个 sql 性能走势如下图:
    TestMysql运行效果图
            本文示例程序《sql 性能测试》源码下载
            已将本文用到的项目相关源代码上传至 CSDN 资源,有兴趣的朋友可以去看一下: sql 性能测试源代码

  • 相关阅读:
    北京燃气IC卡充值笔记
    随机分析、随机控制等科目在量化投资、计算金融方向有哪些应用?
    量化交易平台大全
    Doctor of Philosophy in Computational and Mathematical Engineering
    Institute for Computational and Mathematical Engineering
    Requirements for the Master of Science in Computational and Mathematical Engineering
    MSc in Mathematical and Computational Finance
    万字长文:详解多智能体强化学习的基础和应用
    数据处理思想和程序架构: 使用Mbedtls包中的SSL,和服务器进行网络加密通信
    31-STM32+W5500+AIR202/302基本控制篇-功能优化-W5500移植mbedtls库以SSL方式连接MQTT服务器(单向忽略认证)
  • 原文地址:https://www.cnblogs.com/fuhaots2009/p/3433136.html
Copyright © 2011-2022 走看看