2013-02-18 91 views
1

一些调试后重构代码,我发现下面的东西在现有生产代码:静态听众

public class SomeTTS { 
    private static TTSSpeechListener mSpeechListener; 
    private static TTSBreakListener mBreakListener; 
    // more static (!!!) listeners 
    private String mPath; 

    public TTS(String path, TTSSpeechListener speechListener) 
      throws RuntimeException { 
     // ... 
     mSpeechListener = speechListener; 
     mBreakListener = null; 
     // more listeners set to null 
     // ... 
    } 
    // called from NATIVE code that I cannot change 
    private static void onReceiveSpeechData(byte[] samples) { 
     mSpeechListener.onSpeechData(samples); 
    } 
    // ... 
} 

课堂是一个机库(的Android,NDK,JNI)的包装。我无法访问本地库源。 (当然,你看到了这个问题:在我创建了SomeTTS的第二个实例之后,第一个实例不再工作了。)我有点震惊:除了一个男生,我不会期望这样的错误。可能他们正在使用童工。或者更有可能的是,有人无法向他的经理解释演示和生产代码之间的区别。

无论如何,我必须让它工作。我有一些想法,但我现在可以提出的建议远非完美。任何想法如何重构它?

回答

0

这就是我所做的:我将课程分开,并将其封装在提供合理API的课程中。

由于它是TTS,并且让TTS一次只发出一个请求是合理的,所以我使用了一个静态指针指向当前的SomeTTS实例,并使调用同步。我无法修复SomeTTS类,但我可以确保我的方法调用是正确的 - 顺便说一下,我不会调用某些方法。

public class SomeTTS { 
    private TTSSpeechListener mSpeechListener; 
    // ... more listeners, NOT static ... 

    private static volatile SomeTTS currentTTS; 
    protected static Object currentTtsAccessLock = new Object(); 

    public static TTSSpeechListener currentSpeechListener() { 
     synchronized (currentTtsAccessLock) { 
      return currentTTS == null ? null : currentTTS.mSpeechListener; 
     } 
    } 
    public static void setCurrentTTS(SomeTTS tts) { 
     synchronized (currentTtsAccessLock) { 
      currentTTS = tts; 
     } 
    } 

    // called from NATIVE code that I cannot change 
    private static void onReceiveSpeechData(byte[] samples) { 
     TTSSpeechListener speechListener = currentSpeechListener(); 
     if (speechListener != null) { 
      speechListener.onSpeechData(samples); 
     } else { 
      // Just no better idea. But this should never happen. 
      Log.e("SomeTTS","ERROR: speechListener == null samples: "+samples.length); 
     } 
    } 

    // ... 
} 

这就是这一类。仍然有可能对其方法进行不正确的调用;该纪律是使用MyTTSEngine来代替。该课程MyTTSEngine提供了一个合理的API; SomeTTS没有。

class MyTTSEngine { 
    private SomeTTS mTTS; 
    private Object upperLevelTtsLock = new Object(); 

    // ... 

    public void say(String text) { 
     // ... 
     synchronized (upperLevelTtsLock) { 
      TTS.setCurrentTTS(mTTS); 
      try { 
       mTTS.clearAbortState(); 
       mTTS.synthesizeFromString(text); 
      } finally { 
       TTS.setCurrentTTS(null); 
      } 
     } 
     // ... 
    } 
}