从计算器小例子的总结思考
背景
老师前段时间给我安排了一个小任务,使用面向对象的编程思想实现一个能支持加减乘除的计算器,并且要符合开闭原则,可以随意添加新的运算符(例如添加一个开方运算符)。这个小例子,从老师布置给我到现在已经过去了好几天,由于自己的不理解,一直没有动手开工。偶然今早老师找我过问起这件事,老师帮我梳理了这其中的业务以及一些技术问题,好几天没有头绪的小例子,今天半天的时间就做出来了。
一、设计与思考
1. 不会就要问
不知道你们在遇到问题的时候会怎么处理,我是习惯先自己凭空琢磨,然后再根据琢磨的结果去查资料找答案,往往在这个过程中就已经浪费了大部分的时间,而且常常是把路走歪了或者是走了别人已经走过了的重复的路。
所以才有了这个小标题——不会就要问,我们身边真的不乏那些“巨人”,虚心的向身边的巨人请教,不要碍于面子或者怕自己的问题太低级不敢问。所谓的“要站在巨人的肩膀上”就是这个意思,前辈已经为我们打好了很多的基础,已经为我们探索了很多漆黑的道路,为的就是不需要让我们再重复的去造轮子。当你不懂、不明白或者思路卡主的时候,不如好好的向身边那些“巨人”虚心的请教。
2. 逻辑不通就要画图
小的时候老妈总是教育我“好记性不如烂笔头”,说的就是让我要多做笔记,多将脑子里放着的事情落实到纸面上,按时的清空自己的大脑。今天的这件事也是一样,老师说给我这个小例子后,我一直停留于在脑子里想着这个该怎么实现,总是顾此失彼,考虑的不够全面,落实的方案也是自相矛盾。
直到我将脑中的思路落实到了图上,我凭借着自己的思考画了第一版的流程图:
 
 虽然输出了流程图,但是其中还是有很多地方落实不到代码上。于是跟老师讨论过之后又有了第二版流程图:
 
 这里的第二版流程图更注重解耦合和代码的落实,将改变运算符合求得运算结果分成了两个流程去做梳理,这其中通过对象来进行连接。
实现效果:
 
二、代码实现
1. 具体代码实现
UI页面:
package com.zwb.awtui;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;
/**
 * @program: zwbStudy
 * @description:
 * @author: 翟文彪
 * @create: 2022-06-02 10:07
 **/
public class UI {
    public static Operation opera;
    public static JLabel labelOperation;
    public static void main(String[] args) {
        // 创建窗口
        JFrame jf = new JFrame("运算器");
        jf.setLayout(new FlowLayout());
        jf.setBounds(400,300,400,500);
        // 运算符按钮集合
        List<JButton> jButtonList = new ArrayList<>();
        // 按钮(通过读取配置文件默认加载)
        // 读取配置文件
        Properties properties = new Properties();
        String pat = "D:\\JAVA\\zwbStudy\\src\\main\\resources\\application.properties";
        File file = new File(pat);
        try {
            FileInputStream fileOutputStream = null;
            if (file.getParentFile().exists()) {
                fileOutputStream = new FileInputStream(file);
            }
            properties.load(fileOutputStream);
            String config = properties.getProperty("button");
            List<String> buttonList = new ArrayList<>();
            // 使用字符串分词器将";"作为分隔符分隔各个按钮
            StringTokenizer subString = new StringTokenizer(config,";");
            // 循环存储到buttonList中
            while (subString.hasMoreTokens()){
                buttonList.add(subString.nextToken());
            }
            for (String button : buttonList) {
                // 根据配置文件中的全路径实例化对象,创建页面上的按钮
                Class<?> newButton = null;
                newButton = Class.forName(button);
                ButtonObject jButton = (ButtonObject)newButton.newInstance();
                jButtonList.add(jButton.creatButton());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        JButton equalsButton = new JButton("=");
        equalsButton.setEnabled(true);
        // 输入框
        JTextField textA = new JTextField(5);
        JTextField textB = new JTextField(5);
        // 标签
        labelOperation = new JLabel();
        JLabel labelResult = new JLabel();
        // 运算器执行区域
        jf.add(textA);
        jf.add(labelOperation);
        jf.add(textB);
        jf.add(equalsButton);
        jf.add(labelResult);
        // 运算符库
        for (JButton jButton : jButtonList) {
            jf.add(jButton);
            // 各个运算符加载上运算符监听事件
            OperationClickAction cli = new OperationClickAction();
            jButton.addMouseListener(cli);
        }
        // 给等于按钮加载上等于按钮监听事件
        equalsButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                opera.setNumberA(Double.valueOf(textA.getText()));
                opera.setNumberB(Double.valueOf(textB.getText()));
                labelResult.setText(String.valueOf(opera.getResult()));
            }
        });
        jf.setVisible(true);
        jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
}
  
 - 1
 - 2
 - 3
 - 4
 - 5
 - 6
 - 7
 - 8
 - 9
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 - 17
 - 18
 - 19
 - 20
 - 21
 - 22
 - 23
 - 24
 - 25
 - 26
 - 27
 - 28
 - 29
 - 30
 - 31
 - 32
 - 33
 - 34
 - 35
 - 36
 - 37
 - 38
 - 39
 - 40
 - 41
 - 42
 - 43
 - 44
 - 45
 - 46
 - 47
 - 48
 - 49
 - 50
 - 51
 - 52
 - 53
 - 54
 - 55
 - 56
 - 57
 - 58
 - 59
 - 60
 - 61
 - 62
 - 63
 - 64
 - 65
 - 66
 - 67
 - 68
 - 69
 - 70
 - 71
 - 72
 - 73
 - 74
 - 75
 - 76
 - 77
 - 78
 - 79
 - 80
 - 81
 - 82
 - 83
 - 84
 - 85
 - 86
 - 87
 - 88
 - 89
 - 90
 - 91
 - 92
 - 93
 - 94
 - 95
 - 96
 - 97
 - 98
 - 99
 - 100
 - 101
 - 102
 - 103
 
运算符按钮抽象类与子类:
package com.zwb.awtui;
import javax.swing.*;
/**
 * @program: zwbStudy
 * @description: 按钮
 * @author: 翟文彪
 * @create: 2022-06-10 15:09
 **/
public abstract class ButtonObject {
    protected abstract iFactory creatFactory();
    protected abstract JButton creatButton();
}
class ButtonAdd extends ButtonObject{
    @Override
    protected iFactory creatFactory() {
        return new Factory1();
    }
    @Override
    protected JButton creatButton() {
        JButton jButton = new JButton("+");
        jButton.setEnabled(true);
        return jButton;
    }
}
class ButtonSub extends ButtonObject{
    @Override
    protected iFactory creatFactory() {
        return new Factory2();
    }
    @Override
    protected JButton creatButton() {
        JButton jButton =  new JButton("-");
        jButton.setEnabled(true);
        return jButton;
    }
}
class ButtonMul extends ButtonObject{
    @Override
    protected iFactory creatFactory() {
        return new Factory3();
    }
    @Override
    protected JButton creatButton() {
        JButton jButton =  new JButton("*");
        jButton.setEnabled(true);
        return jButton;
    }
}
class ButtonDiv extends ButtonObject{
    @Override
    protected iFactory creatFactory() {
        return new Factory4();
    }
    @Override
    protected JButton creatButton() {
        JButton jButton =  new JButton("/");
        jButton.setEnabled(true);
        return jButton;
    }
}
  
 - 1
 - 2
 - 3
 - 4
 - 5
 - 6
 - 7
 - 8
 - 9
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 - 17
 - 18
 - 19
 - 20
 - 21
 - 22
 - 23
 - 24
 - 25
 - 26
 - 27
 - 28
 - 29
 - 30
 - 31
 - 32
 - 33
 - 34
 - 35
 - 36
 - 37
 - 38
 - 39
 - 40
 - 41
 - 42
 - 43
 - 44
 - 45
 - 46
 - 47
 - 48
 - 49
 - 50
 - 51
 - 52
 - 53
 - 54
 - 55
 - 56
 - 57
 - 58
 - 59
 - 60
 - 61
 - 62
 - 63
 - 64
 - 65
 - 66
 - 67
 - 68
 
运算工厂:
package com.zwb.awtui;
/**
 * @program: zwbStudy
 * @description: 运算工厂
 * @author: 翟文彪
 * @create: 2022-06-05 10:52
 **/
public interface iFactory {
    Operation createOperation();
}
class Factory1 implements iFactory{
    @Override
    public Operation createOperation() {
        return new OperationAdd();
    }
}
class Factory2 implements iFactory{
    @Override
    public Operation createOperation() {
        return new OperationSub();
    }
}
class Factory3 implements iFactory{
    @Override
    public Operation createOperation() {
        return new OperationMul();
    }
}
class Factory4 implements iFactory{
    @Override
    public Operation createOperation() {
        return new OperationDiv();
    }
}
  
 - 1
 - 2
 - 3
 - 4
 - 5
 - 6
 - 7
 - 8
 - 9
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 - 17
 - 18
 - 19
 - 20
 - 21
 - 22
 - 23
 - 24
 - 25
 - 26
 - 27
 - 28
 - 29
 - 30
 - 31
 - 32
 - 33
 - 34
 - 35
 - 36
 - 37
 - 38
 - 39
 - 40
 
运算符抽象类与子类
package com.zwb.awtui;
/**
 * @program: zwbStudy
 * @description: 运算符抽象类与子类
 * @author: 翟文彪
 * @create: 2022-06-05 10:14
 **/
public abstract class Operation {
    private double numberA = 0;
    private double numberB = 0;
    public double getNumberA() {
        return numberA;
    }
    public void setNumberA(double numberA) {
        this.numberA = numberA;
    }
    public double getNumberB() {
        return numberB;
    }
    public void setNumberB(double numberB) {
        this.numberB = numberB;
    }
    public abstract double getResult();
}
class OperationAdd extends Operation {
    @Override
    public double getResult() {
        double result = 0;
        result = getNumberA() + getNumberB();
        return result;
    }
}
class OperationSub extends Operation {
    @Override
    public double getResult() {
        double result = 0;
        result = getNumberA() - getNumberB();
        return result;
    }
}
class OperationMul extends Operation {
    @Override
    public double getResult() {
        double result = 0;
        result = getNumberA() * getNumberB();
        return result;
    }
}
class OperationDiv extends Operation {
    @Override
    public double getResult() {
        double result = 0;
        try {
            if (getNumberB() == 0) {
                throw new Exception("除数不能为0");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        result = getNumberA() / getNumberB();
        return result;
    }
}
  
 - 1
 - 2
 - 3
 - 4
 - 5
 - 6
 - 7
 - 8
 - 9
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 - 17
 - 18
 - 19
 - 20
 - 21
 - 22
 - 23
 - 24
 - 25
 - 26
 - 27
 - 28
 - 29
 - 30
 - 31
 - 32
 - 33
 - 34
 - 35
 - 36
 - 37
 - 38
 - 39
 - 40
 - 41
 - 42
 - 43
 - 44
 - 45
 - 46
 - 47
 - 48
 - 49
 - 50
 - 51
 - 52
 - 53
 - 54
 - 55
 - 56
 - 57
 - 58
 - 59
 - 60
 - 61
 - 62
 - 63
 - 64
 - 65
 - 66
 - 67
 - 68
 - 69
 - 70
 - 71
 - 72
 - 73
 - 74
 
按钮事件监听类
package com.zwb.awtui;
import javax.swing.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;
/**
 * @program: zwbStudy
 * @description: 按钮事件监听类
 * @author: 翟文彪
 * @create: 2022-06-10 14:40
 **/
public class OperationClickAction implements MouseListener {
    public static String operationText;
    @Override
    public void mouseClicked(MouseEvent mouseEvent) {
        //System.out.println("你点击的按钮名称为"+((JButton) (e.getSource())).getText());
        // 读取配置文件
        Properties properties = new Properties();
        String pat = "D:\\JAVA\\zwbStudy\\src\\main\\resources\\application.properties";
        File file = new File(pat);
        try {
            FileInputStream fileOutputStream = null;
            if (file.getParentFile().exists()) {
                fileOutputStream = new FileInputStream(file);
            }
            properties.load(fileOutputStream);
            String config = properties.getProperty(((JButton) (mouseEvent.getSource())).getText());
            // 根据配置文件中的全路径实例化对象,创建页面上的按钮
            Class<?> newButton = null;
            newButton = Class.forName(config);
            ButtonObject button = (ButtonObject) newButton.newInstance();
            // 创建对应的工厂对象
            iFactory factory = button.creatFactory();
            UI.opera = factory.createOperation();
            // 赋值给运算符文本
            UI.labelOperation.setText(((JButton) (mouseEvent.getSource())).getText());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    @Override
    public void mousePressed(MouseEvent e) {
    }
    @Override
    public void mouseReleased(MouseEvent e) {
    }
    @Override
    public void mouseEntered(MouseEvent e) {
    }
    @Override
    public void mouseExited(MouseEvent e) {
    }
}
  
 - 1
 - 2
 - 3
 - 4
 - 5
 - 6
 - 7
 - 8
 - 9
 - 10
 - 11
 - 12
 - 13
 - 14
 - 15
 - 16
 - 17
 - 18
 - 19
 - 20
 - 21
 - 22
 - 23
 - 24
 - 25
 - 26
 - 27
 - 28
 - 29
 - 30
 - 31
 - 32
 - 33
 - 34
 - 35
 - 36
 - 37
 - 38
 - 39
 - 40
 - 41
 - 42
 - 43
 - 44
 - 45
 - 46
 - 47
 - 48
 - 49
 - 50
 - 51
 - 52
 - 53
 - 54
 - 55
 - 56
 - 57
 - 58
 - 59
 - 60
 - 61
 - 62
 - 63
 - 64
 - 65
 - 66
 - 67
 - 68
 
2. 反射虽好可不要贪杯哦
在上面我给出的代码中,UI类(客户端类)初始的运算符按钮是通过读取配置文件中的类的全路径以及反射加载到Frame上的,后面跟老师讨论的过程中我也了解到,这里完全可以不使用反射来进行按钮加载,因为有多少按钮需要加载我们都是已知的,只需要将按钮类中包括的所有子类按钮全部实例化即可。
这里最大的问题就是滥用反射,虽然我们都知道反射很方便,灵活性很高,但是它相比直接进行实例化的操作有着执行效率上的差距,因为反射需要读取配置文件中的内容再去进行实例化的操作。
所以,虽然反射很方便,还是要注意使用的场景和时机。
三、总结提升
1. 技术提升
(1)对于Java中的GUI编程从使用的角度上进行了学习和了解,也扩宽了这方面的知识
 (2)灵活使用反射、工厂方法、类与类之间的关系可以将各个对象之间的耦合分解到很小
2. 思想提升
(1)遇到了困难一定要及时的去请教,要学会站在巨人的肩膀上。
 (2)要有全局观的意识,通过画图对于整体的业务和结构进行梳理,孤立的、局部的看问题是得不到正确的答案的
 (3)你认为的不一定是你认为的,比如这次的小例子,一开始的时候根本想不到一个合适的解决方案来满足老师提出的需求,但是这并不代表着,不存在这么一种解决的方式。不要将自己的思想局限住了,只要敢想敢做,就一定会有结果。
文章来源: blog.csdn.net,作者:翟文彪,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/zwb568/article/details/125227942
- 点赞
 - 收藏
 - 关注作者
 
            
           
评论(0)