覆盖方法与多次实现方法

时间:2011-08-13 18:17:07

标签: java

假设我有一个从网上下载新闻Feed的课程

public class NewsDownloader {
   public String downloadNewsFast() {
      // download a news feed using a wifi connection
   }

   public String downloadNewsNormal() {
      // download a news feed using a 3g connection
   }

   public String downloadNewsSlow() {
      // download a news feed using a GPRS connection
   }
}

在上述情况下,根据可用的连接,有3种方式可以下载新闻。如您所见,上述类定义了3个方法(我知道在继承的情况下重新定义方法适用于静态方法)。

如果NewsDownloader的客户端根据可用的连接有条件地调用下载方法

public class NewsReader {
   NewsDownloader n = new NewsDownloader();

   public void getLatestNews(Connection c) {
      if (c.getType().equals("Wifi")) {
         n.downloadNewsFast();
      }
      else if (c.getType.equals("3g")) {
         n.downloadNewsNormal();
      }
      else {
         n.downloadNewsSlow();
      }
   }
}

我的问题是双重的

  1. 如上所述,我可以遇到设计NewsDownloader的问题,而不是更抽象的方式,比如使用工厂模式?
  2. NewsReaderNewsDownloader的抽象设计有什么好处(如果有的话)?
  3. 我已经了解了工厂方法和抽象工厂模式的好处,并为了我自己的利益而实施了它们。但是,我看不出上面描述的方法和工厂模式之间的区别。

    我希望人们不认为这是拖钓!我只是想解释抽象设计为我正在编写的项目解决的问题

4 个答案:

答案 0 :(得分:3)

我不确定你想要将事情抽象化的原因是什么。一般规则:

  • 抽象类用于代码重用
  • 接口定义合同
  • 应用反转控制原则,工厂模式有时可以帮助

遵循这些指导原则,我认为没有立即考虑为NewsDownloader创建一个抽象类,因为只有其中一个。你可能会把它变成一个接口而不是一个类来松开耦合,这就是你所要求的好处,我想。最后,NewsReader不应该实例化自己的NewsDownloader,而是依赖于它以某种方式注入。

更新: TofuBeer's answer在将这些原则列入代码方面做得非常好。

答案 1 :(得分:2)

如果你像这样重组:

public interface NewsDowloader
{
    String download();
}

public class FastNewsDownloader
    implements NewsFownloader
{
    public String download() { /* ... */ }
}

public class NormalNewsDownloader
    implements NewsFownloader
{
    public String download() { /* ... */ }
}

public class SlowNewsDownloader
    implements NewsFownloader
{
    public String download() { /* ... */ }
}

然后NewsReader看起来像这样:

public class NewsReader 
{
    public void getLatestNews(NewsDownloader downloader) 
    {
        downloader.download();
    }
}

添加工厂以创建NewsDownloader实例:

public class NewsDownloaderFactory
{
    public NewsDownloader getNewsDownloader(final Connection c)
    {
        final NewsDownloader downloader;

        if(c.getType().equals("Wifi"))
        {
            downloader = new FastNewsDownloader();
        }
        else if(c.getType().equals("3g"))
        {
            downloader = new NormalNewsDownloader();
        }
        else
        {
            downloader = new SlowNewsDownlaoder();
        }

        return (downloader);
    }  
}

然后你可以把它们放在一起:

public void foo(final Connection c)
{
    final NewsDownloader downloader;
    final NewsReader     reader;

    downloader = NewsDownloaderFactory.getNewsDownloader(c);
    reader = new NewsReader(downlaoder);    
}

现在你已经拥有了所有这些优势:

  • 您可以添加新的NewsDownloader实现,而不必将代码添加到代码中的大量if / else语句中(假设您在多个位置创建了NewsDownloader)。
  • 您已将创建(工厂)本地化为单个if / else,这使代码更清晰。

这意味着如果你添加一个不同类型的NewsDownloader,你只需要更改工厂,所有使用下载程序的代码都会神奇地起作用。

如果你的代码乱丢if / else语句,那么在添加新的下载程序类型时忘记修改其中一个错误可以减少错误的数量。

答案 2 :(得分:1)

您不一定会遇到问题,但有人认为,当发明新的网络连接时,您需要同时更新NewsReader以及NewsDownloader。如果(例如)你使用了工厂模式,那么你可以这样做,你将返回一个带有downloadNews()方法的对象,而NewsReader类并不需要担心它是否是慢,快等;返回的对象只需要有一个downloadNews()方法,而NewsReader会很高兴。

但是你拥有的代码肯定会起作用,它不被认为是理想的设计。

答案 3 :(得分:0)

您可以创建NewsDownloader的界面并创建三个Concrete类,以便以不同的速度下载。并设置NewsReader(NewsDownloader n)的属性以保存具体实现。