【问题标题】:Connector design pattern?连接器设计模式?
【发布时间】:2015-12-27 17:37:40
【问题描述】:

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

假设我正在编写一个应用程序,您可以在其中滑动以绘制图表。应用中有很多类是相关的,应该相互关联。

例如三个类是:

Swiper - 负责解释用户的手势

Points - 负责处理图表上的点

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;
    }
}

这是处理用户手势的 My 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 课程,因为我不确定架构。

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

【问题讨论】:

  • 不要道歉,只是编辑问题以便回答
  • @AdamSkywalker 我该如何编辑?我想我很清楚......
  • 写一些代码和你对这个连接器的期望
  • 添加了一些代码和我的期望。希望它很好...... @AdamSkywalker
  • 我认为最适合您的情况的模式是观察者

标签: android oop design-patterns


【解决方案1】:

Chain of Responsibility 可能是您正在寻找的。

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

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

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

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

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

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

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

【讨论】:

  • 感谢您的回复。我会检查这些模式
【解决方案2】:

您真正需要的是 MVC 风格的架构。您的应用程序应该(广义上)分为 3 个不同的区域:

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

  • 视图,负责显示模型。一个模型可能会以不同的方式显示 - 在这种情况下,您会得到一个模型和几个不同的视图。

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

重要的是这三组组件松散耦合,并且职责明确分离。这三者都应该通过定义明确的接口进行通信(可能使用观察者、命令和链式责任模式)。特别是,模型类不应直接了解任何视图或控制器类。

所以,您可能有一些这样的模型/视图类...

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,
        }
    }
}

那么您可能有多个不同的 View 类实现,使用 ChartListener 接口。

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

【讨论】:

  • 谢谢,我会检查一下。
猜你喜欢
  • 2015-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-17
  • 2012-05-25
  • 2013-07-18
  • 1970-01-01
相关资源
最近更新 更多