Java 接口--面向对象的精髓
qeea6228
8年前
<p>接口有何用?面试宝典上背下来的总结,你真的明白吗?</p> <p>接口&工厂方法 其实很简单>。</p> <p><strong>什么是接口</strong></p> <p>先看看生活中的接口,比如USB接口。</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/66f16d3e3377297596a5d5f7ac74b000.png"></p> <p>USB接口的设计者在最初就知道USB能支持这么多功能吗?他们是怎样未卜先知地设计的呢?其实他们也不知道以后USB上会连什么设备,他们只是定义了一个数据传输与供电的标准而已。</p> <p>Java中也是类似的,定义了接口,就等于 <strong>定义了调用对象的标准。</strong></p> <p>接口的基本语法</p> <ul> <li> <p>使用 interface定义;</p> </li> <li> <p>接口当中的方法都是抽象方法;</p> </li> <li> <p>接口当中的方法都是public权限(接口中的方法,写不写public修饰符,都是public权限,别的地方不行哦);</p> </li> </ul> <p>可以把接口理解成一个更加纯粹的抽象类,因此它也不能生成对象。这要怎么办呢?回想抽象类的处理方法,可以用一个类来继承(接口中叫实现)它,从而在子类中生成对象。</p> <p>一个最简单的接口示例:</p> <p>定义一个接口:</p> <pre> <code class="language-java">interface USB { public void read(); public void write(); }</code></pre> <p>定义它的子类,来实现这个接口:</p> <pre> <code class="language-java">class Phone implements USB { public void read() { System.out.println("Phone --> Read"); } public void write() { System.out.println("Phone --> Write"); } }</code></pre> <p>测试:</p> <pre> <code class="language-java">class Test { public static void main(String args []) { Phone phone = new Phone(); //向上转型 USB usb = phone; usb.read(); usb.write(); } }</code></pre> <p>运行结果:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/f635e23656984a0393257f5cd8c8ead1.png"></p> <p>继续了解接口的语法:</p> <ul> <li> <p>实现接口使用implements关键字;</p> </li> <li> <p>一个类可以实现多个接口;<br> 实现是特殊的继承,换句话说,就是一个类可以继承多个接口。<br> 修改上面的代码:<br> 再定义一个WiFi接口:</p> </li> </ul> <pre> <code class="language-java">interface WiFi { public void open(); public void close(); }</code></pre> <p>让Phone也实现WiFi接口:</p> <pre> <code class="language-java">class Phone implements USB, WiFi { public void read() { System.out.println("Phone --> Reading"); } public void write() { System.out.println("Phone --> Writing"); } //实现WiFi中的抽象方法 public void open() { System.out.println("WiFi --> Open"); } public void close() { System.out.println("WiFi --> Close"); } }</code></pre> <p>测试一下:</p> <pre> <code class="language-java">class Test { public static void main(String args []) { Phone phone = new Phone(); //向上转型时,就有两种选择 USB usb = phone; usb.read(); usb.write(); WiFi wifi = phone; wifi.open(); wifi.close(); } }</code></pre> <p>运行结果:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/9893f7b85c52d1e3f329fece85de7213.png"></p> <p>可以看到,用USB连接手机时,手机表现的就是USB的行为,用WiFi连接手机时,手机表现的就是WiFi的行为,这也是面向对象多态性非常明显的体现。</p> <ul> <li> <p>一个接口可以继承多个接口</p> <p>注意这里不能写成implements,因为我们只想继承USB和WiFi接口的抽象方法,而不想实现它。</p> </li> </ul> <pre> <code class="language-java">interface SbFi extends USB, WiFi { public void piu(); }</code></pre> <p>这样SbFi接口就拥有read(),write(),open(),close()和piu()五个抽象方法了:)</p> <h3><strong>接口的实践</strong></h3> <p>如果我们接到一个客户的需求,用程序控制办公室中的打印机,我们该怎么做呢?容易想到,先用一个类描述“打印机”,再用一些方法实现“开机”、“关机”、“打印”等动作,一个简单的Printer类就能搞定了。</p> <p>可是如果客户提出了新的需求,办公室又买了一台其他品牌的打印机,让你修改之前的代码。这时要怎么做呢?都是打印机,只是品牌不同,功能略有差异,容易想到用接口或者继承。接口更灵活一些,所以我们写出了下面的代码:</p> <p>首先定义一个Printer接口,描述打印机都有的行为:</p> <pre> <code class="language-java">interface Printer { void open(); void print(String s); void close(); }</code></pre> <p>在惠普打印机类中,实现Printer中的抽象方法:</p> <pre> <code class="language-java">class HPPrinter implements Printer { public void open() { System.out.println("HP: open"); } public void print(String s) { System.out.println("HP: print--> " + s); } public void close() { System.out.println("HP: close"); } }</code></pre> <p>在佳能打印机中,又增加了新的方法,清洗:</p> <pre> <code class="language-java">public class CanonPrinter implements Printer { public void open() { System.out.println("Canon: open"); } public void print(String s) { System.out.println("Canon: print-->" + s); } public void close() { this.clean(); System.out.println("Canon: close"); } public void clean() { System.out.println("Canon: clean"); } }</code></pre> <p>测试:</p> <p>注意,这里使用对象的向上转型,能减少重复代码。不然就得用HPPrinter和CanonPrinter生成的对象分别调用open, print, close方法,很麻烦。如果以后有100台打印机,岂不是得写300行?</p> <pre> <code class="language-java">class Test { public static void main(String args []) { Printer printer = null; //为简便,flag模拟用户选择使用哪台打印机 int flag = 1; if(flag == 0) { //向上转型 printer = new HPPrinter(); } else if(flag == 1) { printer = new CanonPrinter(); } printer.open(); printer.print("向上转型好用吧~"); printer.close(); } }</code></pre> <p>运行:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/278a6701c2344e7d49e85dba5280ec76.png"></p> <p>大功告成。但是这样就足够了吗?</p> <p>如果我们的打印机代码,是在一个办公自动化的系统当中。可能有各种各样的功能,要使用打印机。那每次使用时,都要把Test类中的这一段写一遍吗?如果以后有100个地方要用,岂不是要把这一段写100次?更可怕的是,如果又添加了新的打印机,岂不是要修改这100段代码?太容易出错了。所以,我们和重复代码,是势不两立的(振臂一呼)!</p> <p>进击的工厂方法模式减少重复代码的一般方法就是,把重复的代码放在一个地方(封装起来),等要用的时候,就调用它,而不是再写一遍。仔细看Test类,重复的地方,不包括最后三行,主要是根据用户的选择,生成打印机对象,并向上转型为Printer类型的部分。</p> <p>我们可以设计一个类,在里面添加一个函数,它的功能就是根据用户的选择生成打印机对象,以后我们直接调用这个函数就行了。函数的参数,就是用户的选择,返回值,就是一个Printer类型的对象。</p> <pre> <code class="language-java">class PrinterFactory { //添加static是为了调用方便 public static Printer getPrinter(int flag) { Printer printer = null; if(flag == 0) { printer = new HPPrinter(); } else if(flag == 1) { printer = new CanonPrinter(); } return printer; } }</code></pre> <pre> <code class="language-java">class Test { public static void main(String args []) { int flag = 1; Printer printer = PrinterFactory.getPrinter(flag); printer.open(); printer.print("对象的转型好用吧~"); printer.close(); } }</code></pre> <p>这样,就算要增加100台打印机,也只用在PrinterFactory中添加 else if(flag == xxx) 的代码,不用修改Test类。</p> <p>这就是著名的简单静态工厂方法模式。</p> <p>PrinterFactory并不关心Printer类有多少个子类,这样我们就能够自由地修改Printer子类了。</p> <p>工厂方法模式的思路很简单,就是把生成对象的代码,封装在工厂类当中。</p> <p> </p> <p> </p> <p>来自:http://geek.csdn.net/news/detail/108448</p> <p> </p>