Builder模式實戰1
阿新 • • 發佈:2020-09-07
一.目的
通過實際的專案程式碼來熟悉並且深入理解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模式有助於使程式碼更加清晰,並且容易拓展。比較適合頻繁建立物件的業務場景,但是缺點就是類的數量會變的特別多,建議還是在屬性特別多並且可選時使用。