桥接模式简单学习记录

2019-12-24  本文已影响0人  梧叶已秋声

由于想深入一点了解Window Manager这一块,由于Window Manager用到了桥接模式,因此先了解一下桥接模式。Android 源码中存在大量的设计模式,而对于设计模式这一块的内容,我是属于看过就忘记的类型,虽然当初花过一段时间去看了很多设计模式,但是由于基本上工作中没有用到过所以时间长了就忘记了,这一块知识待补。
虽然设计模式这一块的文章写的人比较多,但是很多时候实际上由于个人水平以及理解能力的不同,导致不能很好地理解,由于我比较喜欢那种代码贴全了可以运行的sample,所以我觉得下面这篇文章例子举得比较好。
从Java类库看设计模式(3)
下面贴出代码以及简单解释。

出处:https://www.ibm.com/developerworks/cn/java/l-jdkdp/part3/index.html
下面,我们来看一个Bridge模式的具体应用。考虑这样的一个问题,需要生成一份报告,但是报告的格式并没有确定,可能是HTML文件,也可能是纯ASCII文本。报告本身也可能分为很多种,财务报表,货物报表,等等问题很简单,用继承也较容易实现,因为相互之间的组合关系并不是很多。但是,我们现在需要用Bridge的观点来看问题。
在Bridge模式中,使用一个Report类来描叙一个报告的抽象,用一个Reporter类来描叙Report的实现,它的子类有HTMLReporter和ASCIIReporter,用来分别实现HTML格式和ASCII格式的报告。在Report层次下面,有具体的一个StockListReport子类,用来表示货物清单报告。

public abstract class Report {
    Reporter reporter;

    public Report(Reporter reporter) {
        this.reporter = reporter;
    }
    public void addReportItem(Object item){
        reporter.addLine(item.toString());
    }

    public void addReportItems(List items){
        Iterator iterator = items.iterator();
        while ( iterator.hasNext() )
        {
            reporter.addLine(iterator.next().toString());
        }
    }

    public String report(){
        return reporter.getReport();
    }
}
public abstract class Reporter {
    String header = "";
    String trailer = "";
    String report = "";

    public abstract void addLine(String line);

    public void setHeader(String header){
        this.header = header;
    }

    public void setTrailer(String trailer){
        this.trailer = trailer;
    }

    public String getReport(){
        return header+report+trailer;
    }

}
public class StockListReport extends Report {

    ArrayList stock=new ArrayList();

    public StockListReport(Reporter reporter){
        super(reporter);
    }

    public void addStockItem(String stockItem){
        stock.add(stockItem);
        addReportItem(stockItem);
    }
}
public class ASCIIReporter extends Reporter {
    public void addLine(String line) {
        report += line + "\n";
    }
}
public class HTMLReporter extends Reporter {
    public HTMLReporter(){
        setHeader("<HTML>\n<HEAD></HEAD>\n<BODY>\n");
        setTrailer("</BODY>\n</HTML>");
    }
    public void addLine(String line){
        report += line + "<BR>\n";
    }
}

最后就是生成两种报告。

public class MainActivity extends AppCompatActivity{
    private static final String TAG = "MainActivity";

    private StockListReport mStockListReport1;
    private StockListReport mStockListReport2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mStockListReport1 = new StockListReport(new HTMLReporter());
        mStockListReport1.addStockItem("apple :1");
        mStockListReport1.addStockItem("orange :2");
        mStockListReport2 = new StockListReport(new ASCIIReporter());
        mStockListReport2.addStockItem("apple :1");
        mStockListReport2.addStockItem("orange :2");
        Log.d(TAG,"mStockListReport1 report = " + mStockListReport1.report());
        Log.d(TAG,"mStockListReport2 report = " + mStockListReport2.report() );
    }
}

生成报告结果如下:

    <HTML>
    <HEAD></HEAD>
    <BODY>
    apple :1<BR>
    orange :2<BR>
    </BODY>
    </HTML>
    apple :1
    orange :2

出处:https://www.ibm.com/developerworks/cn/java/l-jdkdp/part3/index.html
实际上,Bridge模式是一个很强大的模式,可以应用在很多方面。其基本思想:分离抽象和实现,是设计模式的基础之一。正如GOF所提到的:"找到变化的部分,并将其封装起来";"更多的考虑用对象组合机制,而不是用对象继承机制"。Bridge模式很好的体现了这几点。

桥接模式的关键点在于:找到变化的部分,并将其封装起来。
至此,虽然对桥接模式有一定的了解,但是如果不使用桥接模式的话,直接生成不同格式的报告会怎么样?

public class ASCIIReporterTest {
    String header = "";
    String trailer = "";
    String report = "";

    public ASCIIReporterTest(){

    }
    public void addLine(String line){
        report += line + "\n";
    }

    public String getReport(){
        return header+report+trailer;
    }
}
public class HTMLReporterTest {
    String header = "";
    String trailer = "";
    String report = "";

    public HTMLReporterTest(){
        setHeader("<HTML>\n<HEAD></HEAD>\n<BODY>\n");
        setTrailer("</BODY>\n</HTML>");
    }
    public void addLine(String line){
        report += line + "<BR>\n";
    }

    public void setHeader(String header){
        this.header = header;
    }

    public void setTrailer(String trailer){
        this.trailer = trailer;
    }

    public String getReport(){
        return header+report+trailer;
    }
}
        ASCIIReporterTest asciiReporterTest = new ASCIIReporterTest();
        asciiReporterTest.addLine("apple :1");
        Log.d(TAG,asciiReporterTest.getReport());
        HTMLReporterTest htmlReporterTest = new HTMLReporterTest();
        htmlReporterTest.addLine("apple :1");
        Log.d(TAG,htmlReporterTest.getReport());

结果是

apple :1
    <HTML>
    <HEAD></HEAD>
    <BODY>
    apple :1<BR>
    </BODY>
    </HTML>

对比一下,如果不使用设计模式的话,在需要生成2种不同格式的报告的情况下,只需要直接新建2个类,然后使用,如果使用bridge设计模式的话,这里需要使用5个类。
缺点这里其实很明显了,增加了复杂度。

以下出处:https://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/bridge.html#id11
桥接模式的缺点:
桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。 - 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。

那么桥接模式的优点在哪里?
此时如果不使用设计模式,需要新建不同的repoter类,并且需要重新定义内部细节,这种时候,设计模式的优点就显示出来了,虽然类的数量会稍微多一点,但是可以尽量减少改动,这种优势在数量多的情况下会更加明显(例如20个不同格式的报告类)。
下面以HTMLReporter 和HTMLReporterTest为例去对比分析。

public class HTMLReporterTest {
    String header = "";
    String trailer = "";
    String report = "";

    public HTMLReporterTest(){
        setHeader("<HTML>\n<HEAD></HEAD>\n<BODY>\n");
        setTrailer("</BODY>\n</HTML>");
    }
    public void addLine(String line){
        report += line + "<BR>\n";
    }

    public void setHeader(String header){
        this.header = header;
    }

    public void setTrailer(String trailer){
        this.trailer = trailer;
    }

    public String getReport(){
        return header+report+trailer;
    }
}
public class HTMLReporter extends Reporter {
    public HTMLReporter(){
        setHeader("<HTML>\n<HEAD></HEAD>\n<BODY>\n");
        setTrailer("</BODY>\n</HTML>");
    }
    public void addLine(String line){
        report += line + "<BR>\n";
    }
}

很明显,当使用桥接模式时,如果需要新建一个报告类,所需改动比不使用设计模式时少很多。如果是需要1个或2种不同的报告类,此时不使用设计模式可能还比较方便,但是当所需种类变多了之后,如果不使用设计模式的话就会变得比较麻烦,要新建大量的具有重复性的代码,而且不同格式报告类的差异没有那么一目了然。
这样看,桥接模式的优点也是很明显的。
但是,难点在于,如何找到变化的部分,并将其封装起来,在写代码的过程中,有时候并不能考虑到它的变化情况。

参考链接:
聊聊设计模式(1):桥接模式
Java 设计模式 101
从Java类库看设计模式(3)
2. 桥接模式

上一篇下一篇

猜你喜欢

热点阅读