JAVA設計模式之模板方法模式-場景、例子、深入

前言

模板方法的設計模式的使用場景

設計一個系統時知道了算法所需的關鍵步驟,而且確定了這些步驟的執行順序,但某些步驟的具體實現還未知,或者說某些步驟的實現與具體的環境相關。算法的整體步驟很固定,但其中個別部分易變時,這時候可以使用模板方法模式,將容易變的部分抽象出來,供子類實現。

具體場景例子

比如現在我們可以確定獲取指標A,指標B,指標C,指標D,都需要經過,連接初始化,連接,執行,轉換,關閉,五個步驟,並且對每個指標來說除極個別情況來說,初始化,連接,關閉三個步驟內部細節都是一樣的。

具體例子的類圖

在這裏插入圖片描述

1.聲明抽象模板類AbstaractSearchTemplate

package cn.unicom.panabitpendant.TemplateMethod;

import cn.unicom.panabitpendant.pojo.DelayPo;
import com.google.common.collect.Lists;
import io.github.whyareyousoseriously.czcommonutils.util.IpUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;

import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author chenzhen
 * Created by chenzhen on 2020/6/23.
 */
abstract class AbstractSearchTemplate<T> {

    public static Logger log = LoggerFactory.getLogger(AbstractSearchTemplate.class);

    public String user;
    public String password;
    public String ip;
    public String port;
    public String dbDriver;
    public String table;

    Connection conn = null;
    Statement stmt = null;
    ResultSet rs = null;


    /**
     * 數據初始化
     */
    public void init(String user, String password, String ip, String port, String dbDriver) {
        this.user = user;
        this.password = password;
        this.ip = ip;
        this.port = port;
        this.dbDriver = dbDriver;
    }

    /**
     * 連接
     */
    public void connection() {
        long now = System.currentTimeMillis();
        SimpleDateFormat dbNameFormat = new SimpleDateFormat("yyyyMMddHH");
        String dbName = "npmflow" + dbNameFormat.format(new Date(now));
        SimpleDateFormat tableNameFormat = new SimpleDateFormat("yyyyMMddHHmm");
        //List<String> tables = this.generateHoursTable(new Date(now - 60 * 2 * 1000));
        table = tableNameFormat.format(new Date(now - 60 * 3 * 1000));
        // JDBC 驅動名 及數據庫 URL
        final String JDBC_DRIVER = dbDriver;
        final String DB_URL = "jdbc:mysql://" + ip + ":" + port + "/" + dbName;

        // 數據庫的用戶名與密碼,需要根據自己的設置
        final String USER = user;
        final String PASS = password;

        try {
            // 註冊 JDBC 驅動
            // 把Driver類裝載進jvm
            Class.forName(JDBC_DRIVER);

            // 打開鏈接
            log.info("連接數據庫..." + DB_URL);
            conn = DriverManager.getConnection(DB_URL, USER, PASS);
            // 執行查詢
            stmt = conn.createStatement();

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }

    }

    /**
     * 執行,轉換
     */
    public abstract T transform() throws SQLException;

    /**
     * 關閉
     */
    public void close(){
        try {
            rs.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            // 關閉資源
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        log.info("連接結束");
    }

    public T exec(){
        T transform = null;
        try {
            this.connection();
            transform = this.transform();
            this.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return transform;

    }
}

2. 具體子類

2.1 具體子類DnsTopDelaySearch

package cn.unicom.panabitpendant.TemplateMethod;

import cn.unicom.panabitpendant.config.IpPartition;
import cn.unicom.panabitpendant.pojo.DnsDelayPo;
import cn.unicom.panabitpendant.pojo.TopDelayPo;
import com.google.common.collect.Lists;
import io.github.whyareyousoseriously.czcommonutils.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author chenzhen
 * Created by chenzhen on 2020/6/23.
 */
@Component
public class DnsTopDelaySearch extends AbstractSearchTemplate<List<DnsDelayPo>> {


    @Override
    public List<DnsDelayPo> transform() throws SQLException {
        List<DnsDelayPo> topDelayPos = Lists.newArrayList();
        String sql = "SELECT\n" +
                "t.s1 AS sIp, " +
                "t.sport AS sPort, " +
                "t.d1 AS dIp, " +
                "t.dport AS dPort, " +
                "t.host AS domainName, " +
                "t.appdelay AS appDelay " +
                "FROM " + "`" + super.table + "`" + " AS t " +
                "WHERE " +
                "t.appid = 6 " + " AND " +
                "t.pro = 17 " +
                "ORDER BY " +
                "t.appdelay DESC LIMIT 50" +
                ";";
        super.rs = stmt.executeQuery(sql);
        while (rs.next()) {
            // 通過字段檢索
            double appDelay = super.rs.getDouble("appDelay");
            String sIp = IpUtil.longToIP(super.rs.getLong("sIp"));
            String sPort = "" + super.rs.getInt("sPort");
            String dIp = IpUtil.longToIP(super.rs.getLong("dIp"));
            String dPort = "" + super.rs.getInt("dPort");
            String domainName = super.rs.getString("domainName");
            topDelayPos.add(new DnsDelayPo(sIp, sPort, dIp, dPort, domainName,0.0, 0.0, appDelay));
        }
        return topDelayPos;
    }
}

2.2 具體子類SipTopDelaySearch

package cn.unicom.panabitpendant.TemplateMethod;

import cn.unicom.panabitpendant.config.IpPartition;
import cn.unicom.panabitpendant.pojo.DelayPo;
import com.google.common.collect.Lists;
import io.github.whyareyousoseriously.czcommonutils.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * @author chenzhen
 * Created by chenzhen on 2020/6/24.
 */
@Component
public class SipDelaySearch extends AbstractSearchTemplate<List<DelayPo>> {
    @Autowired
    private IpPartition ipPartition;

    @Override
    public List<DelayPo> transform() throws SQLException {
        List<Map<String, String>> sipPartitionMap = ipPartition.getSipPartitionMap();
        List<DelayPo> delayPos = Lists.newArrayList();
        for (Map<String, String> stringStringMap : sipPartitionMap) {
            String scope = stringStringMap.get("scope");
            String[] split = scope.split(",");
            for (String s : split) {
                String[] se = s.split("-");
                long startIp = IpUtil.ipToLong(se[0]);
                long endIp = IpUtil.ipToLong(se[1]);
                String province = stringStringMap.get("province");
                String area = stringStringMap.get("area");
                String sql = "SELECT\n" +
                        "Avg(t.clntdelay) AS avg_clntdelay, " +
                        "Avg(t.svrdelay) AS avg_svrdelay, " +
                        "Avg(t.appdelay) AS avg_appdelay, " +

                        "MAX(t.clntdelay) AS max_clntdelay, " +
                        "MAX(t.svrdelay) AS max_svrdelay, " +
                        "MAX(t.appdelay) AS max_appdelay, " +

                        "MIN(t.clntdelay) AS min_clntdelay, " +
                        "MIN(t.svrdelay) AS min_svrdelay, " +
                        "MIN(t.appdelay) AS min_appdelay, " +

                        "AVG(t.retmixpkts1/t.pkts1) AS avg_up_rr, " +
                        "MIN(t.retmixpkts1/t.pkts1) AS min_up_rr, " +
                        "MAX(t.retmixpkts1/t.pkts1) AS max_up_rr, " +

                        "AVG(t.retmixpkts2/t.pkts2) AS avg_down_rr, " +
                        "MIN(t.retmixpkts2/t.pkts2) AS min_down_rr, " +
                        "MAX(t.retmixpkts2/t.pkts2) AS max_down_rr " +


                        "FROM " + "`" + table + "`" + " AS t " +
                        "WHERE " +
                        "t.s1 >= " + startIp + " AND " +
                        "t.s1 <= " + endIp + " AND " +
                        "t.pro = 17" + " AND " +
                        //"t.appid = 61" + " AND " +
                        "t.appdelay > 0" +
                        ";";
                rs = stmt.executeQuery(sql);
                while (rs.next()) {
                    // 通過字段檢索
                    double clientDelay = rs.getDouble("avg_clntdelay");
                    double serviceDelay = rs.getDouble("avg_svrdelay");
                    double appDelay = rs.getDouble("avg_appdelay");
                    double maxDelay = rs.getDouble("max_clntdelay");
                    double maxServiceDelay = rs.getDouble("max_svrdelay");
                    double maxAppDelay = rs.getDouble("max_appdelay");
                    double minDelay = rs.getDouble("min_clntdelay");
                    double minServiceDelay = rs.getDouble("min_svrdelay");
                    double minAppDelay = rs.getDouble("min_appdelay");
                    double avgUpRr = rs.getDouble("avg_up_rr");
                    double minUpRr = rs.getDouble("min_up_rr");
                    double maxUpRr = rs.getDouble("max_up_rr");

                    double avgDownRr = rs.getDouble("avg_down_rr");
                    double minDownRr = rs.getDouble("avg_down_rr");
                    double maxDownRr = rs.getDouble("avg_down_rr");
                    delayPos.add(new DelayPo(province, area, clientDelay, serviceDelay, appDelay, maxDelay, maxServiceDelay, maxAppDelay,
                            minDelay, minServiceDelay, minAppDelay, avgUpRr, minUpRr, maxUpRr, avgDownRr, minDownRr, maxDownRr));
                }
            }


        }
        return delayPos;
    }
}

3. 具體子類的使用

3.1 具體子類DnsTopDelaySearch的使用

public List<DnsDelayPo> dnsTopDelay() {
        dnsTopDelaySearch.init(user, password, ip, port, dbDriver);
        return dnsTopDelaySearch.exec();
    }

3.2 具體子類SipTopDelaySearch的使用

public List<TopDelayPo> getSipTopDelay() {
        sipTopDelaySearch.init(user, password, ip, port, dbDriver);
        return sipTopDelaySearch.exec();
    }

4. 鉤子

鉤子方法的返回結果決定了模板方法後面部分的執行步驟,也就是程序接下來的走向,
這樣一來,程序就擁有了變化的可能。
未完待續

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章