BLOG-2-数字电路模拟程序及课堂测验

一、前言
对两次pta题目及课堂作业总结:
有了上一次写pta的基础这次写的时候结合老师提供的建议先自己列出了一些可能的测试点然后写代码的时候尽可能地包含所设置的测试点,当然了老师题目中给出的测试点也是必要的。第一次电路模拟程序总体来说是比较顺畅的。第二次新加门电路后复杂度就上来了。前几天的课堂测试结果让我认识到想要学好java只会敲代码是远远不够的,其中的定义,对知识点的理解也是至关重要的。

二、设计与分析
第一次电路模拟程序分析
题目描述:
数字电路是一种处理离散信号的电子电路。与处理连续变化信号(如声音、温度)的模拟电路不同,数字电路只识别和运算两种基本状态:高电平(通常表示为“1”) 和 低电平(通常表示为“0”)。这正好与二进制数制系统相对应,使得数字电路成为所有计算机和数字系统的物理实现基础,请编程实现数字电路模拟程序。

类图设计:
image
类图分析:
LogicGate(抽象逻辑门类):所有逻辑门的抽象基类,定义了逻辑门的通用接口和行为
具体逻辑门类(AndGate, OrGate, NotGate, XorGate, XnorGate):实现具体逻辑门的功能
CircuitSimulator(电路模拟器类):核心功能类,负责整个电路的模拟过程
Connection(连接类):表示电路中两个引脚之间的连接关系
Main(主程序类):程序的入口点,处理输入/输出
Source Monitor分析结果:
image
由上面的Source Monitor分析的结果来看有有以下优劣势
优势:
1.代码结构(4个类、8个方法/类)符合面向对象设计原则
2.平均方法复杂度为2.91(一般认为3以下较好)
3.注释率为9.1%有一定的注释说明,不过度注释避免注释冗余
存在问题:
1.方法复杂度高:Main.main()方法复杂度达12,包含24条语句,违反了单一职责原则,深层次嵌套(最大块深度7)
2.主方法过于臃肿:24条语句,7层嵌套深度,承担了过多职责:输入解析、门创建、模拟执行
3.方法长度不均:平均每个方法7.06条语句,但Main.main()有24条,getSortedOutputs().sortedGates.sort()有7条语句的lambda表达式

第二次模拟电路程序分析
题目描述:
数字电路是一种处理离散信号的电子电路。与处理连续变化信号(如声音、温度)的模拟电路不同,数字电路只识别和运算两种基本状态:高电平(通常表示为“1”) 和 低电平(通常表示为“0”)。这正好与二进制数制系统相对应,使得数字电路成为所有计算机和数字系统的物理实现基础。请编程实现数字电路模拟程序。与第一次不同的是第二次模拟电路新增了译码器、数据选择器和数据分配器

类图设计:
image
设计模式分析:
1.模板方法模式 (Template Method Pattern):LogicComponent.calculateOutput() 定义了算法骨架,doCalculate() 由子类实现具体计算逻辑
2.策略模式 (Strategy Pattern):每种逻辑门实现不同的计算策略,通过继承和多态实现不同行为
3.工厂方法模式 (Factory Method Pattern):CircuitSimulator.createComponent() 根据字符串创建对应组件,隐藏了具体类的创建细节
类分析:
1.LogicComponent(抽象逻辑元件基类):
双重输出机制:支持多个输出引脚(Map<Integer, Boolean>)
计算状态管理:hasCalculated标志避免重复计算
类型权重系统:getTypeWeight()统一排序规则
灵活的引脚系统:支持任意引脚编号
2.BasicGate(基础门类):统一了基础门的输出格式,简化了子类的实现,所有基础门使用引脚0作为输出
3.Decoder(译码器类):
控制引脚分离:S1, S2, S3作为使能控制
动态输出引脚:根据输入数量确定输出引脚数量
特殊输出格式:返回有效输出编号而非引脚号

Source Monitor分析结果:
image
分析与心得:
相较于第一次模拟电路程序第二次有些许改善但还是存在一些问题
改善部分:
1.架构扩展性增强(类从4个增加到6个):增加了更复杂的电路元件(译码器、多路选择器等),继承层次更加丰富
2.平均复杂度控制良好(2.78 vs 2.91):尽管功能增加,但平均复杂度略有下降,说明新增功能被合理分配到不同类中
问题存在:
1.代码膨胀显著:行数增加63.5%,语句增加69.4%,注释率反而下降(6.6%)
2.最复杂方法恶化:Main.main()复杂度从12增加到16,语句数保持24条,但嵌套深度可能增加
3.方法内聚度下降:平均每个方法语句从7.06增加到7.33,块深度从1.41增加到1.67,嵌套更深

三、踩坑心得
第一次电路模拟程序总的来说写的还是比较顺畅,但是最后一个测试点不知道什么原因用了多个测试点去测试还是过不了 ,最后也只能放弃了,后面去请教同学也没找出问题所在

四、改进建议

  1. 统一引脚管理策略
点击查看代码
// 建议所有元件使用一致的引脚抽象
interface PinManager {
    int getInputPin(String pinName);
    int getOutputPin(String pinName);
    String formatPin(int pinNumber);
}

// 或者为每个元件定义清晰的引脚映射
class PinMapping {
    private Map<String, Integer> inputPins = new HashMap<>();
    private Map<String, Integer> outputPins = new HashMap<>();
    
    public PinMapping(String... pinDefinitions) {
        // 解析引脚定义
        // 如: "IN1:1", "IN2:2", "OUT:0"
    }
}
2. 改进译码器设计
点击查看代码
class Decoder extends LogicComponent {
    private final int dataBits; // 数据位数
    
    public Decoder(String name, int dataBits) {
        super(name);
        this.dataBits = dataBits;
    }
    
    // 定义清晰的引脚
    enum DecoderPin {
        ENABLE(0),     // 使能
        SELECT_A(1),   // 选择线A
        SELECT_B(2),   // 选择线B
        DATA_BASE(3);  // 数据输入起始
        
        final int offset;
        DecoderPin(int offset) { this.offset = offset; }
    }
    
    @Override
    protected void doCalculate() {
        // 检查使能
        if (!inputs.get(DecoderPin.ENABLE.offset)) {
            outputs.clear();
            return;
        }
        
        // 读取选择线
        int selectCode = 0;
        if (inputs.get(DecoderPin.SELECT_A.offset)) selectCode |= 0b01;
        if (inputs.get(DecoderPin.SELECT_B.offset)) selectCode |= 0b10;
        
        // 读取数据输入
        int data = 0;
        for (int i = 0; i < dataBits; i++) {
            if (inputs.get(DecoderPin.DATA_BASE.offset + i)) {
                data |= (1 << i);
            }
        }
        
        // 输出(例如74LS138样式)
        int outputCount = 1 << dataBits;
        for (int i = 0; i < outputCount; i++) {
            int pinNum = DecoderPin.DATA_BASE.offset + dataBits + i;
            outputs.put(pinNum, i == selectCode ? data != 0 : true);
        }
    }
}
3. 添加复位功能
点击查看代码
abstract class LogicComponent {
    // ... 现有代码 ...
    
    public void reset() {
        inputs.clear();
        outputs.clear();
        hasCalculated = false;
    }
}

class CircuitSimulator {
    public void reset() {
        for (LogicComponent component : components.values()) {
            component.reset();
        }
    }
    
    public void simulateWithInput(String inputLine) {
        reset();  // 先重置
        parseInputSignals(inputLine);
        simulate();
    }
}
4. 统一输出格式
点击查看代码
abstract class LogicComponent {
    // ... 现有代码 ...
    
    public List<String> getAllOutputs() {
        List<String> result = new ArrayList<>();
        for (Map.Entry<Integer, Boolean> entry : outputs.entrySet()) {
            result.add(String.format("%s-%d:%s", 
                name, entry.getKey(), entry.getValue() ? "1" : "0"));
        }
        return result;
    }
    
    // 或者使用专门的输出格式化器
    public String formatOutput() {
        if (outputs.isEmpty()) return null;
        
        // 特殊元件特殊处理
        if (this instanceof Decoder) {
            return formatDecoderOutput();
        } else if (this instanceof Demultiplexer) {
            return formatDemuxOutput();
        } else {
            // 默认格式
            Map.Entry<Integer, Boolean> first = outputs.entrySet().iterator().next();
            return String.format("%s-%d:%s", name, first.getKey(), 
                first.getValue() ? "1" : "0");
        }
    }
}
5. 添加输入验证和调试信息
点击查看代码
class CircuitSimulator {
    public void simulate() {
        System.err.println("开始模拟,元件数量: " + components.size());
        
        // 检查悬空输入
        for (LogicComponent comp : components.values()) {
            if (!comp.hasAllInputs()) {
                System.err.println("警告: " + comp.getName() + " 缺少输入");
            }
        }
        
        // ... 现有模拟逻辑 ...
        
        System.err.println("模拟完成,迭代次数: " + iteration);
    }
}

总结:有了之前的经验这次入手的时候没有那么困难了,如类的设计方法的调用等都能较为熟练地写出来,这两次的题目难度仍是循序渐进的。第一版因为功能简单而相对清晰,第二版功能增强但接口复杂度增加。抽象类的使用使得代码迭代变得更加容易些。

课堂作业总结:
做完课堂测试后发现问题挺多的,一些语法规范只有在写代码报错的时候才能发现,还有修饰符修饰不同的方法的时候,内部类和外部类的权限不同等。

posted @ 2025-12-14 21:02  nchulj  阅读(5)  评论(0)    收藏  举报