我有一个包含许多switch语句的类。代码对我来说看起来很难看,但我无法弄清楚如何修复它。如果有人可以提出一个设计模式或一个清理它的技巧,这将是伟大的。下面是Class的缩写版本,带有一些上下文注释。
/**
* Slides a desktop Notification from the edge of the screen into the desktop by some margin.
*/
public class SlideManager extends NotificationManager {
// Location enum provided below for reference:
/*public enum Location {
NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, NORTHWEST
}*/
private Location m_loc; // the corner / edge of the screen where the Notification should appear
// A Screen abstracts away the padding logic.
// The idea was that you would just give it a padding and I could reuse
// it later in all my NotificationManagers to give me the x and y for a Notification Location later.
private Screen m_standardScreen;
private Screen m_noPaddingScreen;
// the direction that the Notification should slide in from.
// For instance, if we had our Notification show up on the center east side of the screen,
// it should slide in from the edge towards the west until it was a suitable margin away from the edge of the screen.
private SlideDirection m_direction;
private double m_slideSpeed;
// this is a flag to signal when the user has overridden the default SlideDirection calculation.
// If the user constructs the SlideManager without calling setSlideDirection later,
// this will be false. However, if the user does setSlideDirection
// we want to avoid changing that automatically if the user later calls setLocation.
private boolean m_overwrite;
public enum SlideDirection {
NORTH, SOUTH, EAST, WEST
}
{
m_standardScreen = Screen.standard();
m_noPaddingScreen = Screen.withPadding(0);
m_slideSpeed = 300;
m_overwrite = false;
}
public SlideManager() {
m_loc = Location.NORTHEAST;
recalculateSlideDirection();
}
public SlideManager(Location loc) {
m_loc = loc;
recalculateSlideDirection();
}
/**
* Sets the location where the Notifications show up.
* If the user has not explicitly given a SlideDirection, this will also recalculate the SlideDirection.
* For example, if the user moves the Notification spawn location from East to West
* we want to change the SlideDirection from West to East, respectively.
*
* @param loc
*/
public void setLocation(Location loc) {
m_loc = loc;
if (!m_overwrite)
recalculateSlideDirection();
}
/**
* Sets the direction that the Notification should slide in from.
*
* @param slide
*/
public void setSlideDirection(SlideDirection slide) {
m_direction = slide;
m_overwrite = true;
}
private void recalculateSlideDirection() {
switch (m_loc) {
// The tricky part is when the user wants the Notification to appear in a corner of the screen.
// If this weren't the case, it would make no sense for a user to set
// his own SlideDirection because the SlideDirection for Location.
// EAST would always be West, Location.NORTH would always be SOUTH, etc.
// But for the (literal) corner cases I want to somehow give a way for the user to have a preference.
// For example, in the top right corner the Notification could either slide in from the right or from the top.
// By default I choose the top, but I want the user to be able to change this and also have that choice remembered if the Location changes.
case NORTHWEST:
m_direction = SlideDirection.SOUTH;
break;
case NORTH:
m_direction = SlideDirection.SOUTH;
break;
case NORTHEAST:
m_direction = SlideDirection.SOUTH;
break;
case EAST:
m_direction = SlideDirection.WEST;
break;
case SOUTHEAST:
m_direction = SlideDirection.NORTH;
break;
case SOUTH:
m_direction = SlideDirection.NORTH;
break;
case SOUTHWEST:
m_direction = SlideDirection.NORTH;
break;
case WEST:
m_direction = SlideDirection.EAST;
break;
}
}
/*
When a Notification is added it should slide in from the edge towards an area slightly off the edge.
*/
@Override
protected void notificationAdded(Notification note, Time time) {
int noPaddingX = m_noPaddingScreen.getX(m_loc, note);
int noPaddingY = m_noPaddingScreen.getY(m_loc, note);
int standardX = m_standardScreen.getX(m_loc, note);
int standardY = m_standardScreen.getY(m_loc, note);
Slider slider = null;
double frequency = 50;
double slideDelta = m_slideSpeed / frequency;
// How would I abstract this?
switch (m_direction) {
case NORTH: {
note.setLocation(standardX, noPaddingY);
slider = new Slider(note, m_direction, 0, -slideDelta, standardX, standardY);
}
break;
case SOUTH: {
note.setLocation(standardX, noPaddingY);
slider = new Slider(note, m_direction, 0, slideDelta, standardX, standardY);
}
break;
case EAST: {
note.setLocation(noPaddingX, standardY);
slider = new Slider(note, m_direction, slideDelta, 0, standardX, standardY);
}
break;
case WEST:
note.setLocation(noPaddingX, standardY);
slider = new Slider(note, m_direction, -slideDelta, 0, standardX, standardY);
break;
}
Timer timer = new Timer((int) frequency, slider);
timer.start();
note.show();
}
/*Slides a Notification from its current location to a desired location with fixed deltaX's and deltaY's. It needs the SlideDirection to know which end values to check for stopping.*/
public class Slider implements ActionListener {
private Notification m_note;
private SlideDirection m_dir;
private double m_deltaX;
private double m_deltaY;
private double m_stopX;
private double m_stopY;
private double m_x;
private double m_y;
public Slider(Notification note, SlideDirection dir, double deltaX, double deltaY, double stopX, double stopY) {
m_note = note;
m_dir = dir;
m_deltaX = deltaX;
m_deltaY = deltaY;
m_stopX = stopX;
m_stopY = stopY;
m_x = note.getX();
m_y = note.getY();
}
@Override
public void actionPerformed(ActionEvent e) {
m_x += m_deltaX;
m_y += m_deltaY;
// another ugly heap of conditionals. Is there a way to abstract away the stopping logic?
if (m_dir == SlideDirection.SOUTH) {
if (m_y >= m_stopY) {
m_y = m_stopY;
((Timer) e.getSource()).stop();
}
} else if (m_dir == SlideDirection.NORTH) {
if (m_y <= m_stopY) {
m_y = m_stopY;
((Timer) e.getSource()).stop();
}
} else if (m_dir == SlideDirection.EAST) {
if (m_x >= m_stopX) {
m_x = m_stopX;
((Timer) e.getSource()).stop();
}
} else if (m_dir == SlideDirection.WEST) {
if (m_x <= m_stopX) {
m_x = m_stopX;
((Timer) e.getSource()).stop();
}
}
m_note.setLocation((int) (m_x), (int) (m_y));
}
}
}
显然,拥有两个switch
和一个条件链意味着出了问题。我最初的想法是制作某种类型的SlideVector类,我可以给它一个SlideDirection,它会计算翻译并处理最终案例。这种方法的优点/缺点是什么?在这种情况下,HashMap是否有用?还有其他方法可以解决这个问题吗?
答案 0 :(得分:2)
查看策略模式。您可以将所有switch语句移动到不同的类中。你的类将有一个这个翻译类的实例,它有一个方法可以为你提供状态(所有信息),它会为你创建输出。
在recalculateSlideDirection中你可以使用fall through来保存在线上(虽然呃,它不会为你节省很多)。
notificationAdded的另一个选项是定义一个接口并创建一个hashmap,它将m_direction映射到该接口的实现。所以你基本上只有一个HashMap&lt; SlideDirection,IYourInterface&gt; yourMap ... 所以你基本上会调用yourMap.get(n_direction).action();这将取代你的switch语句。