Design Patterns
Exception Handling Methods
Global Exception Handling Class ExceptionHandlingController
package com.whalefall.learncases.exception;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.sql.SQLException;
/**
* @author WhaleFall
* @create 2022-05-28 10:41
* codes copy from => https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
*/
@Slf4j
@ControllerAdvice// Specify as global exception handling
public class ExceptionHandlingController {
// Specify name of a specific view that will be used to display the error:
@ExceptionHandler(SQLException.class)
public String databaseError() {
// Nothing to do. Returns the logical view name of an error page, passed
// to the view-resolver(s) in usual way.
// Note that the exception is NOT available to this view (it is not added
// to the model) but see "Extending ExceptionHandlerExceptionResolver"
// below.
return "databaseError";
}
// Total control - setup a model and return the view name yourself. Or
// consider subclassing ExceptionHandlerExceptionResolver (see below).
@ExceptionHandler(Exception.class)
public ModelAndView handleError(HttpServletRequest req, Exception ex) {
log.error("Request: " + req.getRequestURL() + " raised " + ex);
ModelAndView mav = new ModelAndView();
mav.addObject("exception", ex);
mav.addObject("url", req.getRequestURL());
mav.setViewName("error");
return mav;
}
}
Interface-Based Design
Interface Class
package com.whalefall.learncases.design;
/**
* @author WhaleFall
* @create 2022-07-25 19:21
*/
public interface IService {
boolean doService();
boolean doServiceBefore();
boolean doServiceAfter();
void doLog();
}
Interface Implementation Class
package com.whalefall.learncases.design;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author WhaleFall
* @create 2022-07-24 6:34
*/
@Slf4j
@Component
public class AService implements IService {
@Override
public boolean doService() {
log.info("do A service");
if (true)
throw new RuntimeException("Exception msg1");
return true;
}
@Override
public boolean doServiceBefore() {
return false;
}
@Override
public boolean doServiceAfter() {
return false;
}
@Override
public void doLog() {
if (true)
throw new RuntimeException("Exception msg2");
log.error("A1 do log");
}
}
Core Process Encapsulation
- Singleton Template Design Pattern
Singleton Template Design Pattern
package com.whalefall.learncases.design;
import lombok.extern.slf4j.Slf4j;
import javax.validation.constraints.NotNull;
import java.util.function.Consumer;
/**
* @author WhaleFall
* @create 2022-07-24 6:26
*/
@Slf4j
public class SProcessService {
private SProcessService() {
}
private static class SProcessServiceHolder {
private static final SProcessService INSTANCE = new SProcessService();
}
public static SProcessService getInstance() {
return SProcessServiceHolder.INSTANCE;
}
public boolean handle(IService service, Consumer<Exception> exceptionConsumer) {
serviceBefore(service);
service(service, exceptionConsumer);
serviceAfter(service);
log(service, exceptionConsumer);
return true;
}
private void serviceAfter(@NotNull IService service) {
service.doServiceAfter();
}
private void serviceBefore(@NotNull IService service) {
service.doServiceBefore();
}
private void service(@NotNull IService service, Consumer<Exception> exceptionConsumer) {
try {
service.doService();
} catch (Exception e1) {
exceptionConsumer.accept(e1);
throw e1;
}
}
private void log(@NotNull IService service, Consumer<Exception> exceptionConsumer) {
try {
service.doLog();
} catch (Exception e2) {
log.error("failed do log");
exceptionConsumer.accept(e2);
}
}
}
- Inject into Container
Inject into Container
package com.whalefall.learncases.design;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.validation.constraints.NotNull;
import java.util.function.Consumer;
/**
* @author WhaleFall
* @create 2022-07-24 6:26
*/
@Component
@Slf4j
public class ProcessService {
public boolean handle(IService service, Consumer<Exception> exceptionConsumer) {
serviceBefore(service);
service(service, exceptionConsumer);
serviceAfter(service);
log(service, exceptionConsumer);
return true;
}
private void serviceAfter(@NotNull IService service) {
service.doServiceAfter();
}
private void serviceBefore(@NotNull IService service) {
service.doServiceBefore();
}
private void service(@NotNull IService service, Consumer<Exception> exceptionConsumer) {
try {
service.doService();
} catch (Exception e1) {
exceptionConsumer.accept(e1);
throw e1;
}
}
private void log(@NotNull IService service, Consumer<Exception> exceptionConsumer) {
try {
service.doLog();
} catch (Exception e2) {
log.error("failed do log");
exceptionConsumer.accept(e2);
}
}
}
Calling Class
package com.whalefall.learncases.design;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author WhaleFall
* @create 2022-07-24 6:37
*/
@RestController
@Slf4j
public class ControllerA {
private IService service;
private ProcessService processService;
public ControllerA(IService service, ProcessService processService) {
this.service = service;
this.processService = processService;
}
@GetMapping("/testA")
public boolean getA(){
return processService.handle(service, e -> log.error(e.getMessage(), e));
}
}
DDD
Entity objects cannot be assigned directly, domain objects cannot be newed directly, factory methods and builder patterns should be used to implement.
Application Layer Responsibilities:
- Basic data validation
- Data conversion
- Security authentication
- Permission check
- Transaction control
- Message sending
Principles:
- If it is difficult to split, you can write the code to application service first.
- If you cannot confirm whether it is an entity or a value object, you can treat it as an entity first.
- Entity (has unique identifier, mutable state, has life cycle).
- Value Object (Address, Amount, Measurement, Date, Time, Color, Transaction Snapshot).
- Entities should not depend on Spring container.
Domain Object Relationship Handling
- Composition, Aggregation Relationships: One contains another; each object is a whole.
- Association Relationships: Non-composition, aggregation association relationships.
- Generalization Relationships: Inheritance.
Only business exceptions can be reported in SupportImpl.
Jar file FunctionalInterface can be extended by user implement class
FunctionalInterface.java
@Resource
private Custom customImpl;
/**
* Define {@link FunctionalInterface} in Jar package<br/>
* Of course, the usage class in Jar implements ApplicationContextAware, then gets the injected object of the application, and then writes where the function is triggered<br/>
* User defines implementation class and injects it into container.<br/>
* @param str function input parameter
*/
public void custom(String str) {
Consumer<Custom> consumer = custom -> custom.custom(str);
consumer.accept(customImpl);
}
Jar file FunctionalInterface can be extended by user implement class
Agreement
The code part of this work is licensed under Apache License 2.0 . You may freely modify and redistribute the code, and use it for commercial purposes, provided that you comply with the license. However, you are required to:
- Attribution: Retain the original author's signature and code source information in the original and derivative code.
- Preserve License: Retain the Apache 2.0 license file in the original and derivative code.
- Attribution: Give appropriate credit, provide a link to the license, and indicate if changes were made.
- NonCommercial: You may not use the material for commercial purposes. For commercial use, please contact the author.
- ShareAlike: If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.