You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将switch语句重构为多态实现?附代码优化建议

Refactoring for Open/Closed Principle & Clean Code

Great catch on the Open/Closed Principle violation here—this switch statement is definitely going to become a maintenance headache as more links get added. Let's break down how to refactor this with polymorphism, plus some other clean code tweaks to make this more maintainable.

1. Polymorphic Solution with Strategy Pattern

The strategy pattern is perfect here: we'll encapsulate each link's behavior into its own class, then use a lookup map to retrieve the right behavior without modifying the original method.

Step 1: Define the Strategy Interface

First, create an interface that represents the action for a hyperlink:

public interface HyperlinkAction {
    void execute(LoginPage loginPage);
}

Step 2: Implement Concrete Strategies

Create a class for each link type—this is where you'll put the specific behavior:

public class CookieLinkAction implements HyperlinkAction {
    @Override
    public void execute(LoginPage loginPage) {
        loginPage.openCookieInformationPage();
        loginPage.switchToNewestTab();
    }
}

public class PrivacyPolicyLinkAction implements HyperlinkAction {
    @Override
    public void execute(LoginPage loginPage) {
        loginPage.openPrivacyPolicyInformationPage();
        loginPage.switchToNewestTab();
    }
}

// Add more as new links are required

Step 3: Use a Lookup Map to Replace the Switch

Modify your Cucumber step to use a map that links the link text to its corresponding action. You can initialize this map once (e.g., in a constructor or setup method):

private final Map<String, HyperlinkAction> linkActions = Map.of(
    "cookie", new CookieLinkAction(),
    "privacy policy", new PrivacyPolicyLinkAction(),
    "report a problem", new ReportAProblemLinkAction()
);

@When("^they click the (.*) hyperlink$") 
public void the_browser_opens_a_new_hyperlink(String link) {
    HyperlinkAction action = linkActions.get(link.toLowerCase());
    if (action == null) {
        throw new IllegalArgumentException("Unsupported link: " + link);
    }
    Runnable asyncTask = () -> action.execute(loginPage);
    driverTabHelper.execAsyncTaskThatLaunchesATab(asyncTask);
}

Now, adding a new link only requires creating a new HyperlinkAction implementation and adding it to the map—no changes to the step definition method needed!

2. Compact Alternative: Enum-Based Polymorphism

If you prefer a more concise approach (without creating many small classes), an enum can work just as well. Enums can implement interfaces, so we can encapsulate behavior directly in each enum value:

public enum Hyperlink implements HyperlinkAction {
    COOKIE("cookie") {
        @Override
        public void execute(LoginPage loginPage) {
            loginPage.openCookieInformationPage();
            loginPage.switchToNewestTab();
        }
    },
    PRIVACY_POLICY("privacy policy") {
        @Override
        public void execute(LoginPage loginPage) {
            loginPage.openPrivacyPolicyInformationPage();
            loginPage.switchToNewestTab();
        }
    },
    REPORT_A_PROBLEM("report a problem") {
        @Override
        public void execute(LoginPage loginPage) {
            loginPage.openReportAProblemPage();
            loginPage.switchToNewestTab();
        }
    };

    private final String displayText;

    Hyperlink(String displayText) {
        this.displayText = displayText;
    }

    // Helper method to find the enum by link text
    public static Hyperlink fromText(String text) {
        return Arrays.stream(values())
            .filter(link -> link.displayText.equalsIgnoreCase(text))
            .findFirst()
            .orElseThrow(() -> new IllegalArgumentException("Unsupported link: " + text));
    }
}

Then update your step definition:

@When("^they click the (.*) hyperlink$") 
public void the_browser_opens_a_new_hyperlink(String link) {
    Hyperlink hyperlink = Hyperlink.fromText(link);
    Runnable asyncTask = () -> hyperlink.execute(loginPage);
    driverTabHelper.execAsyncTaskThatLaunchesATab(asyncTask);
}

This keeps all link behavior in one place, and adding a new link just means adding a new enum value.

3. Additional Clean Code Optimizations

Beyond the OCP fix, here are a few more tweaks to improve this code:

  • Improve Cucumber Regex: The (.*) pattern is too broad and can cause unexpected matches. Use a quoted capture group to handle links with spaces more reliably:

    @When("they click the \"([^\"]*)\" hyperlink")
    

    This ensures the step only matches text wrapped in quotes, which is more explicit for Cucumber scenarios.

  • Extract Duplicate Code: Notice that every action calls switchToNewestTab()—we can move this to a common place to avoid repetition. For example, modify the HyperlinkAction interface to have a default method:

    public interface HyperlinkAction {
        void openPage(LoginPage loginPage);
    
        default void execute(LoginPage loginPage) {
            openPage(loginPage);
            loginPage.switchToNewestTab();
        }
    }
    

    Then each concrete implementation only needs to implement openPage(), reducing boilerplate.

  • Strengthen Error Handling: Instead of relying on Objects.requireNonNull, throw a specific exception with context (like we did in the examples above) to make debugging easier.

  • Dependency Injection: If you're using a framework like Spring or Cucumber's dependency injection, you can inject all HyperlinkAction implementations into the map automatically, instead of manually initializing it. This makes adding new actions even more seamless.


内容的提问来源于stack exchange,提问作者symon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:31:10