1. 程式人生 > 實用技巧 >Builder模式實戰1

Builder模式實戰1

一.目的

  通過實際的專案程式碼來熟悉並且深入理解Builder的作用,並瞭解該模式的優缺點.

二.作用

  Builder模式的作用

  1.簡化程式碼結構

   當一個類中屬性比較多時,而構建物件時,也並非每一個屬性都要用。如果此時用建構函式來夠造物件.時,需要過載多次構造方法。或者使用一個方法需要過載多次。

過載方法多了會造成類非常臃腫,且不好維護,此時可以把這些屬性抽離出去,或者把建立物件委託給另外一個類。

  2.封裝和解耦

  將建立物件的方法隱藏起來,外部呼叫者只管傳參,不用管建立者內部如何建立該物件。

  3.控制權反轉,方便配置

  將物件的建立權交給Builder類,可將物件的屬性傳遞和被建立物件隔離開,方便使用配置檔案來配置建立物件

  4.可複用物件,避免重複的new物件造成記憶體開銷,並且很容易的結合快取和物件池來使用

  

三.未重構前的程式碼

過載方法多,傳入屬性多,且有些是可選的

public static boolean createTable(String tableName, String cf, boolean inMemory, int ttl, int maxVersion){

        HTableDescriptor htd = createHTableDescriptor(tableName, cf, inMemory, ttl, maxVersion, COPROCESSORCLASSNAME);

        return createTable(htd);

    }

    public static boolean createTable(String tableName, String cf, boolean inMemory, int ttl, int maxVersion,  boolean useSNAPPY){


        HTableDescriptor htd = createHTableDescriptor(tableName, cf, inMemory, ttl, maxVersion, useSNAPPY , COPROCESSORCLASSNAME);

        return createTable(htd);

    }

    public static boolean createTable(String tableName, String cf, boolean inMemory, int ttl, int maxVersion,  boolean useSNAPPY, byte[][] splits){


        HTableDescriptor htd = createHTableDescriptor(tableName, cf, inMemory, ttl, maxVersion, useSNAPPY, COPROCESSORCLASSNAME);
        return createTable(htd , splits);

    }

   
    public static boolean createTable(String tableName,
                                      String cf,
                                      boolean inMemory,
                                      int ttl,
                                      int maxVersion,
                                      byte[][] splits){

        //建立表描述類  設定表的結構和引數
        HTableDescriptor htd = createHTableDescriptor(tableName, cf, inMemory, ttl, maxVersion, COPROCESSORCLASSNAME);
        //通過HTableDescriptor 和 splits 分割槽策略來定義表
        return createTable(htd , splits);

    }

  

四.角色劃分

五.具體程式碼

HBaseTableOperatorBase.java
public class HBaseTableOperatorBase {
    protected HBaseConf conf = HBaseConf.getInstance();
    protected final Logger LOG = LoggerFactory.getLogger(HBaseTableOperatorBase.class);
    protected final String COPROCESSORCLASSNAME =  "org.apache.hadoop.hbase.coprocessor.AggregateImplementation";
}

  

HBaseTableCreator.java
public class HBaseTableCreator extends HBaseTableOperatorBase{
    private HBaseTableCreatorParms parms;

    public void setParms(HBaseTableCreatorParms parms){
        this.parms = parms;
    }

    private HTableDescriptor createHTableDescriptor(){
        // 2.表描述
        HTableDescriptor htd = new HTableDescriptor(TableName.valueOf(parms.getTableName()));

        List<HColumnDescriptor> columnDescriptors = createColumnDescriptors();
        columnDescriptors.forEach(hcd->{
            htd.addFamily( hcd);
        });

        for( String coprocessorClassName : parms.getCoprocessorClassNames() ){
            try {
                htd.addCoprocessor(coprocessorClassName);
            } catch (IOException e1) {
                LOG.error("為表" + parms.getTableName() + " 新增協處理器失敗。 ", e1);
            }
        }
        return htd;
    }

    private List<HColumnDescriptor> createColumnDescriptors(){
        List<HColumnDescriptor> cfs = new ArrayList<>();
        parms.getColumFamilies().forEach(x->{
            cfs.add(createColumnDescriptor(x));
        });
       return cfs;
    }

    private HColumnDescriptor createColumnDescriptor(String columnFamily){
        HColumnDescriptor hcd = new HColumnDescriptor(columnFamily);
        //定義最大版本號
        if( parms.getMaxVersion() > 0 )hcd.setMaxVersions(parms.getMaxVersion());

        hcd.setBloomFilterType(BloomType.ROWCOL);
        hcd.setInMemory(parms.isInMemory());
        hcd.setScope(1);

        if(parms.isUseSNAPPY())hcd.setCompressionType(Compression.Algorithm.SNAPPY);

        if( parms.getTtl() < 0 ) parms.setTtl(HConstants.FOREVER);
        hcd.setTimeToLive(parms.getTtl());
        return hcd;
    }

    public  boolean createTable(){
        HTableDescriptor htd = createHTableDescriptor();
        Admin admin = null;

        try {
            admin = conf.getHconnection().getAdmin();
            if(admin.tableExists(htd.getTableName())){
                LOG.info("表" + htd.getTableName() + "已經存在");
            }else{
                if(parms.getSplits()==null){
                    admin.createTable(htd);
                }else{
                    admin.createTable(htd,parms.getSplits());
                }
            }
        } catch(IOException e )  {
            LOG.error("建立HBase表失敗。", e);
            return false;
        }finally{
            try {
                if(admin!=null){
                    admin.close();
                }
            } catch (IOException e) {
                LOG.error("", e);
            }
        }
        return true;
    }
}

  

HBaseTableCreatorParms.java
public class HBaseTableCreatorParms {
    private String tableName;
    private List<String> columFamilies = new ArrayList();
    private boolean inMemory = false;
    private int ttl = -1;
    private int maxVersion = 1;
    private boolean useSNAPPY = true;
    private byte[][] splits = null;
    private List<String> coprocessorClassNames = new ArrayList();

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public List<String> getColumFamilies() {
        return columFamilies;
    }

    public void setColumFamilies(List<String> columFamilies) {
        this.columFamilies.addAll(columFamilies);
    }

    public void setColumFamilies(String... columFamilies) {
        for (String columFamily : columFamilies) {
            this.columFamilies.add(columFamily);

        }
    }

    public boolean isInMemory() {
        return inMemory;
    }

    public void setInMemory(boolean inMemory) {
        this.inMemory = inMemory;
    }

    public int getTtl() {
        return ttl;
    }

    public void setTtl(int ttl) {
        this.ttl = ttl;
    }

    public int getMaxVersion() {
        return maxVersion;
    }

    public void setMaxVersion(int maxVersion) {
        this.maxVersion = maxVersion;
    }

    public boolean isUseSNAPPY() {
        return useSNAPPY;
    }

    public void setUseSNAPPY(boolean useSNAPPY) {
        this.useSNAPPY = useSNAPPY;
    }

    public byte[][] getSplits() {
        return splits;
    }

    public void setSplits(byte[][] splits) {
        this.splits = splits;
    }

    public List<String> getCoprocessorClassNames() {
        return coprocessorClassNames;
    }

    public void setCoprocessorClassNames(List<String> coprocessorClassNames) {
        this.coprocessorClassNames.addAll(coprocessorClassNames);
    }

    public void setCoprocessorClassNames(String... coprocessorClassNames) {
        for (String coprocessorClassName : coprocessorClassNames) {
            this.coprocessorClassNames.add(coprocessorClassName);
        }
    }

    @Override
    public String toString() {
        return "HBaseTableCreatorParms{" +
                "tableName='" + tableName + '\'' +
                ", columFamilies=" + columFamilies +
                ", inMemory=" + inMemory +
                ", ttl=" + ttl +
                ", maxVersion=" + maxVersion +
                ", useSNAPPY=" + useSNAPPY +
                ", coprocessorClassNames=" + coprocessorClassNames +
                '}';
    }
}

  

HBaseTableCreatorBuilder.java
public class HBaseTableCreatorBuilder {

    private HBaseTableCreatorParms parms = new HBaseTableCreatorParms();
   
    //應該快取,或者懶載入 
    public static HBaseTableCreatorBuilder builder(){
        return new HBaseTableCreatorBuilder();
    }

    public HBaseTableCreatorBuilder setTableName(String tableName){
        this.parms.setTableName(tableName);
        return this;
    }

    public HBaseTableCreatorBuilder setColumnFamilies(String ...columnFamily){
        this.parms.setColumFamilies(columnFamily);
        return this;
    }

    public HBaseTableCreatorBuilder setColumnFamilies(List<String> columnFamily){
        this.parms.setColumFamilies(columnFamily);
        return this;
    }

    public HBaseTableCreatorBuilder setInMemory(boolean inMemory){
        this.parms.setInMemory(inMemory);
        return this;
    }

    public HBaseTableCreatorBuilder setMaxVersion(int maxVersion){
        this.parms.setMaxVersion(maxVersion);
        return this;
    }

    public HBaseTableCreatorBuilder setUseSNAPPY(boolean useSNAPPY){
        this.parms.setUseSNAPPY(useSNAPPY);
        return this;
    }

    public HBaseTableCreatorBuilder setSplits(byte[][] splits){
        this.parms.setSplits(splits);
        return this;
    }

    public HBaseTableCreatorBuilder setCoprocessorClassNames(String... coprocessorClassNames){
        this.parms.setCoprocessorClassNames(coprocessorClassNames);
        return this;
    }

    public HBaseTableCreatorBuilder setCoprocessorClassNames(List<String> coprocessorClassNames){
        this.parms.setCoprocessorClassNames(coprocessorClassNames);
        return this;
    }

    // TODO: 8/29 後期優化程式碼時,要考慮把該物件快取起來,避免每次建立都new (可以結合原型pattern ,也可以不考慮)
    public HBaseTableCreator Create(){
        HBaseTableCreator creator = new HBaseTableCreator();
        creator.setParms(parms);
        return creator;
    }
}

  測試用例,呼叫

 @Test
    public void TestCreateTable(){
        boolean success = HBaseTableCreatorBuilder.builder()
                                .setTableName("test1")
                                .setColumnFamilies("cf1","cf2")
                                .Create()
                                .createTable();
        System.out.println(success);
    }

    @Test
    public void TestCreateSplitTable(){
        boolean success = HBaseTableCreatorBuilder.builder()
                .setTableName("test2")
                .setColumnFamilies("info")
                .setSplits(SpiltRegionUtil.getSplitKeysByRadom())
                .Create()
                .createTable();
        System.out.println(success);
    }

  

六.總結

通過上述程式碼可知,Builder模式有助於使程式碼更加清晰,並且容易拓展。比較適合頻繁建立物件的業務場景,但是缺點就是類的數量會變的特別多,建議還是在屬性特別多並且可選時使用。