设计模式之模板模式到桥接模式



之所以把模板模式和桥接模式联系到一块儿说,是因为我最近写一个HBaseTemplate的时候突然发现按照模板模式去写,使用的时候必须继承自该类,很重量级,不优雅。于是对他进行改造,改造之后发现这不就是桥接模式吗?


先说一下什么是模板模式?

引用《设计模式之禅》中的模板模式的定义:定义一个操作中算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。


我个人通俗的解释是某件事有成型或者固有的操作流程,先干A,再干B,最后干C,而A,C是必须要干的,而且每个流程都一样,那么我们可以定义一个抽象类,把B这件事定义为一个抽象方法,让子类去实现,不同的B就有不同的子类,但是主流程没有变,而且也不用管A和C,只关注B就行了。


比如我们用HBase的时候,要先设置configuration、然后再获取connection,然后根据tablename获取HTable,根据HTable去做put,get操作,用完后关闭table。

public static HConnection CONNECTION = null;      
HTable table = null;
try{ 
CONF = HBaseConfiguration.create();
CONNECTION = HConnectionManager.createConnection(CONF);
table = (HTable) CONNECTION.getTable(tableName);
Put rowPut = new Put(Bytes.toBytes(rowKey));
table.put(rowPut);
}catch(Exception e){
if(table != null){
   table.close();
}
}

 
如以上步骤,只有7、 8两行是实际业务有用的操作,其他部分所有的都得写一遍,太费事了。


于是定义了一个抽象模板类

public abstract class HBaseTemplate {
    public void execute(String tableName) {
        Configuration CONF = null;
        HConnection CONNECTION = null;
        HTable table = null;
        try {
            CONF = HBaseConfiguration.create();
            CONNECTION = HConnectionManager.createConnection(CONF);
            table = (HTable) CONNECTION.getTable(tableName);
            doInTable(table);
        } catch (Exception e) {
            if (table != null) {
                try {
                    table.close();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    public abstract void doInTable(HTable hTable);
}

 
以上红色代码是实际要做的事情,实际用的时候继承该类,实现doInTable()方法就可以了,获取connection、关闭连接等都不用管了。

这就是一个典型的模板模式,类图如下:


什么是桥接模式?

以上模板模式存在的问题是每次使用都需要继承父类,很重量级。针对以上结构做了如下改造


public class HBaseTemplate {
    public void execute(String tableName,TableCallback tableCallback) {
        Configuration CONF = null;
        HConnection CONNECTION = null;
        HTable table = null;
        try {
            CONF = HBaseConfiguration.create();
            CONNECTION = HConnectionManager.createConnection(CONF);
            table = (HTable) CONNECTION.getTable(tableName);
            tableCallback.doInTable(table);
        } catch (Exception e) {
            if (table != null) {
                try {
                    table.close();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
    }
}



public static interface TableCallback {
        void doInTable(HTableInterface table) throws Exception;
    }
}

 

把之前的抽象方法变成了接口,这样用的时候可以这样:

HBaseTemplate hbaseTemplate = new HBaseTemplate();
hbaseTemplate.execute("tableName1", new TableCallback() {
            @Override
            public void doInTable(HTableInterface table) throws Exception {
               //do something...

            }
});

 
也可以把匿名内部类的实现单独定义为一个类TableCallBackImpl,动态给hbaseTemplate注入进来,这样既灵活又不用继承。
以上是对模板模式的一个改造,以上只是针对获取htable后的操作的变化,但是如果获取htable的方法也变化怎么办,比如以后我要维护一个HTable的池,不每次都"获取table->用table->关闭连接",而是同一个tableName维护一定数量的table,每次从池里取,可以快速,并节省资源。可以再改造

public abstract class HBaseTemplate {
    public void execute(String tableName,TableCallback tableCallback) {
        Configuration CONF = null;
        HConnection CONNECTION = null;
        HTable table = null;
        try {
            getTable(tableName);
            tableCallback.doInTable(table);
        } catch (Exception e) {
            if (table != null) {
                try {
                    table.close();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    public static interface TableCallback {
        void doInTable(HTableInterface table) throws Exception;
    }
    
    public abstract HTable getTable(String tableName);
}

 

这样就可以有HBasePoolTemplate、HBaseNotPoolTemplate实现了获取table维度的扩展。
其实也大可以把getTable()抽象方法改成接口类,动态注入进来。


写着写着感觉我们平常写Controller、Service类的时候就是在注入各种service、dao,头大了吧,其实设计模式只是一种理念、一种思想,体现到类图上可能会很像,甚至一样。理解这种思想,在实际工作中有意识的去应用,而不是随便乱堆代码就可以了。时间长了自然能写出很优雅的代码,设计模式神马的已经融入血液了,无意识的就知道什么场景该怎么写,已经不管他什么模式了。就像张三丰教张无忌太极剑,最后张无忌一招都不记得了,但却很厉害!




如果不是这么做还是按照之前模板模式的方案,那么每有一个htable的操作都要有一个子类HBaseDao1,HBaseDao2,如果再加上连接池,那么又要继承自HBaseDao1,HBaseDao2,就出现了HBasePoolDao1,HBasePoolDao2,如果有三个维度的变化那类的扩张速度就更多了。


桥接模式定义:将抽象和实现解耦,使得两者可以独立的变化。


桥接模式类图:




1.Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。

2.所谓抽象和实现沿着各自维度的变化,即“子类化”它们,得到各个子类之后,便可以任意组合它们。

3.Bridge模式的应用一般在“两个非常强的变化维度(以上例子的两个维度是:获取htable、应用htable做增删改)”,有时候即使有两个变化的维度,但是某个方向的变化维度并不剧烈——换言之两个变化不会导致纵横交错的结果,并不一定要使用Bridge模式。



猜你喜欢

转载自danding.iteye.com/blog/2363615
今日推荐