Java 8 java阻止了大量的if,并用设计模式取代它

Java 8 java阻止了大量的if,并用设计模式取代它,java-8,Java 8,我在我的应用程序中使用了这段代码,我发现它非常难看。 有没有聪明的方法 for (final ApplicationCategories applicationCategorie : applicationCategories) { if (applicationCategorie == ApplicationCategories.PROJECTS) { // invoke right method } else if (a

我在我的应用程序中使用了这段代码,我发现它非常难看。 有没有聪明的方法

for (final ApplicationCategories applicationCategorie : applicationCategories) {
          if (applicationCategorie == ApplicationCategories.PROJECTS) {
              // invoke right method
            } else if (applicationCategorie == ApplicationCategories.CALENDAR) {
              // ...
            } else if (applicationCategorie == ApplicationCategories.COMMUNICATION) {

            } else if (applicationCategorie == ApplicationCategories.CONTACTS) {

            } else if (applicationCategorie == ApplicationCategories.DOCUMENTS) {

            } else if (applicationCategorie == ApplicationCategories.WORKINGBOOK) {

            }
        }

我的目标是处理包含在枚举列表中的所有应用程序类别枚举。

您至少可以在
应用程序类别
中声明处理依赖于
枚举的行为的方法。这样,如果要向枚举添加新值,则只需更改相对于枚举的代码即可

通过这种方式,您的代码遵循开闭原则,因此更易于维护

enum ApplicationCategories {
    PROJECTS,
    CALENDAR,
    // And so on...
    WORKINGBOOK;

    public static void handle(ApplicationCategories category) {
        switch (category) {
            case PROJECTS:
                // Code to handle projects
                break;
            case CALENDAR:
                // Code to handle calendar
                break;
            // And so on
        }
    }
}
仅当您不需要任何外部信息来处理枚举值时,此解决方案才可行

请记住,您还可以向枚举值添加字段

编辑

如果需要,还可以实现策略设计模式。首先,定义一个策略接口和一些具体的实现

interface CategoryStrategy {
    void handle(/* Some useful input*/);
}
class ProjectStrategy implements Strategy {
    public void handle(/* Some useful input*/) {
        // Do something related to projects...
    }
}
class CalendarStrategy implements Strategy {
    public void handle(/* Some useful input*/) {
        // Do something related to calendars...
    }
}
//...
然后,您可以修改枚举以使用上述策略

enum ApplicationCategories {
    PROJECTS(new ProjectStrategy()),
    CALENDAR(new CalendarStrategy()),
    // And so on...
    WORKINGBOOK(new WorkingBookStrategy());

    private CategoryStrategy strategy;
    ApplicationCategories(CategoryStrategy strategy) {
        this.strategy = strategy;
    }

    public static void handle(ApplicationCategories category) {
        category.strategy.handle(/* Some inputs */);
    }
}

显然,上面的代码只是一个草图。

您需要的设计模式是

枚举和违反打开/关闭原则 当必须对每个定义的值执行不同的操作时,使用枚举是一种不好的做法。随着软件的发展,很可能您必须在不同的地方传播if链。如果添加新的枚举值,则必须在所有这些位置为该值添加新的If。由于您甚至可能无法找到所有必须包含新if的地方,这是bug的来源

这种做法也违反了法律仅仅创建一个方法来处理每个枚举值并不能使代码符合OCP。这将使代码更有条理,但不会改变关于“如果”问题的任何内容

具有策略模式的Java7解决方案 使用Java 7或更早版本,您可以定义所有类别都将实现的ApplicationCategory接口。该接口将提供每个类别将实现的通用方法,以执行该类别所需的操作:

public interface ApplicationCategory {
     boolean handle();
}
通常你的方法应该返回一些东西。因为我不知道你的确切目标是什么,所以我要让这个方法只返回一个布尔值。例如,它将指示是否处理了该类别

然后,您必须为每个类别定义一个实现此类接口的类。例如:

public class CalendarCategory implements ApplicationCategory {
     boolean handle(){
         //the code to handle the Calendar category
         return true;
     }
}

public class CommunicationCategory implements ApplicationCategory {
     boolean handle(){
         //the code to handle the Communication category
         return true;
     }
}
现在您不需要enum类,而需要将其中的handle方法移到其他位置,这完全取决于您的项目。该
句柄
方法将更改为:

public static void handle(ApplicationCategory category) {
    //Insert here any code that may be executed,
    //regardless of what category it is.
    category.handle();
}
您不再需要枚举,因为任何声明为
ApplicationCategory
的变量都只接受实现此类接口的对象如果将枚举与策略实施一起使用,则在添加新的
ApplicationCategory
实施时,仍然需要更改枚举类,从而再次违反OCP

如果使用策略模式,在本例中甚至不需要枚举

具有函数式编程和策略模式的Java 8解决方案 您可以使用函数式编程和lambda表达式更容易地实现策略模式,并避免类的扩散,仅为了提供单个方法的不同实现(本例中的
handle
方法)

由于
handle
方法没有接收任何参数,并且正在重新调整某些内容,因此此描述符合功能接口。确定定义的方法符合哪种功能接口的一个很好的方法是研究包

一旦确定了功能接口的类型,我们就可以以功能的方式创建一个
ApplicationCategory
类(在Java 7示例中是一个接口),将前面的
handle
方法定义为
Supplier
类型的属性。必须为此句柄属性定义一个setter,才能更改句柄实现。将一个方法定义为一个属性,就可以在运行时更改这样一个方法实现,从而提供一个不同但更简单、更容易和更易于维护的策略模式实现

如果需要在某个地方使用类别名称,例如在用户界面中显示类别名称,可以在
ApplicationCategory
类中定义枚举。但是,枚举值与提供的
句柄
之间没有直接关系。枚举的作用与类别的标记相同。它就像
Person
类中的“name”属性,我们通常只使用它来“标记”和打印一个人

public class ApplicationCategory {
     //insert all categories here
     enum Type {CALENDAR, COMMUNNICATION} 

     /**
      * The Supplier object that will handle this category object.
      * It will supply (return) a boolean to indicate if the category
      * was processed or not.
     */
     private Supplier<Boolean> handler;

     private Type type;

     /**
     * A constructor that will receive a Supplier defining how to 
     * handle the category that is being created.
     */
     public ApplicationCategory(Type type, Supplier<Boolean> handler){
         Objects.requireNonNull(type);
         this.handler = handler;
         setType(type);
     } 

     /**
     * Handle the category by calling the {@link Supplier#get()} method,
     * that in turn returns a boolean.
     */
     public boolean handle(){
         return supplier.get();
     }

     public Type getType(){ return type; }

     public final void setHandler(Supplier<Boolean> handler){
        Objects.requiredNonNull(handler);
        this.handler = handler;
     }
}
this::calendarHandler
指令是向
calendarHandler
方法传递“指针”的指令。它不是调用方法(您可以看到,由于使用了::而不是.以及缺少括号),它只是定义调用
handle()
方法时实际上必须调用的方法,如
System.out.println(“Was”+cat+“handled?”+cat.handle())中所示


通过使用这种方法,可以为同一类别的不同实例定义不同的处理程序,或者为类别的子集使用相同的处理程序。

与其他语言不同,Java提供了专门允许以安全的面向对象方式完成这类工作的工具

在枚举上声明一个抽象方法,然后为每个枚举常量声明特定的实现。然后,编译器将确保每个常量都有一个实现,并且在添加新值时,没有人需要担心在某个地方丢失一个实例:

enum ApplicationCategories {
    PROJECTS {
       void handle() {
           ...
       }
    },
    ...

    public abstract void handle();
}

然后,不要调用一些静态的
句柄(category)
,只需调用
category.handle()

试试开关case,您可以在Java中向枚举添加方法。然后,尝试添加到
enum ApplicationCategories {
    PROJECTS {
       void handle() {
           ...
       }
    },
    ...

    public abstract void handle();
}