首页 > 编程语言 >软件设计原则(Java实现/给出正例反例)

软件设计原则(Java实现/给出正例反例)

时间:2024-09-16 21:24:41浏览次数:3  
标签:正例 Java 示例 void System 反例 class println public

文章目录

前言

软件设计原则有助于编写灵活、可扩展且易于维护的代码。以下是每个设计原则的定义以及未遵循和遵循原则的 Java 示例。

1. 开闭原则(Open/Closed Principle)

定义:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。意味着我们应通过添加新代码,而不是修改现有代码来实现功能的扩展。

违反开闭原则的示例
class Rectangle {
    public double width;
    public double height;
}

class Circle {
    public double radius;
}

class AreaCalculator {
    public double calculateArea(Object shape) {
        if (shape instanceof Rectangle) {
            Rectangle rectangle = (Rectangle) shape;
            return rectangle.width * rectangle.height;
        } else if (shape instanceof Circle) {
            Circle circle = (Circle) shape;
            return Math.PI * circle.radius * circle.radius;
        }
        return 0;
    }
}

问题:如果要添加新形状(例如三角形),必须修改 calculateArea 方法,违反了开闭原则。

遵循开闭原则的示例
interface Shape {
    double calculateArea();
}

class Rectangle implements Shape {
    public double width;
    public double height;

    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public double calculateArea() {
        return width * height;
    }
}

class Circle implements Shape {
    public double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
}

class AreaCalculator {
    public double calculateArea(Shape shape) {
        return shape.calculateArea();
    }
}

优势:如果要添加新形状,只需创建一个新的实现类,而无需修改 AreaCalculator 类。

2. 里氏代换原则(Liskov Substitution Principle)

定义:子类必须能够替换其基类,而不会破坏应用程序的正确性。也就是说,程序中的对象应能够使用其子类实例替换而不影响功能。

违反里氏代换原则的示例
class Bird {
    public void fly() {
        System.out.println("Bird is flying");
    }
}

class Ostrich extends Bird {
    @Override
    public void fly() {
        throw new UnsupportedOperationException("Ostriches cannot fly");
    }
}

问题OstrichBird 的子类,但它无法飞行,导致在使用 Bird 类型时可能产生异常。

遵循里氏代换原则的示例
class Bird {
    public void move() {
        System.out.println("Bird is moving");
    }
}

class FlyingBird extends Bird {
    public void fly() {
        System.out.println("Flying bird is flying");
    }
}

class Ostrich extends Bird {
    @Override
    public void move() {
        System.out.println("Ostrich is running");
    }
}

class Sparrow extends FlyingBird {
    @Override
    public void fly() {
        System.out.println("Sparrow is flying");
    }
}

优势:通过将 BirdFlyingBird 分开处理,Ostrich 仍然遵循里氏代换原则,并且代码更具扩展性。

3. 依赖倒转原则(Dependency Inversion Principle)

定义:高层模块不应该依赖于低层模块。二者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。

违反依赖倒转原则的示例
class LightBulb {
    public void turnOn() {
        System.out.println("LightBulb is on");
    }

    public void turnOff() {
        System.out.println("LightBulb is off");
    }
}

class Switch {
    private LightBulb bulb;

    public Switch(LightBulb bulb) {
        this.bulb = bulb;
    }

    public void press() {
        bulb.turnOn();
    }
}

问题Switch 类直接依赖于具体的 LightBulb 实现,违反了依赖倒转原则。

遵循依赖倒转原则的示例
interface Switchable {
    void turnOn();
    void turnOff();
}

class LightBulb implements Switchable {
    @Override
    public void turnOn() {
        System.out.println("LightBulb is on");
    }

    @Override
    public void turnOff() {
        System.out.println("LightBulb is off");
    }
}

class Fan implements Switchable {
    @Override
    public void turnOn() {
        System.out.println("Fan is on");
    }

    @Override
    public void turnOff() {
        System.out.println("Fan is off");
    }
}

class Switch {
    private Switchable device;

    public Switch(Switchable device) {
        this.device = device;
    }

    public void press() {
        device.turnOn();
    }
}

优势Switch 类依赖于 Switchable 接口,而不是具体的实现。现在我们可以轻松替换为任何其他实现。

4. 接口隔离原则(Interface Segregation Principle)

定义:不应该强迫客户端依赖于他们不使用的接口。应将庞大的接口拆分成更小、更具体的接口,使得客户端只需知道它们真正需要的方法。

违反接口隔离原则的示例
interface Worker {
    void work();
    void eat();
}

class HumanWorker implements Worker {
    @Override
    public void work() {
        System.out.println("Human is working");
    }

    @Override
    public void eat() {
        System.out.println("Human is eating");
    }
}

class RobotWorker implements Worker {
    @Override
    public void work() {
        System.out.println("Robot is working");
    }

    @Override
    public void eat() {
        // Robot does not eat, but must implement this method
        throw new UnsupportedOperationException("Robot does not eat");
    }
}

问题RobotWorker 实现了 eat() 方法,但它实际上并不需要这个功能。

遵循接口隔离原则的示例
interface Workable {
    void work();
}

interface Eatable {
    void eat();
}

class HumanWorker implements Workable, Eatable {
    @Override
    public void work() {
        System.out.println("Human is working");
    }

    @Override
    public void eat() {
        System.out.println("Human is eating");
    }
}

class RobotWorker implements Workable {
    @Override
    public void work() {
        System.out.println("Robot is working");
    }
}

优势RobotWorker 只实现了它需要的 Workable 接口,不再需要实现不必要的 eat() 方法。

5. 迪米特法则(Law of Demeter)

定义:迪米特法则也称为“最少知识原则”,它规定一个对象应该对其他对象有尽可能少的了解。具体而言,一个对象不应直接调用其他对象的内部方法或与其不直接相关的对象交互。

违反迪米特法则的示例:
class Engine {
    public void start() {
        System.out.println("Engine started");
    }
}

class Car {
    private Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }

    public Engine getEngine() {
        return engine;
    }
}

class Driver {
    private Car car;

    public Driver(Car car) {
        this.car = car;
    }

    public void startCar() {
        car.getEngine().start(); // 直接调用 Engine 的方法
    }
}

问题Driver 直接调用了 Enginestart() 方法,违反了迪米特法则。Driver 类不应该知道 Car 的内部实现细节(即 Engine 的存在)。

遵循迪米特法则的示例:
class Engine {
    public void start() {
        System.out.println("Engine started");
    }
}

class Car {
    private Engine engine;

    public Car(Engine engine) {
        this.engine = engine;
    }

    public void start() {
        engine.start(); // Car 自己管理 Engine 的启动
    }
}

class Driver {
    private Car car;

    public Driver(Car car) {
        this.car = car;
    }

    public void startCar() {
        car.start(); // 只与 Car 对象直接交互
    }
}

优势Driver 只与 Car 交互,而不是直接操控 Car 的内部组件 Engine,从而遵循了迪米特法则。这样减少了对象之间的耦合度,提高了代码的可维护性。

6. 合成复用原则(Composition Over Inheritance)

定义:合成复用原则建议优先使用对象的组合而不是继承来实现代码复用。继承容易导致子类和父类之间的强耦合,而组合更灵活且降低了耦合性。

违反合成复用原则的示例
class Animal {
    public void makeSound() {
        System.out.println("Animal sound");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Bark");
    }
}

class RobotDog extends Dog {
    // 机器人狗不是真正的狗,但却继承了 Dog
    public void chargeBattery() {
        System.out.println("RobotDog charging battery");
    }
}

问题RobotDog 继承了 Dog,但它并不需要 Dog 的所有行为,例如真实狗的叫声,这使得继承不适用。

遵循合成复用原则的示例
class AnimalSound {
    public void makeSound() {
        System.out.println("Animal sound");
    }
}

class Dog {
    private AnimalSound sound;

    public Dog(AnimalSound sound) {
        this.sound = sound;
    }

    public void makeSound() {
        sound.makeSound();
    }
}

class RobotDog {
    public void chargeBattery() {
        System.out.println("RobotDog charging battery");
    }
}

优势RobotDogDog 不再有强制的继承关系。Dog 使用组合来实现 makeSound() 方法,这使得它与其他对象(如 RobotDog)更加独立,减少了类之间的耦合。

标签:正例,Java,示例,void,System,反例,class,println,public
From: https://blog.csdn.net/qq_53655497/article/details/142306777

相关文章

  • 铁路订票平台小程序的设计与实现(Java+Mysql+万字文档+ppt+系统源码+数据库 +调试)
    目  录目  录第1章 绪论1.1 课题背景1.2课题意义1.3研究内容第2章 开发环境与技术2.1MYSQL数据库2.2Java语言2.3微信小程序技术2.4 SpringBoot框架2.5 B/S架构2.6 Tomcat介绍2.7HTML简介2.8MyEclipse开发工具第3章 系统分析......
  • Java - 1
    特点面向对象OOP健壮性:强类型机制、异常处理、垃圾的自动收集跨平台性:.class文件可以在多个系统下运行(java虚拟机-JVM)解释性语言:编译好的代码需要解释器来执行JVM-JavavirtualmachineJDK包含JVM​ -运行->JVMforLinux​ ......
  • 基于微信小程序的使命召唤游戏助手的设计与实现(Java+Mysql+万字文档+ppt+系统源码+数
    目 录1绪  论1.1开发背景1.2国内外研究现状和发展趋势综述1.3开发设计的意义及研究方向2系统开发技术2.1JAVA编程语言2.2springboot框架2.3IDEA介绍2.4B/S架构2.5MySQL数据库介绍2.6微服务架构2.7微服务架构的优势3系统分析3.1整体分析......
  • 【Java】深入理解Java中的多线程同步机制
    一、多线程的数据不一致    当多个线程同时运行时,线程的调度由操作系统决定,程序本身无法决定。因此,任何一个线程都有可能在任何指令处被操作系统暂停,然后在某个时间段后继续执行。    这个时候,一个在单线程模型下不存在的问题就会发生:如果多个线程同时读写共享......
  • Java 双括号初始化(匿名内部类初始化)
    原文:Java:双括号初始化/匿名内部类初始化法ArrayList可以这样初始化://新建一个列表并赋初值A、B、CArrayList<String>list=newArrayList<String>(){{add("A");add("B");add("C");}};还有其他集合比如HashMap的初始化:Mapmap=newHashMap()......
  • 60.《Java集合框架-List-Set-Map》
    此篇所写不知道你们是否在网页开发的时候当看到要写Map集合什么HashMap之类的突然蒙了虽然之前学过突然让你调用方法懵了所以在此总结一下以备后需对比数组可存储任意类型对象且存储长度是可以变的集合类乃内存层面对数据进行存储数据库是持久层断电后仍长期存在......
  • java的方法和数组
    什么是方法呢?就类似c语言的函数                            返回类型 方法名   形式参数列表方法名最好使用小驼峰的形式,在java中方法不可以嵌套使用, 方法的调用:就是在main方法里面写上调用的方法名加......
  • 重生之我在Java世界------学单例设计模式
    什么是单例设计模式?单例模式是面向对象编程中最简单却又最常用的设计模式之一。它的核心思想是确保一个类只有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的原理、常见实现方法、优缺点,以及在使用过程中可能遇到的陷阱。单例模式的核心原理单例模式的实现主要......
  • 基于springboot的图书商城管理系统。Javaee项目,springboot项目。
    演示视频:基于springboot的图书商城管理系统。Javaee项目,springboot项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+Maven+Layui+Thymeleaf来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构的Web系统。界面简洁......
  • Springboot宠物领养管理系统。Javaee项目。Springboot项目。
    演示视频:Springboot宠物领养管理系统。Javaee项目。Springboot项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+Vue+Maven来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构的Web系统。界面简洁,操作简单。系统......