我可以使用设计模式来解决这个问题吗?

时间:2011-07-16 10:57:07

标签: java design-patterns

我根据屏幕分辨率在各种GUI屏幕上添加了一个行间隔符。目前在各种GUI类中,调用一种方法,该方法返回屏幕分辨率并根据屏幕分辨率添加新的间隔。根据类类型,SpacerField的值可以更改。是否有一种设计模式可以用来重构代码,以便条件更少,更面向对象?

Class A:
            if(getScreenResolution() == 360){
                add(new SpacerField(15));   
            }

            if(getScreenResolution() == 460){
                add(new SpacerField(5));    
            }


Class B:
            if(getScreenResolution() == 360){
                add(new SpacerField(35));   
            }

            if(getScreenResolution() == 460){
                add(new SpacerField(15));   
            }

可能的解决方案 -

add(new SpacerUtils.getSpacerField(this));

public static SpacerUtils {
    static {
        int screenRes  = getScreenRes();
    }

    public static SpacerField getSpacerField(Object obj) {

        if(obj instanceof GuiScreen1 && screenRes == 360){
            return new SpacerField(25);
        }
        else  if(obj instanceof GuiScreen2 && screenRes == 360){
            return new SpacerField(35);
        }

    }
}

这样的东西? 对于每个可能的间隔值,我需要添加一个新的实现,在这种情况下我只有一个 - SpacerSmall。

Caller - 
                    Spacer spacer  = new SpacerSmall();

                    if(resolution == 360){
                    add(new SpacerField(0 , spacer.getSpacerValue()));  
                    }


Interface -                 
                    public interface Spacer {

        public int getSpacerValue();

    }

Implementation - 
    public class SpacerSmall implements Spacer{

        public int getSpacerValue() {
            return 15;
        }

    }

4 个答案:

答案 0 :(得分:2)

在您的第二个示例中,您正在应用delegation pattern。如果你需要的是将你的应用程序组合成模式集合,那么你就是正确的方式。但是如果你想让你的代码易于理解,那么最好将间隔宽度检测委托给A类和B类的对象。比如这样,例如:

public interface SpacerWidthResolver {
    public int getSpacerWidth(int resolution);
}

public class A implements SpacerWidthResolver {
    public int getSpacerWidth(int resolution) {
        int spacerWidth = -1;
        switch (resolution) {
            case 360: {
                spacerWidth = 15;
                break;
            }
            case 460: {
                spacerWidth = 5;
                break;
            }
            default: {
                spacerWidth = -1;
                break;
            }
        }
        return spacerWidth;
    }
}
public class B implements SpacerWidthResolver {
    public int getSpacerWidth(int resolution) {
        int spacerWidth = -1;
        switch (resolution) {
            case 360: {
                spacerWidth = 35;
                break;
            }
            case 460: {
                spacerWidth = 15;
                break;
            }
            default: {
                spacerWidth = -1;
                break;
            }
        }
        return spacerWidth;
    }
}

然后,在您的课程中稍后您将使用getScreenResolution方法:

public void DoSomething(SpacerWidthResolver component) {
    add(new SpacerField(component.getSpacerWidth(getScreenResolution())));
}

这可能不是最好的解决方案,但是在你的第一次和第二次尝试中建议的更好(就OO范式而言)。

编辑另请注意@eznme如何回答您的问题。他的想法可能更适合你的问题。

答案 1 :(得分:1)

如果你想要一些易于扩展的东西,比如用不同的值添加更多像A和B这样的类,你可以这样做:

    class Z {
            abstract int small();
            abstract int large();
            void doSomething() {
                    if(getScreenResolution() == 360){
                            add(new SpacerField(this.small()));   
                    }
                    if(getScreenResolution() == 460){
                            add(new SpacerField(this.large));    
                    }
            }
    }
    class A extends Z {
            int small() {
                    return 15;
            }
            int large() {
                    return 5;
            }
    }
    class B extends Z {
            int small() {
                    return 35;
            }
            int large() {
                    return 15;
            }
    }

答案 2 :(得分:1)

你只需要一个班级。类不应该在行为上而不是在数据上,你甚至不应该根据不同的数据创建两个不同的类。这带来了无用的阶级扩散。可以在构造函数中提供不同的配置。

public interface Spacer {

    public SpacerField getSpacer(int resolution);

}

public class MySpacer implements Spacer {

    private Map<Integer, Integer> spacerSize;

    public MySpacer(Map spacerSize<Integer, Integer>) {
        this.spacerSize = spacerSize;
    }

    public SpacerField getSpacer(int resolution) {
        Integer size = spacerSize.get(resolution);
        if (size == null) {
            throw new IllegalArgumentException("Invalid resolution: " 
                            + resolution);
        }
        return new SpacerField(size);
    }

}

这是配置,使用依赖注入框架创建这些实例并使用setter方法在必要时注入实例是一种很好的做法。

即使你不使用依赖注入框架,你现在可以自己做,并在将来进行迁移。方法如下:

public class AClassThatUseSpacer {

    private Spacer spacer;

    public void setSpacer(Spacer spacer) {
        this.spacer = spacer;
    }
}

当你使用它时:

AClassThaUseSpacer anInstance = new AClassThatUseSpacer();
Map<Integer, Integer> spacerSize = new HashMap<Integer, Integer>();
spacerSize.put(360, 15);
spacerSize.put(460, 5);
anInstance.setSpacer(new MySpacer(spacerSize));

答案 3 :(得分:0)

class A:
private static Map<Integer, Integer> spacerMap = new HashMap<Integer, Integer>() {{put(360, 15);put(460, 5);};};
...
add(new SpacerField(spacerMap.get(getScreenResolution())))

class B:
private static Map<Integer, Integer> spacerMap = new HashMap<Integer, Integer>() {{put(360, 35);put(460, 15);};};
...
add(new SpacerField(spacerMap.get(getScreenResolution())))