首页 > 解决方案 > 使用 Java Runnable 进行糟糕的类设计

问题描述

您能否解释一下为什么在以下程序中以这种方式实现 Runnable 接口是一个糟糕的设计决策?直观地说,如果我必须自己编写这个,我会让 Hotel 成为它自己的类,并在一个实现 Runnable 的新类中为 run() 编写规范。但是,我无法真正解释为什么下面的代码是一个糟糕的设计决定。

该课程模拟了一家酒店,里面有排队的人和房间列表。有几个“工作台”在不同的线程上运行,每个工作台负责从队列中移除人员并将他们签入可用的房间。为简单起见,不包括退房。方法的实现并不重要(相信它是线程安全的),这个问题是关于将 run() 放入 Hotel 类的设计决策。

public class Hotel implements Runnable {
    private final static int NR_ROOMS = 10;
    private final Person [] rooms = new Person [ NR_ROOMS ];
    private final List < Person > queue = new ArrayList < >();
    private final Lock queueLock = new ReentrantLock ();

    private boolean occupied (int i) {
        return ( rooms [i] != null);
    }

    private int checkIn ( Person p) {
        // add Person to a free room
    }


    private void enter ( Person p) {
        // add a person to the waiting queue
    }

    // every desk employee should run as a separate thread
    @Override
    public void run () {
        // remove guests from the queue and check them in
    }
}

标签: javamultithreadingthread-safetyrunnable

解决方案


OO 编程的重点是创建对业务逻辑建模的类;由于您的问题涉及酒店、房间、人员等,因此可以期望在您的问题域中存在代表这些“名词”的类。然后这些类上的方法表示对对象执行的操作。

run()对 Hotel 类的方法的直接问题是根本不清楚酒店“运行”的含义。我想在某些情况下这可能是有道理的;例如,如果你有一个模拟,并且有关于酒店随着时间推移应该发生的事情的规则。不自然的部分是酒店通常是发生事情的地方,而不是做事情的地方。

就此而言,在我看来,酒店实例有一个 列表rooms,每个列表都是 类型Person。您可以通过这种方式使简单的逻辑工作,但是 OO 设计的原则之一是使现有程序的扩展变得容易,因为您已经对问题域的真实世界对象进行了建模,因此用它们做更多的事情将是自然比你没有更容易。在这种情况下,在我看来,如果 Hotel 有一个 Room 对象列表,那么每个 Room 对象可以包含一定数量的 Person 对象,则可以更好地匹配已知问题空间。那么一个房间里的人数就更灵活了,不同房间的人数可能不同,等等。

我完全赞成从一个简单的系统开始,但既然你问的是 OO 设计,我想我会借此机会指出这些关于这个的事情。


推荐阅读