【问题标题】:OOP structure designOOP结构设计
【发布时间】:2012-10-31 01:57:11
【问题描述】:

我正在尝试设计“网络连接”,以便轻松用于从服务器检索数据。但是,我面临一个设计问题。

我要使用的NetworkUtil 类被设计为

class NetworkUtil
    public NetworkUtil(URL, resultType); // resultType might be XML or RAW
    public setListener(listener); // listener will notice when result has arrive
    public addPostData(key, value);
    public connect(); // connect start new thread, so result will shown in listener

interface NetworkUtilListener1
    public onNetworkFail();
    public onNetworkSuccess(URL, resultType, xml, raw);

interface NetworkUtilListener2
    public onNetworkFail();
    public onNetworkSuccessRAW(URL, resultType, raw);
    public onNetworkSuccessXML(URL, resultType, xml);

一旦结果到达,我将检查 resultType 并使用该参数的结果。但是在上面显示的 2 个示例中(NetworkUtilListener1NetworkUtilListener2),当更多 resultType 出现时(例如 JSON、图像甚至我的自定义类型),我会考虑将来使用的问题,因此我的团队可以轻松使用它。

NetworkUtilListener1 将有长期未使用的参数,如

onNetworkSuccess(URL, resultType, raw, xml, json, image);

这不是我认为的好设计。

NetworkUtilListener2 将强制使用它的具体类有很多空方法,因为大多数时候我们更喜欢每个项目只使用 1 或 2 种类型的结果。

onNetworkSuccessRAW(URL, resultType, raw);
onNetworkSuccessXML(URL, resultType, xml);
onNetworkSuccessJSON(URL, resultType, json);
onNetworkSuccessImage(URL, resultType, image);

任何人都可以在重新设计这个类结构时给我一些帮助,或者向我推荐我需要关注的设计模式。所以我可以有更好的NetworkListener

【问题讨论】:

    标签: java oop design-patterns conceptual


    【解决方案1】:

    利用多态性代替接收类型和结果:

    public interface Result { ... }
    
    public class XmlResult implements Result { ... }
    

    将来您可以根据需要添加任意数量。

    public class JSonResult implements Result { ... }
    

    终于有了这个界面

    interface NetworkUtilListener1
        public onNetworkFail();
        public onNetworkSuccess(URL, result);
    

    【讨论】:

      【解决方案2】:

      这听起来像是经典 visitor pattern 的解决方案:

      让我们从重载 NetworkListener 方法开始:

      interface NetworkListener {
          void onSuccess(XMLResult xml);
          void onSuccess(JSONResult json);
      }
      

      然后,按照建议,让我们有几个结果的实现。他们每个人都能够通过调用适当的重载方法来通知侦听器。

      interface Result {
          void notify(NetworkListener listener);
      }
      
      class XMLResult implements Result {
      
          @Override
          public void notify(NetworkListener listener) {
              listener.onSuccess(this);
          }
      
      }
      
      class JSONResult implements Result {
      
          @Override
          public void notify(NetworkListener listener) {
              listener.onSuccess(this);
          }
      }
      

      现在,让我们看看示例网络侦听器实现的样子:

      class SampleListner implements NetworkListener{
      
          @Override
          public void onSuccess(XMLResult xml) {
              // handle here
          }
      
          @Override
          public void onSuccess(JSONResult json) {
              // handle here
      
          }
      }
      

      你的通知代码看起来有点像:

      Result result = null;
      for(NetworkListener listener: listeners){
         result.notify(listener);
      }
      

      由于该模式严重依赖于方法重载,因此您可以添加一个接收 Result 对象的包罗万象的方法,这将保证如果创建了任何新的 Result 实现,如果您不这样做,您仍然可以获得它们的默认处理添加更多的重载方法。

      【讨论】:

      • 感谢您的回答,但我认为您的解决方案与 NetworkUtilListener2 存在相同的问题 - 具体类(在您的情况下是 SampleListener)需要实现很多空方法。但是,从您的代码中,我想出了一个想法。如果我使用类而不是接口作为侦听器真正的创建类不需要具有接口的所有功能。但我仍然不确定这是个好主意。
      • @Chetchhaiyan 访问者模式有很多优点,您应该考虑一下。关于实现许多方法的需要,这是设计使然,因为您的代码是关于单独处理每种类型的结果。但是,您可以定义一个具有所有方法的空实现的抽象类(即 NetworkUtilsAdapter)(类似于某些 Java Swing 侦听器中使用的策略 [即 WindowAdapter)。然后你的实际监听器实现可以简单地扩展这个抽象适配器并实现你感兴趣的具体方法。
      【解决方案3】:

      我认为 NetworkUtil 不应该担心格式类型。只需让 NetworkListener 将自己注册到 NetworkUtil 并让 NetworkUtil 成功通知侦听器。让 NetworkListener 担心类型,因为它们是唯一处理结果的。应该是这样的

      class NetworUtil{
         registerListener( listener){ mylisteners.push( listener); }
         notifyListener(){ for(listener: mylisteners){ listener.onSuccess( myresult ); }
      }
      
      class Listener1{
         Listener1(){ registerWithNetworkUtil(); }
         void onSuccess(myresult){
             if(myresult.isXML){ parseXML(myresult); }
             else if(myresult.isJSON()){ parseJSON(myresult); }
             else if(myresult.isXXYYZZ()){ parseXXYYZZ(myresult); }
         }
      }
      

      请注意,您可能需要一些方便的默认解析器,以便新的侦听器可以使用它们。

      【讨论】:

      • 最有可能的字符串,虽然上面是伪代码,或者可能是原始结果的包装
      • String 没有像 isJSON()isXML() 这样的方法。
      • 我知道,只是演示想法,以上都不是有效代码,显然...
      • 谢谢你的回答,我想我明白你的概念了。使用 myresult 的概念与 ivowiblo 建议完全相同。但是 parseJON(myresult) 和 parseXXYYZZ(myresult) 真的很有趣,我会尝试更深入地打破它。
      猜你喜欢
      • 1970-01-01
      • 2017-02-16
      • 2019-01-26
      • 2016-05-08
      • 1970-01-01
      • 2010-11-21
      • 2014-10-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多