避免重复的代码块

Avoiding duplicate code blocks

我的代码中有这样的东西:

        switch (item.getItemId()) {
            case R.id.search:
                if (currentFragment == null || !(currentFragment instanceof ClipsFragment)) {
                    ClipsFragment clipsFragment = new ClipsFragment();
                    fragmentTransaction.replace(R.id.container,
                            clipsFragment).commit();
                    currentFragment = clipsFragment;
                } else {
                    fragmentTransaction.replace(R.id.container,
                            currentFragment).commit();
                }
                currentDrawerItem = R.id.search;
                return true;
            case R.id.download_managers:
                if (currentFragment == null || !(currentFragment instanceof DownloadFragment)) {
                    DownloadFragment downloadFragment = new DownloadFragment();
                    fragmentTransaction.replace(R.id.container,
                            downloadFragment).commit();
                    currentFragment = downloadFragment;
                } else {
                    fragmentTransaction.replace(R.id.container,
                            currentFragment).commit();
                }
                currentDrawerItem = R.id.search;
                return true;

            default:
                return false;
        }

如您所见,有两个相似的 switch case。
有什么方法可以将它们转换为使用 Java 7 的方法?
我尝试了一下,但 instanceof 很棘手。
None 我的尝试值得在这里发布。

注意:FragmentDownloadFragment 扩展 Fragment

They both extend Fragment

好吧,那么除了创建实例之外,您确实需要使用特定的子类。只需将当前 Fragment 声明为那些新实例即可。

这个清洁剂适合你吗?

boolean handled = true;
switch (item.getItemId()) {
    case R.id.search:
        if (currentFragment == null || !(currentFragment instanceof ClipsFragment)) {
            currentFragment = new ClipsFragment();
        }
        break;
    case R.id.download_managers:
        if (currentFragment == null || !(currentFragment instanceof DownloadFragment)) {
            currentFragment = new DownloadFragment();
        }
        break;
    default:
        handled = false;
}

if (currentFragment != null) {
    fragmentTransaction.replace(R.id.container,
            currentFragment).commit();
}
if (handled) {
    currentDrawerItem = item.getItemId();
}

return handled;

As you can see there are two similar switch cases. Any way I could convert them to a method using Java 7? I tried a bit but the instanceof is tricky.

为了避免 switch case 并用直接方法调用替换它们,您可以使用 object 和多态性。 在您的情况下,您可以引入一个带有方法的接口:

public interface  Processing{
    Fragment doProcess();
}

您可以有两种实现方式(根据代码中的项目 ID):

  • DownloadManagerProcessing
  • ReadProcessing

然后,您可以使用工厂 returns 方便的 Processing 实例 :

public ProcessingFactory{
  ..
  Map<Integer, Processing> processingByItemId;
  ..
  public Processing getProcessing(int itemId){
     return processingByItemId.get(itemId);
   }
..
}

你切换大小写:

 switch (item.getItemId()) {
            case R.id.search:
             ... 
            case R.id.download_managers:
            ...
            default:
            return false;
  }

将替换为:

Processing processing = ProcessingFactory.getProcessing(itemId);
if (processing==null){
   return false;
}
Fragment fragment = processing.doProcess();
return true;

在此解决方案中,我们始终依赖 itemId,但将它们与处理相关联的工作是独立的。
因此,如果需要,您可以在依赖 itemId 的工厂中添加其他类型的处理,而无需担心其映射。


编辑(从干净的代码开始实施)

通过像 cricket_007 那样从没有强重复的代码开始,您可以再次使用方法来避免 switch case。 在此版本中,您可以使用工厂来检索 ItemId 的匹配实例:

public FragmentFactory{
  ..

  ..
  public Fragment createInstanceIfNeeded(Fragment currentFragment, int itemId){


     if(itemId ==...){
        if (!(currentFragment instanceof ClipsFragment)) {
          return new ClipsFragment();
       }
     }
     else if(itemId == ..){
         if (!(currentFragment instanceof DownloadFragment)) {
          return new DownloadFragment();
       }
     }
     return currentFragment;
   }
..
}

您的情况需要 instanceof,因为您希望更改实现,如果它不是您期望的那样。如果你想避免它,你应该在 Fragment 中有一个 public 方法 getType() 其中 returns 一个 String 或一个 Enum 并且将由每个 children class. 但在某种程度上,它有点像 instanceof

在您的客户端代码中,您可以这样做:

currentFragment = FragmentFactory.createInstanceIfNeeded(item.getItemId());

if (currentFragment==null){
   return false;
}

fragmentTransaction.replace(R.id.container,
            currentFragment).commit();
currentDrawerItem = item.getItemId();

return true;

就我个人而言,我不喜欢使用 switch case。我找到了 error-prone.