连接器设计模式?

时间:2015-12-27 17:37:40

标签: android oop design-patterns

我想连接几个单独运行但相关的类。

让我们说我正在编写一个应用程序,您可以在其中滑动以绘制图表。应用程序中有很多类是相关的,应该连接起来。

例如,其中三个类是:

Swiper - 负责解释用户的手势

积分 - 负责处理图表上的积分

ChartDrawer - 负责在屏幕上绘制图表

我想知道是否有任何设计模式,如连接器,可以处理这些类的关系和通信?我可以用更好的方式重新设计或让头脑更加面向对象吗?

这是我的ChartDraw类,它扩展了一个视图:

public class ChartDraw extends View implements GestureReceiver {
    int chartYPosition;
    private int circleColor;
    private int circleRadius;
    int height;
    private float lastPointOnChart;
    private int lineColor;
    private int lineWidth;
    private Paint paint;
    private float tempPoint;
    int width;

    public ChartDraw(Context context) {
        super(context);
        init();
    }

    public ChartDraw(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ChartDraw(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        this.lineWidth = 15;
        this.circleRadius = 20;
        this.lineColor = Color.parseColor("#1976D2");
        this.circleColor = Color.parseColor("#536DFE");
        this.lastPointOnChart = 0.0f;
        this.tempPoint = 0.0f;
        this.paint = new Paint();
        this.height = getHeight();
        this.width = getWidth();
        this.chartYPosition = this.height / 2;
    }

    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        this.chartYPosition = canvas.getHeight() / 2;
        this.paint.setStrokeWidth((float) this.lineWidth);
        this.paint.setColor(this.lineColor);
        canvas.drawLine(0.0f, (float) this.chartYPosition, this.tempPoint, (float) this.chartYPosition, this.paint);
        if (this.tempPoint > 20.0f) {
            this.paint.setColor(this.circleColor);
            canvas.drawCircle(20.0f, (float) this.chartYPosition, 20.0f, this.paint);
            drawTriangle(canvas, this.paint, this.tempPoint, this.chartYPosition);
        }
    }

    private void drawTriangle(Canvas canvas, Paint paint, float startX, int startY) {
        Path path = new Path();
        path.moveTo(startX, (float) (startY - 20));
        path.lineTo(startX, (float) (startY + 20));
        path.lineTo(30.0f + startX, (float) startY);
        path.lineTo(startX, (float) (startY - 20));
        path.close();
        canvas.drawPath(path, paint);
    }

    public void onMoveHorizontal(float dx) {
        this.tempPoint = this.lastPointOnChart + dx;
        invalidate();
    }

    public void onMoveVertical(float dy) {
    }

    public void onMovementStop() {
        this.lastPointOnChart = this.tempPoint;
    }
}

这是我的SwipeManager,正在处理用户手势:

public class SwipeManager implements View.OnTouchListener {
    GestureReceiver receiver;
    private int activePointer;

    private float initX,
            initY;
    private long startTime,
            stopTime;

    private boolean resolving = false;
    private boolean resolved = false;

    private Direction direction;

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if (receiver == null) throw new AssertionError("You must register a receiver");
        switch (motionEvent.getActionMasked()) {
            case ACTION_DOWN:
                activePointer = motionEvent.getPointerId(0);

                initX = motionEvent.getX(activePointer);
                initY = motionEvent.getY(activePointer);

                startTime = new Date().getTime();
                break;

            case ACTION_MOVE:
                if (!resolving && !resolved) {
                    resolving = true;
                    float x = motionEvent.getX(activePointer);
                    float y = motionEvent.getY(activePointer);
                    direction = resolveDirection(x, y);
                    if (direction != Direction.STILL) {
                        resolved = true;
                        resolving = false;
                    } else {
                        resolving = false;
                        resolved = false;
                    }
                    break;
                }

                if (resolved) {
                    if (direction == Direction.HORIZONTAL)
                        receiver.onMoveHorizontal(motionEvent.getX(activePointer) - initX);
                    else receiver.onMoveVertical(motionEvent.getX(activePointer) - initY);
                }
                break;

            case ACTION_UP:
                resolved = false;
                receiver.onMovementStop();
                break;
        }
        return true;
    }

    private Direction resolveDirection(float x, float y) {
        float dx = x - initX;
        float dy = y - initY;
        float absDx = Math.abs(dx);
        float absDy = Math.abs(dy);
        if (absDx > absDy + 10) {
            return Direction.HORIZONTAL;
        } else if (absDy > absDx + 10) {
            return Direction.VERTICAL;
        }
        return Direction.STILL;
    }

    public void setReceiver(GestureReceiver receiver) {
        this.receiver = receiver;
    }

    private enum Direction {HORIZONTAL, VERTICAL, STILL;}
}

我没有启动Points类,因为我不确定架构。

我希望此连接器注册类的所有侦听器并等待更改并通知相应的更改类,例如添加新点或滑动已启动和已完成或应用程序中的任何其他事件。

2 个答案:

答案 0 :(得分:2)

Chain of Responsibility可能就是你要找的东西。

这是一种将一系列“处理对象”绑定在可以处理“命令对象”的“链”中的模式。

我可以看到你制作了封装触摸事件的命令对象,然后通过几个处理器传递,最后由处理该特定“命令对象”的输入检测/输出生成的“处理对象”进行“处理”。 / p>

我不知道这是否是-ideal-,但它可能是有效的。

要研究的其他相关模式可能是:

https://en.wikipedia.org/wiki/Command_pattern

https://en.wikipedia.org/wiki/Observer_pattern

https://en.wikipedia.org/wiki/Bridge_pattern

答案 1 :(得分:1)

你真正想要的是一个MVC风格的架构。您的申请应该(广义上说)分为3个不同的领域:

  • 模型,与您的演示或沟通问题完全脱节。它提供了一个用于交互的API,可以使用简单的框架(如JUnit)完全独立地进行测试。

  • View,负责显示Model。可能是模型可以以不同的方式显示 - 在这种情况下,您可以获得单个模型和几个不同的视图。

  • 控制器,负责响应用户(或其他)输入对模型进行更改。

重要的是,这三组组件松散耦合,责任明确分开。所有这三个都应该通过定义良好的接口进行通信(可能使用Observer,Command和ChainOfResponsibility模式)。特别是,Model类不应该直接了解任何View或Controller类。

所以,你可能会有像这样的模型/视图类......

public interface ChartListener {
    void notifyUpdate();
}

public interface Chart {
    void newPoint(Point p);

    Collection<Point> thePoints();

    void addListener(ChartListener listener);
}

public class ChartModel implements Chart {
    private final Collection<Point> points;
    private final Collection<ChartListener> listeners;

    public Collection<Point> thePoints() {
        return Collections.unmodifiableCollection(points);
    }

    public void newPoint(Point p) {
        thePoints.add(p);
        listeners.stream().forEach(ChartListener::notifyUpdate);
    }

    public void addListener(ChartListener cl) {
        listeners.append(cl);
    }
}

public PieChartViewer implements ChartListener {
    // All you colour management or appearance-related concerns is in this class.
    private final Chart chart;

    public PieChartView(Chart chart) {
        this.chart = chart;
        // set up all the visuals...
    }

    public void notifyUpdate() {
        for (final Point p:chart.thePoints()) {
            // draw a point somehow, lines, dots, etc,
        }
    }
}

然后,您可以使用ChartListener界面,对View类进行多种不同的实现。

您的Swipe类看起来像一个Controller类,它将采用ChartModel实现,然后根据用户的一些输入进行修改。