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模式有助于使代码更加清晰,并且容易拓展。比较适合频繁创建对象的业务场景,但是缺点就是类的数量会变的特别多,建议还是在属性特别多并且可选时使用。