Java图形时钟开发:对象间属性数据传递问题求助
解决Java图形化时钟的组件通信问题
嘿,我来帮你理一理这个问题~你现在的架构思路其实是挺合理的:用Drawer作为协调层,整合数据模型Clock和视图ClockPanel,这种分层的思想本身就很规范,不用怀疑架构的合理性,只是需要调整一下组件间的通信方式,让Drawer真正发挥它的协调作用。
核心问题分析
你之前考虑把Clock直接传入ClockPanel,确实会让Drawer的存在感变弱——因为这样视图层直接依赖了数据模型,Drawer就只是个简单的创建者,而不是协调者。我们要做的是让各模块职责单一:
Clock:只负责时间的存储和更新(数据层)ClockPanel:只负责根据给定的时间绘制时钟(视图层)Drawer:负责连接数据层和视图层,传递数据并触发更新(协调层)
具体解决方案
方案1:让Drawer作为中间传递者
这是最简单直接的方式,适合当前的场景:
给
ClockPanel添加时间设置方法
去掉ClockPanel对Clock的直接依赖,改成通过方法接收时间数据,然后自动触发重绘:public class ClockPanel extends JPanel { private int currentHour; private int currentMinute; private int currentSecond; // 你已有的其他变量(m_radiusWhiteCircle、m_centerX等) // 添加设置时间的方法 public void setCurrentTime(int hour, int minute, int second) { this.currentHour = hour; this.currentMinute = minute; this.currentSecond = second; repaint(); // 时间更新后自动触发重绘 } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // 你已有的静态元素绘制代码(背景、圆圈、刻度等) // 新增绘制指针的逻辑,使用currentHour、currentMinute、currentSecond drawHourHand(g); drawMinuteHand(g); drawSecondHand(g); } // 绘制时针 private void drawHourHand(Graphics g) { // 计算时针角度:30度/小时 + 0.5度/分钟(因为时针会随分钟移动),减去90度让0点指向顶部 double angle = (currentHour % 12) * 30 + currentMinute * 0.5 - 90; int handLength = m_radiusWhiteCircle / 2; int endX = (int) (m_centerX + handLength * Math.cos(Math.toRadians(angle))); int endY = (int) (m_centerY + handLength * Math.sin(Math.toRadians(angle))); g.setColor(Color.BLACK); g.setStroke(new BasicStroke(4)); g.drawLine(m_centerX, m_centerY, endX, endY); } // 绘制分针(类似逻辑) private void drawMinuteHand(Graphics g) { double angle = currentMinute * 6 - 90; // 6度/分钟 int handLength = m_radiusWhiteCircle * 3 / 4; int endX = (int) (m_centerX + handLength * Math.cos(Math.toRadians(angle))); int endY = (int) (m_centerY + handLength * Math.sin(Math.toRadians(angle))); g.setColor(Color.DARK_GRAY); g.setStroke(new BasicStroke(2)); g.drawLine(m_centerX, m_centerY, endX, endY); } // 绘制秒针(类似逻辑) private void drawSecondHand(Graphics g) { double angle = currentSecond * 6 - 90; // 6度/秒 int handLength = m_radiusWhiteCircle - 20; int endX = (int) (m_centerX + handLength * Math.cos(Math.toRadians(angle))); int endY = (int) (m_centerY + handLength * Math.sin(Math.toRadians(angle))); g.setColor(Color.RED); g.setStroke(new BasicStroke(1)); g.drawLine(m_centerX, m_centerY, endX, endY); } }修改
Drawer的initDraw方法
让Drawer持有Clock和ClockPanel的引用,定期从Clock获取时间,传递给ClockPanel:public void initDraw() { clockWindow = new JFrame(); // 你已有的窗口配置代码(标题、大小、位置等) clockPanel = new ClockPanel(); // 不再传入m_clock clockWindow.setContentPane(clockPanel); clockWindow.setVisible(true); // 注意:最好把setVisible放在最后,避免组件加载问题 // 启动定时任务,每秒更新一次时间 javax.swing.Timer timer = new javax.swing.Timer(1000, e -> { // 从Clock获取当前时间(假设Clock有getHour()、getMinute()、getSecond()方法) int hour = m_clock.getHour(); int minute = m_clock.getMinute(); int second = m_clock.getSecond(); // 传递给ClockPanel clockPanel.setCurrentTime(hour, minute, second); }); timer.start(); }
方案2:使用观察者模式(更优雅的解耦)
如果你的Clock需要主动通知视图时间变化(比如时间不是定时轮询,而是有外部触发更新),可以用观察者模式实现解耦:
让
Clock成为被观察者import java.util.Observable; public class Clock extends Observable { private int hour; private int minute; private int second; // 假设你有更新时间的方法,比如每秒自动更新 public void updateTime() { // 这里写更新hour、minute、second的逻辑(比如获取系统时间) // ... // 通知观察者时间已变化 setChanged(); notifyObservers(new TimeUpdate(hour, minute, second)); } // 内部类封装时间更新数据 public static class TimeUpdate { public final int hour; public final int minute; public final int second; public TimeUpdate(int hour, int minute, int second) { this.hour = hour; this.minute = minute; this.second = second; } } }让
Drawer成为观察者import java.util.Observer; import java.util.Observable; public class Drawer implements Observer { private Clock m_clock; private ClockPanel clockPanel; private JFrame clockWindow; public Drawer() { m_clock = new Clock(); m_clock.addObserver(this); // 注册为观察者 } @Override public void update(Observable o, Object arg) { if (arg instanceof Clock.TimeUpdate update) { // 把时间传递给ClockPanel clockPanel.setCurrentTime(update.hour, update.minute, update.second); } } public void initDraw() { // 你已有的窗口初始化代码 clockPanel = new ClockPanel(); clockWindow.setContentPane(clockPanel); clockWindow.setVisible(true); // 启动Clock的时间更新任务 javax.swing.Timer timer = new javax.swing.Timer(1000, e -> m_clock.updateTime()); timer.start(); } }
总结
你的架构思路完全没问题,Drawer作为协调层的定位很准确,只需要让它承担起数据传递和触发更新的职责,而不是让视图直接依赖数据模型。这样每个类都只做自己擅长的事,符合单一职责原则,后续维护和扩展都会更轻松。
内容的提问来源于stack exchange,提问作者Quentin
相关产品推荐
相关产品推荐

