美文网首页
桥接模式简单学习记录

桥接模式简单学习记录

作者: 梧叶已秋声 | 来源:发表于2019-12-24 15:57 被阅读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. 桥接模式

    相关文章

      网友评论

          本文标题:桥接模式简单学习记录

          本文链接:https://www.haomeiwen.com/subject/itwxoctx.html