java面向对象思维程序设计开发以及案例 -电梯运行问题对象分析与程序设计(1)

简介: java面向对象思维程序设计开发以及案例 -电梯运行问题对象分析与程序设计(1)

电梯是我们日常生活中经常看见和使用的运载工具,但其中也隐藏着一个精而小的程序,我们今天模拟一个电梯运行程序来开始我们面向对象之旅


电梯问题-抽取关键需求


1.电梯首先肯定是要可以上下不间断运行

2.可以达到顶层或底层之后向反方向继续运行

3.人员可以按钮然后等待电梯停在本楼层并进入

4.进入的人可以选择自己的目的层数

5.电梯可以在目的层数停止等待一定时间后继续运行


问题需求关键环节流程图


我们进入需求转化环境,我们来梳理一下需求并且转化为一个时序图,便于我们拆分对象以及确定逻辑顺序,流程图如下

1.png

初步领域对象分析,最小可用原则


我们创建对象以及方法要使用最小可用原则,既不需要的就不要加进对象,直到确定需要这个对象或  者属性或者方法再添加,所以可以如下分析

依据时序图,我们初步分为了对象人person与对象电梯elevator

对象电梯可以被启动,然后不断运行,所以我们觉得他应该有一个start方法

我们也许会觉得对象人是外部触发电梯start 方法的对象

电梯应该方法是判断是否到顶部isTop(),是否到底部isBottom(),并且有一个方法是wait() 等待人进入并且选择目标层数selectFloor(int floor)

那么我们的对象建模就结束了,领域建模图如下

1.png

对象建模思考


思考1:电梯运行是否内部维护运行状态,是否需要一个start方法


我个人认为都可以,这里我是按照不需要设计的,我这里把电梯运行和电梯本身认为是两个实体,你 可以用轿厢品牌1 带动电梯,第二天也可以用轿厢2带动电梯,

也就是说电梯是被外部轿厢发动机带动运行的,而电梯本身只负责内部运行逻辑处理

换句话说我的运行创建线程并不是电梯内部维护的,而是适用方,可以用线程池,也可以直接new thread

这样就把更大的自由度留给了电梯合作方:电机轿厢,也符合易扩展多方合作的共赢思维


思考2:是否需要人这个person对象


本程序我们真的需要人这个对象吗,

实际上人在这里的作用无非就是提供电梯需要停止的层数

而实际上这个程序的外部使用者是真正活着的实体人

因此,我们在程序里定义人这个对象是多余的,所以我们可以将对象人person这个类去掉,换成层数floor

重新分析后-最终领域对象图

1.png

面向对象程序设计核心思想原则


1.就是让人从外面看起来就知道你的代码是在干什么,每一个对象都要有意义,并且真实符合世界上实体事物运行规则

2.设计的对象没有绝对的对与错,只要让人觉得你的对象确实合理并且使用起来符合正常人的思维习惯就可以

经过以上分析建模,形成目前的初版代码如下

public class ElevatorTest {
    public static void main(String[] args){
        //18层的电梯
        int floor = 18;
        //电梯初始化
        Elevator elevator = new Elevator(floor);
        //创建一个线程池,初始化两个线程,1:电梯运行线程,2:模拟随机层数人员进入电梯线程
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,2,10L, TimeUnit.SECONDS,new  ArrayBlockingQueue(2));
        //启动电梯
        threadPoolExecutor.execute(elevator);
        //模拟随机楼层人员进电梯与出电梯
        threadPoolExecutor.execute(()->{
                while (true){
                    //模拟随机生成 1~18楼人
                    int enterRandom = new Random().nextInt(18);
                    if(enterRandom ==0){
                        continue;
                    }else {
                        try {
                            //人员进入
                            elevator.enter(enterRandom);
                            Thread.sleep(3000);
                        }catch (InterruptedException e){
                        }
                    }
                }
        });
    }
}
class Elevator implements Runnable {
    boolean start = false;
    int currentFloor ;
    boolean directionTop = true;
    int floor ;
    //保存目标层数map
    Map enterMap = new HashMap(18);
    ReentrantLock lock = new ReentrantLock();
    public Elevator(int floor){
        this.floor = floor;
        this.currentFloor = 1;
        System.out.println("初始化了一个"+floor+"层的电梯,当前电梯在第1层");
    }
    /**
     * 人员进入电梯同时选择好目标层数
     * */
    public void enter(int outFloor){
        lock.lock();
        System.out.println("人员进入,按了"+outFloor+"层");
        enterMap.put(outFloor,null);
        lock.unlock();
    }
    /**
     * 是否是顶层
     * */
    public boolean isTop(){
        return this.currentFloor == floor;
    }
    /**
     * 是否是底层
     * */
    public boolean isBottom(){
        return this.currentFloor == 1;
    }
    @Override
    public void run() {
        System.out.println("电梯启动");
        start = true;
        while (start){
            if(!lock.isLocked()) {
                try {
                    if (directionTop) {
                        currentFloor++;
                        System.out.println("当前在电梯第" + currentFloor + "层");
                        //该层人员出门出门后将该层移除
                        if(enterMap.containsKey(currentFloor)){
                            try {
                                System.out.println(currentFloor+"人员出门");
                                enterMap.remove(currentFloor);
                                System.out.println("剩余楼层"+enterMap.keySet());
                                Thread.sleep(5000);
                            }catch (Exception e){
                            }
                        }
                        if (isTop()) {
                            directionTop = false;
                            System.out.println("到达顶层,开始向下运行");
                        }
                    } else {
                        currentFloor--;
                        System.out.println("当前在电梯第" + currentFloor + "层");
                        //该层人员出门出门后将该层移除
                        if(enterMap.containsKey(currentFloor)){
                            try {
                                System.out.println(currentFloor+"人员出门");
                                enterMap.remove(currentFloor);
                                System.out.println("剩余楼层"+enterMap.keySet());
                                Thread.sleep(5000);
                            }catch (Exception e){
                            }
                        }
                        System.out.println("当前在电梯第" + currentFloor + "层");
                        if (isBottom()) {
                            directionTop = true;
                            System.out.println("到达1层,开始向向运行");
                        }
                    }
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                }
            }else {
                try {
                    System.out.println("进人中。。");
                    Thread.sleep(5000);
                }catch (Exception e){
                }
            }
        }
    }
}

运行输出结果


初始化了一个18层的电梯,当前电梯在第1层

电梯启动

当前在电梯第2层

人员进入,按了17


当前在电梯第3层

当前在电梯第4层

当前在电梯第5层

人员进入,按了13


当前在电梯第6层

当前在电梯第7层

当前在电梯第8层

人员进入,按了7


当前在电梯第9层

当前在电梯第10层

当前在电梯第11层

人员进入,按了6


当前在电梯第12层

当前在电梯第13层

13人员出门

剩余楼层[6, 7, 17]

人员进入,按了11


人员进入,按了4


当前在电梯第14层

人员进入,按了13


当前在电梯第15层

当前在电梯第16层

当前在电梯第17层

17人员出门

剩余楼层[4, 6, 7, 11, 13]

人员进入,按了7


人员进入,按了1


当前在电梯第18层

到达顶层,开始向下运行

人员进入,按了16


当前在电梯第17层

当前在电梯第17层

当前在电梯第16层

16人员出门

剩余楼层[1, 4, 6, 7, 11, 13]

人员进入,按了4


人员进入,按了3


当前在电梯第16层

当前在电梯第15层

当前在电梯第15层

当前在电梯第14层

当前在电梯第14层

人员进入,按了14


当前在电梯第13层

13人员出门

剩余楼层[1, 3, 4, 6, 7, 11, 14]

人员进入,按了10


当前在电梯第13层

人员进入,按了10


当前在电梯第12层

当前在电梯第12层

当前在电梯第11层

11人员出门

剩余楼层[1, 3, 4, 6, 7, 10, 14]


面向对象到底是节省时间还是浪费时间


其实使用面向对象角度建模并且进行程序开发并不是耗费时间,而是节省时间

因为设计的对象是充血模型,所以后续其他业务使用对应功能只需要对象.方法就可以了,这也是DDD 领域驱动设计的核心思想

而且面向对象设计开发也是利于大家对需求转化的加深,会加速开发效率,比如这个程序我建模可能用了30分钟,但编码只用了15分钟左右


结语


程序是依照我们小设计原则没有任何优化重构编写的,肯定细节上还有容错以及重用上有很多问题

但这就是程序设计,因为他满足了最小化的我们的需求

但是,问题终究是问题,我们还是要解决的,先把当前代码重构,然后我们要把缺失逻辑补充:

比如并没有实现人按电梯上下进入的操作,进入的人并没有实现同时允许多层数选择的操作等

没有使用层数floor对象,而是用map简单表示

下一篇我们将继续优化并完成这个电梯程序


相关文章
|
10天前
|
Java
Java快速入门之类、对象、方法
本文简要介绍了Java快速入门中的类、对象和方法。首先,解释了类和对象的概念,类是对象的抽象,对象是类的具体实例。接着,阐述了类的定义和组成,包括属性和行为,并展示了如何创建和使用对象。然后,讨论了成员变量与局部变量的区别,强调了封装的重要性,通过`private`关键字隐藏数据并提供`get/set`方法访问。最后,介绍了构造方法的定义和重载,以及标准类的制作规范,帮助初学者理解如何构建完整的Java类。
|
9天前
|
安全 Java
Object取值转java对象
通过本文的介绍,我们了解了几种将 `Object`类型转换为Java对象的方法,包括强制类型转换、使用 `instanceof`检查类型和泛型方法等。此外,还探讨了在集合、反射和序列化等常见场景中的应用。掌握这些方法和技巧,有助于编写更健壮和类型安全的Java代码。
30 17
|
10天前
|
前端开发 Java 程序员
菜鸟之路day02-04拼图小游戏开发一一JAVA基础综合项目
本项目基于黑马程序员教程,涵盖面向对象进阶、继承、多态等知识,历时约24小时完成。项目去除了登录和注册模块,专注于单机游戏体验。使用Git进行版本管理,代码托管于Gitee。项目包含窗体搭建、事件监听、图片加载与打乱、交互逻辑实现、菜单功能及美化界面等内容。通过此项目,巩固了Java基础并提升了实际开发能力。 仓库地址:[https://gitee.com/zhang-tenglan/puzzlegame.git](https://gitee.com/zhang-tenglan/puzzlegame.git)
35 6
|
13天前
|
Java 应用服务中间件 API
【潜意识Java】javaee中的SpringBoot在Java 开发中的应用与详细分析
本文介绍了 Spring Boot 的核心概念和使用场景,并通过一个实战项目演示了如何构建一个简单的 RESTful API。
31 5
|
13天前
|
前端开发 Java 数据库连接
【潜意识Java】深度解读JavaWeb开发在Java学习中的重要性
深度解读JavaWeb开发在Java学习中的重要性
24 4
|
13天前
|
SQL Java API
|
13天前
|
前端开发 Java 数据库连接
Java后端开发-使用springboot进行Mybatis连接数据库步骤
本文介绍了使用Java和IDEA进行数据库操作的详细步骤,涵盖从数据库准备到测试类编写及运行的全过程。主要内容包括: 1. **数据库准备**:创建数据库和表。 2. **查询数据库**:验证数据库是否可用。 3. **IDEA代码配置**:构建实体类并配置数据库连接。 4. **测试类编写**:编写并运行测试类以确保一切正常。
27 2
|
27天前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
85 17
|
2月前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
23天前
|
缓存 安全 算法
Java 多线程 面试题
Java 多线程 相关基础面试题