2015-08-13 75 views
0

背景:我經常問自己以下問題,我從來沒有找到沒有缺陷的答案,我認爲這是模塊化軟件開發中的常見問題。所以我不肯定是否programmers.stackexchange.com更適合 - 但這個問題是完全集中在Java和我想的Java解決方案:將對象以標準方式傳遞給接口/抽象類

例子:有加載幾個插件誰是一個文本編輯器負責文本編輯器中的文件類型交互(Java插件處理Java代碼/文件,C/C++插件處理C/C++代碼/文件等) - 每個插件都需要配置和訪問文件管理器。這些插件必須訪問應用程序API才能完成一些有用的功能,而無需重新發明輪子。請記住,例如,應用程序的文件管理器本身也需要數據/對象(例如,具有行分隔符類型的配置,讀取模式類型等)。

問題:如何在文件管理器本身也需要配置時將配置/文件管理器傳遞給模塊化應用程序中的pugin(基於接口或抽象類)?

問題/事情要記住:

  • 我們需要將數據傳遞到文件管理器(配置等)
  • Java不支持自定義構造函數的接口和抽象類
  • 註解的對象很難測試,通常是所有邪惡的根源
  • 嘗試創建一個合適的/清晰的API,並儘可能地以扭曲的方式濫用/使用API​​

解決方案1:在插件中使用通過註釋進行依賴注入,所以我們可以獲取配置和文件管理器,並在我們的插件中使用它們。這是最流暢的解決方案,但不容易測試。

public class JavaPlugin implements Plugin 
{ 
    @Autowired 
    Configuration configuration; 

    @Autowired 
    FileManager filemanager; 

    public String processText(String rawtext) 
    { 
     // Do stuff and access the configuration/file manager 
    } 
} 

解決方案2:使文件管理器單......別急,我們如何通過配置的單身?製作另一個採用這些參數的靜態方法?這不再是一個單身人士,而是一個合適的API的地獄。

public class JavaPlugin implements Plugin 
{ 
    public String processText(String rawtext) 
    { 
     FileManager filemanager = FileManager.getInstance(); 
     Configuration configuiration = filemanager.getConfiguration(); 
     // Do stuff and use the configuration/file manager 
    } 
} 

public class FileManager 
{ 
    private static FileManager filemanager; 

    private Configuration configuration; 

    private FileManager(Configuration configuration) 
    { 
     this.configuration = configuration; 
    } 

    public static FileManager getIntialInstance(Configuration configuration) 
    { 
     if(filemanager == null) 
     { 
      filemanager = new FileManager(configuration); 
     } 
     return filemanager; 
    } 

    public static FileManager getInstance() 
    { 
     return filemanager; 
    } 

    public Configuration getConfiguration() 
    { 
     return configuration; 
    } 
} 

解決方案3:只是告訴了所有的插件開發者實現一個構造函數的配置和文件管理器作爲參數(因爲Java不支持在一個接口/抽象類的自定義構造函數)。我們使用反射創建插件對象,並將配置和文件管理器傳遞給構造函數。但是如果我們需要第三個對象會發生什麼?

public class JavaPlugin implements Plugin 
{ 
    public(Configuration configuration, FileManager filemanager) 
    { 
     // Save them 
    } 

    public String processText(String rawtext) 
    { 
     FileManager filemanager = FileManager.getInstance(); 
     Configuration configuiration = filemanager.getConfiguration(); 
     // Do stuff and use the configuration/file manager 
    } 
} 

public class PhpPlugin implements Plugin 
{ 
    public PhpPlugin() 
    { 
     // Oh dear you just broke your plugin.... 
    } 

    public String processText(String rawtext) 
    { 
     // Do stuff and use the configuration/file manager 
    } 
} 

最後的思考:我不滿意這三個解決方案之一100% - 每個人都有缺陷。我更喜歡強制開發人員遵循API的純粹主義(例如,他不應該能夠在任何地方使用單身人士 - 他應該得到數據,如果他需要他們,他必須存儲他們 - 否則他必須處理它) 。

StackOverflow問題:有沒有其他方法可以「解決」這個問題(也許我錯過了這些想法)?

+1

我錯過了什麼,或者爲什麼沒有你提到使用簡單的文件管理和配置,您可以通過Spring通過接口,自動裝配強制制定者(或注入自己,因爲你可以簡單的測試界面)並嘲笑UnitTests。 –

+0

這是另一個解決方案,但對我來說,這不是一個合適的API,因爲有人可以訪問文件管理器對象並將配置設置爲null - et瞧,你有樂趣 – swaechter

+1

雖然這是真的,但我沒有看到問題。有人也可以編寫一個FileManager實現,拋出隨機異常並將其設置在那裏,好的。但是,對於那些做最愚蠢的事情的人來說,冥想並不是思考的最佳方式。我總是假設合理的編碼員。 –

回答

1

從弗洛裏安Schaetz輸入後,我結束了這個解決方案,我真的很喜歡:

  • 隱藏插件開發者
  • 沒有構造所需的所有方法中的插件擴展基本插件類
  • 輕鬆添加新的變量/方法
  • 正確和清晰的API

代碼:

import java.util.ArrayList; 

public class PluginLoader 
{ 
    public static void main(String args[]) 
    { 
     new PluginLoader(); 
    } 

    public PluginLoader() 
    { 
     Configuration configuration = new Configuration("Processed text from plugin: "); 
     FileManager filemanager = new FileManager(configuration); 
     ArrayList<Plugin> plugins = new ArrayList<>(); 

     Plugin plugin1 = new JavaPlugin(); 
     plugin1.setConfiguration(configuration); 
     plugin1.setFileManager(filemanager); 
     plugins.add(plugin1); 

     Plugin plugin2 = new PhpPlugin(); 
     plugin2.setConfiguration(configuration); 
     plugin2.setFileManager(filemanager); 
     plugins.add(plugin2); 

     for(Plugin plugin : plugins) 
     { 
      System.out.println(plugin.getOutputName()); 
     }  
    } 

    public class JavaPlugin extends Plugin 
    { 
     public String getOutputName() 
     { 
      return getFileManager().getConfiguration().getText() + "JavaPlugin"; 
     } 
    } 

    public class PhpPlugin extends Plugin 
    { 
     public String getOutputName() 
     { 
      return getFileManager().getConfiguration().getText() + "PhpPlugin"; 
     } 
    } 

    public abstract class Plugin 
    { 
     private Configuration configuration; 

     private FileManager filemanager; 

     public abstract String getOutputName(); 

     public void setConfiguration(Configuration configuration) 
     { 
      if(this.configuration == null) 
      { 
       this.configuration = configuration; 
      } 
     } 

     public void setFileManager(FileManager filemanager) 
     { 
      if(this.filemanager == null) 
      { 
       this.filemanager = filemanager; 
      } 
     } 

     public Configuration getConfiguration() 
     { 
      return configuration; 
     } 

     public FileManager getFileManager() 
     { 
      return filemanager; 
     } 
    } 

    public class FileManager 
    { 
     private final Configuration configuration; 

     public FileManager(Configuration configuration) 
     { 
      this.configuration = configuration; 
     } 

     public Configuration getConfiguration() 
     { 
      return configuration; 
     } 
    } 

    public class Configuration 
    { 
     private final String text; 

     public Configuration(String text) 
     { 
      this.text = text; 
     } 

     public String getText() 
     { 
      return text; 
     } 
    } 
} 
+0

幹得好。就個人而言,我會讓Plugin成爲一個界面(更容易模擬等),併爲需要它的人提供了一個基本的AbstractPlugin,但這不僅僅是一種品味問題。 –