Java编程模型:VO,BO,PO,DO,DTO

Java编程模型是一种在软件开发中帮助组织和管理代码的框架。其中,VO(Value Object),BO(Business Object),PO(Persistent Object),DO(Domain Object),以及DTO(Data Transfer Object)是一些关键概念,它们在不同层次和阶段起到重要作用。

Value Object(VO)

Value Object是Java编程模型中的基础概念之一。它主要用于表示简单的数据结构,不包含任何业务逻辑。VO的设计目的是存储和传递数据,通常是不可变的。让我们通过一个例子来了解VO的基本结构:

public class AddressVO {
    private String street;
    private String city;
    private String zipCode;

    // 构造函数、getter方法等
}

在这个例子中,AddressVO包含了街道、城市和邮政编码等简单数据,这些数据用于描述地址,而且AddressVO本身不包含业务逻辑。

使用VO的好处之一是它可以增加代码的清晰度。将数据封装在VO中,使得代码更易读、更易维护。此外,VO的不可变性可以提高代码的安全性,防止意外的修改。

Business Object(BO)

Business Object(BO)是Java编程模型中负责处理业务逻辑的组件。它表示业务实体,并包含了与业务相关的处理规则。BO通常协调不同的业务对象,执行业务操作并处理业务规则。

为了更好地理解BO的概念,我们将创建一个简单的购物车业务对象,其中包含添加商品到购物车的业务逻辑。

public class ShoppingCartBO {
    private List<ProductPO> cartItems;

    public void addToCart(ProductPO product, int quantity) {
        // 简化的添加商品到购物车的业务逻辑
        for (int i = 0; i < quantity; i++) {
            cartItems.add(product);
        }
    }

    // 其他业务方法
}

在这个例子中,ShoppingCartBO负责处理购物车的业务逻辑,包括将商品添加到购物车的操作。BO通常会涉及到多个PO(Persistent Object)或其他BO的协同工作,以执行更复杂的业务操作。

BO在系统中起到了组织业务逻辑的关键作用,它可以在服务层或应用层中调用其他业务对象,使得系统的业务逻辑更具可维护性和可扩展性。

Persistent Object(PO)

Persistent Object(PO)是与数据库表结构相对应的对象,用于在应用程序和数据库之间持久化数据。PO通常是可持久化的,它映射到数据库表的行,并包含与数据库交互的方法。

我们将创建一个简单的ProductPO(产品)作为示例,演示如何设计一个Persistent Object。

@Entity
@Table(name = "products")
public class ProductPO {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private double price;

    // 其他属性和getter、setter方法
}

在这个例子中,ProductPO使用JPA(Java Persistence API)注解来标识它与数据库表的映射关系。它包含了产品的基本信息,如名称和价格。

Persistent Object的设计旨在与数据库进行交互,因此通常包含用于持久化操作的方法。这使得开发人员可以通过PO来访问和操作数据库中的数据,而不必直接处理SQL语句。

Domain Object(DO)

Domain Object(DO)是领域模型中的核心对象,它包含业务逻辑和领域规则。DO通常表示业务中的实体,具有处理业务逻辑的能力,并与其他领域对象协同工作。

我们将创建一个简单的OrderDO(订单)作为示例,演示如何设计一个Domain Object。

public class OrderDO {
    private List<ProductPO> products;
    private CustomerVO customer;

    public double calculateTotal() {
        // 计算订单总金额的业务逻辑
        double total = 0;
        for (ProductPO product : products) {
            total += product.getPrice();
        }
        return total;
    }

    // 其他业务方法
}

在这个例子中,OrderDO表示一个订单,它包含了一组产品(ProductPO)和一个顾客(CustomerVO)。calculateTotal方法演示了一个简单的业务逻辑,即计算订单的总金额。

Domain Object在整个应用程序中扮演着核心角色,它包含了与业务相关的逻辑和规则。DO通常由BO或服务层调用,用于执行具体的业务操作。

Data Transfer Object(DTO)

Data Transfer Object(DTO)是用于在系统内部或不同系统之间传递数据的对象。DTO的设计旨在减少数据传输的开销,通常只包含必要的字段,而不包含业务逻辑。DTO用于在层之间传递数据,使得系统更加灵活和可维护。

我们将创建一个简单的OrderDTO(订单传输对象)作为示例,演示如何设计一个DTO。

public class OrderDTO {
    private Long orderId;
    private List<ProductDTO> products;
    private CustomerDTO customer;

    // 构造函数、getter、setter等
}

在这个例子中,OrderDTO包含了订单的基本信息,如订单ID、产品列表和顾客信息。DTO通常不包含业务逻辑,而是专注于传递数据。

DTO在系统架构中的作用很重要,它可以用于在不同层之间传递数据,如在控制器和服务层之间、服务层和持久层之间等。通过使用DTO,可以实现松耦合的系统设计。

综合应用

综合运用这些概念,我们可以构建一个简单的电子商务系统来演示它们的使用。

考虑一个在线商店的场景,我们需要处理商品、订单和顾客信息。

  • Value Object(VO):使用VO表示简单的数据结构,比如AddressVO用于表示顾客的地址。
public class AddressVO {
    private String street;
    private String city;
    private String zipCode;

    // 构造函数、getter方法等
}
  • Business Object(BO):创建ShoppingCartBO用于处理购物车业务逻辑,比如添加商品到购物车。
public class ShoppingCartBO {
    private List<ProductPO> cartItems;

    public void addToCart(ProductPO product, int quantity) {
        // 简化的添加商品到购物车的业务逻辑
        for (int i = 0; i < quantity; i++) {
            cartItems.add(product);
        }
    }

    // 其他业务方法
}
  • Persistent Object(PO):使用PO来映射数据库表,比如ProductPO用于表示商品信息。
@Entity
@Table(name = "products")
public class ProductPO {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
    private double price;

    // 其他属性和getter、setter方法
}
  • Domain Object(DO):创建OrderDO用于处理订单的业务逻辑,比如计算订单总金额。
public class OrderDO {
    private List<ProductPO> products;
    private CustomerVO customer;

    public double calculateTotal() {
        // 计算订单总金额的业务逻辑
        double total = 0;
        for (ProductPO product : products) {
            total += product.getPrice();
        }
        return total;
    }

    // 其他业务方法
}
  • Data Transfer Object(DTO):设计OrderDTO用于在系统内传递订单信息。
public class OrderDTO {
    private Long orderId;
    private List<ProductDTO> products;
    private CustomerDTO customer;

    // 构造函数、getter、setter等
}

总结

Java编程模型中的VO,BO,PO,DO,DTO提供了一种结构化和组织代码的方法。通过合理运用这些概念,可以使代码更具可读性、可维护性和可扩展性。在实际项目中,根据需求和架构设计,合理选择和运用这些概念将有助于构建清晰、高效的Java应用程序。


相关文章

  • SpringBoot底层原理

    springboot3.x中,META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中,配置了需要创建Bean对象的全类名。当Springboot项目启动后,Springboot中的一些配置类,bean对象就会自动存入到IOC容器中,不需要我们手动去申明。,它负责管理Spring应用程序中所有的bean,同时提供了一些方法来获取Bean,注册Bean,是整个Spring应用的核心。

  • C# 实现网页内容保存为图片并生成压缩包

    通过动态页面技术,可以实现简历配置后的网页内容输出,但制作对应的各种模板会遇到开发效率和服务跟进的问题。为了保障原样输出,折中而简单的方案就是将动态输出的页面转化为图片格式。

  • 五种多目标优化算法(MSSA、MOJS、NSWOA、MOPSO、MOAHA)性能对比(提供MATLAB代码)

    多目标优化算法是用于解决具有多个目标函数的优化问题的一类算法。其求解过程可以分为以下几个步骤:1. 定义问题:首先需要明确问题的目标函数和约束条件。多目标优化问题通常涉及多个目标函数,这些目标函数可能是相互矛盾的,因此需要进行权衡和平衡。2. 生成初始解集:通过某种方式生成初始解集,可以是随机生成、根据经验生成或者使用已有的解集。3. 评估解集:对初始解集中的每个解进行评估,计算其在各个目标函数上的值。评估方法可以根据具体问题选择,例如计算目标函数值、计算约束违反程度等。

  • SQL实现模糊查询的四种方法总结

    SQL实现模糊查询的四种方法总结

  • 【C#小知识】c#中的delegate(委托)和event(事件)

    今天来介绍一下delegate和event。delegate在c#中可以定义一个函数类型,可以将函数作为一个对象来使用。event在c#中则可以看做一个函数的集合,event中包含了一个或多个函数。

  • Spring两大核心思想:IOC和AOP

    1.先自定义一个注解@Target(ElementType.METHOD) //作用范围 此处是方法@Retention(RetentionPolicy.RUNTIME) //生命周期 此处是运行时2.在切点表达式中加入该注解@Aspect@Component@Slf4j@Around(&quot;@annotation(com.example.demo.aspect.TestAnnotation)&quot;) //此处加自定义注解log.info(&quot;around继续&quot;);try {

  • SpringCloud-搭建Nacos配置中心

    本文详细介绍了如何在Spring Cloud项目中使用Nacos实现配置管理。首先,通过简洁的步骤指导了Nacos的安装和配置。然后,通过在项目中引入Nacos的依赖和配置,实现了与Nacos配置中心的连接。在Nacos控制台上演示了如何新建配置,并通过Spring Cloud项目实现了动态读取配置的操作。这种灵活的配置管理方案为微服务架构提供了高度可维护性和实时性的优势,使得项目能够在运行时动态调整配置,而无需重启服务

  • C#使用重载方法实现不同类型数据的计算

    为了避免异常,可以先使用Decimal.Parse(string)方法将字符串转换为小数,然后再使用Convert.ToInt32(decimal)方法将小数转换为整数。如果一个类中存在两个以上的同名方法,并且方法的参数类型、个数或者顺序不同,当调用这样的方法时,编译器会根据传入的参数自动进行判断,决定调用哪个方法。例如,字符串是&quot;123.456&quot;,包含非数字字符&quot;.&quot;。重载方法就是方法名称相同,但是每个方法中参数的数据类型、个数或顺序不同的方法。如果字符串包含非数字字符,例如小数点,该方法将引发异常。

  • 小程序 自定义组件和生命周期

    类似vue或者react中的自定义组件⼩程序允许我们使⽤⾃定义组件的⽅式来构建⻚⾯。类似于页面,一个自定义组件由 json wxml wxss js 4个文件组成可以在微信开发者⼯具中快速创建组件的⽂件结构在⽂件夹内 components/myHeader ,创建组件 名为 myHeader⾸先要在⻚⾯的 json ⽂件中进⾏引⽤声明。还要提供对应的组件名和组件路径index.wxml// 引用声明// 要使用的组件的名称 // 组件的路径&lt; view &gt; _微信小程序 自定义组件生命周期

  • Makefile 和 Bash 脚本之间区别和联系

    在 Makefile 中可以调 Bash 脚本,或在 Makefile 中直接写入 Bash 命令。这使得在构建过程中执行更复杂的任务成为可能。Makefile和Bash脚本由于它们的设计目标和用途不同,它们在基本结构、命令执行、通配符使用、错误处理等方面存在显著的差异。了解这些差异对于正确编写和理解Makefile和Bash脚本至关重要。Makefile主要用于编译和构建软件项目,而Bash脚本则更广泛地应用于系统管理和自动化任务。在实际工作中,两者可以结合使用,以创建一个完整、自动化的构建和部署。

  • C#:Sleep() 和 Wait() 有什么区别

    Sleep() 和 Wait() 是两个不同的方法,用于控制线程的执行。

  • DockerUI如何部署结合内网穿透实现公网环境管理本地docker容器

    DockerUI是一个docker容器镜像的可视化图形化管理工具。DockerUI可以用来轻松构建、管理和维护docker环境。它是完全开源且免费的。基于容器安装方式,部署方便高效,浏览和维护docker单节点或集群节点worker和manager。DockerUI具有易于使用的界面。它不需要记住 docker 指令。只需下载镜像即可立即加入并完成部署。使用DockerUI并结合cpolar内网穿透可以更加轻松的管理docker和swarm,实现后台公网访问并管理,视觉性更加直观,后台开发更加便利。

  • C++ STL库详解:容器适配器stack和queue的结构及功能

    详细介绍了c++中的stack和queue两大容器适配器的功能、接口与使用方法,通过与vector、string等容器的配合使用来实现特定的功能。介绍了stack与queue的底层默认容器deque的原理及结构以及它的优缺陷。

  • C语言——深入理解指针(1)

    我们已经知道,32内存位计算器有32条地址总线,每条线有1和0两个状态,那么一个内存的编号就有32条地址线表示,一条地址线占一个比特位,那么32条地址线就是32个比特位,因此就是4个字节。,可以这么理解,32位的计算器有32条这样的线,每个线有两种状态,分别是0和1,那么32根线一共能表示2^32种状态,这样的每个状态就是我们的一个地址,他们分别储存在不同的硬件上,地址信息被下达给内存,在内存上,就可以找到该地址对应的数据,将数据在通过数据总线传入CPU内寄存器。当然,需要我们了解一下计算机的进制转换,

  • C,C++,C# 的区别

    C#是一种面向对象的编程语言,由微软开发。总的来说,C适合系统级编程和嵌入式开发,C++适合大型项目和需要高性能的应用程序开发,而C#适合Windows应用程序开发和.NET平台。C++是一种面向对象的编程语言,是C的扩展。C++也具有更强大的标准库,以支持更多的功能和任务。它具有简单的语法和较小的标准库,适合于高效的低级编程和处理底层细节。C++具有更高的性能和更好的底层控制能力,但开发过程中更复杂。C#的开发速度更快,代码更易于维护,但性能可能稍逊于C++。C,C++,C# 是三种不同的编程语言。

  • 一些著名的软件都用什么语言编写?

    比如你的两个朋友与你分别玩用VB、Java、与C++编写的“跑跑卡丁车”,你玩C++编写的游戏已经跑玩结束了,发现你的两个朋友还没开始跑呢,那是相当的卡啊。备注:曾经在智能手机的操作系统(Windows Mobile)考虑掺点C#写的程序,比如软键盘,结果因为写出来的程序太慢,实在无法和别的模块合并,最终又回到C++重写。:2008 年推出:C语言(有传言说是用Java开发的操作系统,但最近刚推出原生的C语言SDK): 部分JAVA(对外接口),主要为C++ (开源,可下载其源代码)

  • Java把列表数据导出为PDF文件,同时加上PDF水印

    可以看到字体文件在jar目录下面是有的,但是发现classes后面多了个叹号。这是引入外部字体方式不对,后改用问题2参考文章的第三种写法就没问题了。网上都是说jar包的版本不对,导致的字体兼容性问题。换了jar包版本发现没效果,后来索性直接把字体下载到本地直接引入。字体文件资源自己百度,直接搜。

  • HarmonyOS 鸿蒙应用开发( 六、实现自定义弹窗CustomDialog)

    自定义弹窗(CustomDialog)可用于广告、中奖、警告、软件更新等与用户交互响应操作。开发者可以通过CustomDialogController类显示自定义弹窗。具体用法请参考自定义弹窗。

  • java获取双异步返回值时,如何保证主线程不阻塞?

    CompletableFuture的异步执行通过ForkJoinPool实现,ForkJoinPool在于可以充分利用多核CPU的优势,把一个任务拆分成多个小任务,把多个小任务放到多个CPU上并行执行,当多个小任务执行完毕后,再将其执行结果合并起来。

  • Vue3前端开发,如何获取组件内dom对象以及子组件的属性和方法

    传统的vue2里面,我们访问dom时的代码,还是的借助于this对象的【this.$refs.userName】。毕竟,父子组件之间,各司其职。下面展示的是,借助于ref来访问子组件的实例对象。(声明:默认情况下,子组件内部的属性和方法,不会主动对外暴漏的。Vue3前端开发,借助Ref来获取组件内dom对象,借助defineExpose编译宏可以获取到子组件的属性和方法。如图,确实是可以拿到子组件的属性和方法了,如果不使用编译宏,是访问不到的。这个是子组件里面的内容,我们定义了一个常量,一个方法。

  • 掌握Spring MVC拦截器整合技巧,实现灵活的请求处理与权限控制!

    在这个方法中可以通过返回值来决定是否要进行放行,我们可以把业务逻辑放在该方法中,如果满足业务则返回true放行,不满足则返回false拦截。方法,如果返回true,则代表放行,会执行原始Controller类中要请求的方法,如果返回false,则代表拦截,后面的就不会再执行了。(7)如果满足规则,则进行处理,找到其对应的controller类中的方法进行执行,完成后返回结果。配置多个后,执行顺序是什么?(5)在找到具体的方法之前,我们可以去配置过滤器(可以配置多个),按照顺序进行执行。