文章目录
【Java设计模式】领域模型模式:构建强大的业务逻辑
一、概述
领域模型模式旨在在软件中创建一个与它所设计代表的现实世界系统相匹配的概念模型。它涉及使用丰富的领域对象,这些对象封装了与应用程序领域相关的数据和行为,确保业务逻辑集中化。
二、详细解释及实际示例
- 实际示例:
- 考虑一个使用领域模型设计模式的在线书店系统。在这个系统中,各种领域对象如
Book
、Author
、Customer
和Order
封装了核心业务逻辑和规则。例如,Book
对象包含标题、作者、价格和库存数量等属性,以及管理这些属性的方法。Order
对象管理订单细节、计算总价并验证库存可用性。这种方法确保业务逻辑集中在领域对象中,使系统更具模块化、更易于维护和扩展,因为可以添加新功能。
- 考虑一个使用领域模型设计模式的在线书店系统。在这个系统中,各种领域对象如
- 通俗解释:
- 领域模型是一个包含行为和数据的领域对象模型。
三、Java中领域模型模式的编程示例
假设我们需要构建一个电子商务Web应用程序。在分析需求时,您会注意到有几个名词会反复提及。这就是您的Customer
和客户寻找的Product
。这两个是您的特定领域类,每个类都将包含一些特定于其领域的业务逻辑。
在电子商务应用程序的示例中,我们需要处理想要购买产品并在需要时退货的客户的领域逻辑。我们可以使用领域模型模式并创建类Customer
和Product
,其中该类的每个实例都包含行为和数据,并仅表示基础表中的一条记录。
public class Customer {
// 客户属性和方法
public class Product {
// 产品属性和方法
数据访问对象(DAOs):这些对象提供了对数据库的抽象接口。它们用于检索领域实体并将更改保存回数据库。在提供的代码中,CustomerDaoImpl
和ProductDaoImpl
是DAOs。
public class CustomerDaoImpl implements CustomerDao {
// 实现CustomerDao接口中定义的方法
public class ProductDaoImpl implements ProductDao {
// 实现ProductDao接口中定义的方法
领域逻辑:这被封装在领域实体中。例如,Customer
类具有buyProduct
和returnProduct
等方法,这些方法代表客户可以执行的操作。
public class Customer {
// 其他属性和方法...
public void buyProduct(Product product) {
// 购买产品的实现
}
public void returnProduct(Product product) {
// 退货产品的实现
}
应用程序:App
类使用领域实体及其方法来实现应用程序的业务逻辑。
public class App {
public static final String H2_DB_URL = "jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1";
public static final String CREATE_SCHEMA_SQL =
"CREATE TABLE CUSTOMERS (name varchar primary key, money decimal);"
+ "CREATE TABLE PRODUCTS (name varchar primary key, price decimal, expiration_date date);"
+ "CREATE TABLE PURCHASES ("
+ "product_name varchar references PRODUCTS(name),"
+ "customer_name varchar references CUSTOMERS(name));";
public static final String DELETE_SCHEMA_SQL =
"DROP TABLE PURCHASES IF EXISTS;"
+ "DROP TABLE CUSTOMERS IF EXISTS;"
+ "DROP TABLE PRODUCTS IF EXISTS;";
public static void main(String[] args) throws Exception {
// 创建数据源并创建客户、产品和购买表
final var dataSource = createDataSource();
deleteSchema(dataSource);
createSchema(dataSource);
// 创建客户
var customerDao = new CustomerDaoImpl(dataSource);
var tom =
Customer.builder()
.name("Tom")
.money(Money.of(USD, 30))
.customerDao(customerDao)
.build();
tom.save();
// 创建产品
var productDao = new ProductDaoImpl(dataSource);
var eggs =
Product.builder()
.name("Eggs")
.price(Money.of(USD, 10.0))
.expirationDate(LocalDate.now().plusDays(7))
.productDao(productDao)
.build();
var butter =
Product.builder()
.name("Butter")
.price(Money.of(USD, 20.00))
.expirationDate(LocalDate.now().plusDays(9))
.productDao(productDao)
.build();
var cheese =
Product.builder()
.name("Cheese")
.price(Money.of(USD, 25.0))
.expirationDate(LocalDate.now().plusDays(2))
.productDao(productDao)
.build();
eggs.save();
butter.save();
cheese.save();
// 显示客户每次购买后的资金余额
tom.showBalance();
tom.showPurchases();
// 购买鸡蛋
tom.buyProduct(eggs);
tom.showBalance();
// 购买黄油
tom.buyProduct(butter);
tom.showBalance();
// 尝试购买奶酪,但收到拒绝,因为他没有足够的钱
tom.buyProduct(cheese);
tom.showBalance();
// 退货黄油并拿回钱
tom.returnProduct(butter);
tom.showBalance();
// Tom现在可以购买奶酪,因为他有足够的钱,并且奶酪因为还有2天过期而有折扣
tom.buyProduct(cheese);
tom.save();
// 显示购物后的资金余额和购买记录
tom.showBalance();
tom.showPurchases();
}
private static DataSource createDataSource() {
var dataSource = new JdbcDataSource();
dataSource.setUrl(H2_DB_URL);
return dataSource;
}
private static void deleteSchema(DataSource dataSource) throws SQLException {
try (var connection = dataSource.getConnection();
var statement = connection.createStatement()) {
statement.execute(DELETE_SCHEMA_SQL);
}
}
private static void createSchema(DataSource dataSource) throws SQLException {
try (var connection = dataSource.getConnection();
var statement = connection.createStatement()) {
statement.execute(CREATE_SCHEMA_SQL);
}
}
程序输出:
12:17:23.834 [main] INFO com.iluwatar.domainmodel.Customer -- Tom balance: USD 30.00
12:17:23.836 [main] INFO com.iluwatar.domainmodel.Customer -- Tom didn't bought anything
12:17:23.841 [main] INFO com.iluwatar.domainmodel.Customer -- Tom want to buy Eggs($10,00)...
12:17:23.842 [main] INFO com.iluwatar.domainmodel.Customer -- Tom bought Eggs!
12:17:23.842 [main] INFO com.iluwatar.domainmodel.Customer -- Tom balance: USD 20.00
12:17:23.842 [main] INFO com.iluwatar.domainmodel.Customer -- Tom want to buy Butter($20,00)...
12:17:23.843 [main] INFO com.iluwatar.domainmodel.Customer -- Tom bought Butter!
12:17:23.843 [main] INFO com.iluwatar.domainmodel.Customer -- Tom balance: USD 0.00
12:17:23.843 [main] INFO com.iluwatar.domainmodel.Customer -- Tom want to buy Cheese($20,00)...
12:17:23.843 [main] ERROR com.iluwatar.domainmodel.Customer -- Not enough money!
12:17:23.843 [main] INFO com.iluwatar.domainmodel.Customer -- Tom balance: USD 0.00
12:17:23.843 [main] INFO com.iluwatar.domainmodel.Customer -- Tom want to return Butter($20,00)...
12:17:23.844 [main] INFO com.iluwatar.domainmodel.Customer -- Tom returned Butter!
12:17:23.844 [main] INFO com.iluwatar.domainmodel.Customer -- Tom balance: USD 20.00
12:17:23.844 [main] INFO com.iluwatar.domainmodel.Customer -- Tom want to buy Cheese($20,00)...
12:17:23.844 [main] INFO com.iluwatar.domainmodel.Customer -- Tom bought Cheese!
12:17:23.846 [main] INFO com.iluwatar.domainmodel.Customer -- Tom balance: USD 0.00
12:17:23.846 [main] INFO com.iluwatar.domainmodel.Customer -- Tom bought: Eggs - $10.00, Cheese - $20.00
四、何时在Java中使用领域模型模式
- 适用于具有丰富业务逻辑的复杂应用程序。
- 当业务逻辑或领域复杂性较高,需要一个紧密代表现实世界实体及其关系的模型时。
- 适用于领域专家参与开发过程以确保模型准确反映领域概念的应用程序。
五、领域模型模式在Java中的实际应用
- 企业应用程序(ERP、CRM系统)
- 金融系统(银行、交易平台)
- 医疗保健应用程序(患者记录管理)
- 电子商务平台(产品目录、购物车)
六、领域模型模式的优点和权衡
优点:
- 改进沟通:为开发人员和领域专家提供了一种共同语言,增强了理解和协作。
- 灵活性:将业务逻辑封装在领域实体中,使其更容易修改和扩展,而不会影响系统的其他部分。
- 可维护性:结构良好的领域模型可以简化应用程序随时间的维护和演进。
- 可重用性:领域类通常可以在同一领域的不同项目中重用。
权衡:
- 复杂性:可能会引入复杂性,特别是在简单应用程序中,领域模型可能过于复杂。
- 性能问题:具有复杂行为的丰富领域对象可能会导致性能瓶颈,需要仔细优化。
- 学习曲线:需要对领域有很好的理解,对于不熟悉领域概念的开发人员来说,可能会涉及陡峭的学习曲线。