Я разобрал кое-какую архитектуру Java и материалы интервью (микросервисы, кластеры, распределенное, промежуточное ПО и т.д.), а друзья, кому нужно, могут обратить внимание на официальный аккаунт [Внутренние дела Программиста], и получить самостоятельно без всяких рутин
Отличный обзор:
- Интервьюер немного смутился, сказав 9 распределенных методов генерации ID на одном дыхании.
- Правила сопоставления переадресации Nginx, которые должны знать бэкенд-программисты
- Функция распознавания лиц на основе Java (с исходным кодом)
- Назовите 6 сценариев сбоя аннотации @Transactional за один раз
- Рекомендуемые сухие товары! 13 бесплатных сайтов о технических электронных книгах, которые должен иметь каждый программист
Во-первых, традиционный способ реализации
Давайте сначала поговорим о конкретных потребностях: у компании много порталов продвижения, и каждый источник заказа обрабатывается со специальной логикой при оформлении заказа, и источник может добавляться каждые два дня.
Тогда код по традиционному способу реализации выглядит следующим образом:
public class OrderServiceImpl implements IOrderService {
@Override
public String handle(OrderDTO dto) {
String type = dto.getType();
if ("1".equals(type)) {
return "处理普通订单";
} else if ("2".equals(type)) {
return "处理团购订单";
} else if ("3".equals(type)) {
return "处理促销订单";
}
return null;
}
}
Почему он должен быть таким раздутым? Многие коллеги скажут: «Ой, никак, бизнес тугой, поэтому оперативность разработки быстрая и легкая». Это правда, что во многих случаях деловая сторона действительно заставляет вас догонять период строительства, как призрак, и вы хотите быстро реализовать функцию, это лучший выбор.
Код выше вроде бы достаточно понятен, но если я вам скажу, что в компании сотни источников заказов, представьте себе такое раздутое if-else, что вы почувствуете, пролистывая код?
Во-вторых, реализация шаблона стратегии
Шаблон стратегииoop
Одним из наиболее известных шаблонов проектирования в , является абстракция поведения метода, которую можно классифицировать как поведенческий дизайн.oop
серединаinterface
Классическое приложение. Его функции просты и функциональны, и это один из моих любимых режимов.
Шаблон стратегии определяет семейство алгоритмов с общим поведением, каждый из которых инкапсулирован, может заменяться друг другом и изменяется независимо от клиента.
Многие люди говорят: шаблоны проектирования Java были пересказаны много раз, но это не дело написания if-else в повседневной жизни, и оно вообще не используется. На самом деле дело не в том, что он не используется или используется не в том месте!
1. Используйте сценарии режима стратегии:
- Существует несколько способов решения одной и той же проблемы, только когда конкретное поведение отличается;
- Когда необходимо безопасно инкапсулировать несколько операций одного типа;
- Когда существует несколько подклассов одного и того же абстрактного класса, и клиенту необходимо использовать if-else или switch-case для выбора конкретного подкласса.
Это модифицированный код, использующий режим стратегии:
@Component
@OrderHandlerType(16)
public class DispatchModeProcessor extends AbstractHandler{
@Autowired
private OrderStencilledService orderStencilledService;
@Override
public void handle(OrderBO orderBO) {
/**
* 订单完结广播通知(1 - 支付完成)
*/
orderStencilledService.dispatchModeFanout(orderBO);
/**
* SCMS 出库单
*/
orderStencilledService.createScmsDeliveryOrder(orderBO.getPayOrderInfoBO().getLocalOrderNo());
}
}
Каждый источник заказа имеет свой отдельный класс реализации логики, и каждый раз, когда вам нужно добавить источник заказа, создайте новый класс реализации напрямую, измените@OrderHandlerType(16)
Значения достаточно, и вам не нужно раз и навсегда проходить через сотни строк!
2. Конкретный процесс реализации:
1. Определите аннотацию, которая идентифицирует источник заказа
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface OrderHandlerType {
int value() default 0;
}
2. Абстрагируйте конкретный бизнес-процессор
public abstract class AbstractHandler {
abstract public void handle(OrderBO orderBO);
}
3. Сканирование запуска проектаhandler
Вход
@Component
@SuppressWarnings({"unused","rawtypes"})
public class HandlerProcessor implements BeanFactoryPostProcessor {
private String basePackage = "com.ecej.order.pipeline.processor";
public static final Logger log = LoggerFactory.getLogger(HandlerProcessor.class);
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
Map<Integer,Class> map = new HashMap<Integer,Class>();
ClassScaner.scan(basePackage, OrderHandlerType.class).forEach(x ->{
int type = x.getAnnotation(OrderHandlerType.class).value();
map.put(type,x);
});
beanFactory.registerSingleton(OrderHandlerType.class.getName(), map);
log.info("处理器初始化{}", JSONObject.toJSONString(beanFactory.getBean(OrderHandlerType.class.getName())));
}
}
4. Инструменты, необходимые для сканирования
public class ClassScaner {
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
private final List<TypeFilter> includeFilters = new ArrayList<TypeFilter>();
private final List<TypeFilter> excludeFilters = new ArrayList<TypeFilter>();
private MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
/**
* 添加包含的Fiter
* @param includeFilter
*/
public void addIncludeFilter(TypeFilter includeFilter) {
this.includeFilters.add(includeFilter);
}
/**
* 添加排除的Fiter
* @param includeFilter
*/
public void addExcludeFilter(TypeFilter excludeFilter) {
this.excludeFilters.add(excludeFilter);
}
/**
* 扫描指定的包,获取包下所有的Class
* @param basePackage 包名
* @param targetTypes 需要指定的目标类型,可以是pojo,可以是注解
* @return Set<Class<?>>
*/
public static Set<Class<?>> scan(String basePackage,
Class<?>... targetTypes) {
ClassScaner cs = new ClassScaner();
for (Class<?> targetType : targetTypes){
if(TypeUtils.isAssignable(Annotation.class, targetType)){
cs.addIncludeFilter(new AnnotationTypeFilter((Class<? extends Annotation>) targetType));
}else{
cs.addIncludeFilter(new AssignableTypeFilter(targetType));
}
}
return cs.doScan(basePackage);
}
/**
* 扫描指定的包,获取包下所有的Class
* @param basePackages 包名,多个
* @param targetTypes 需要指定的目标类型,可以是pojo,可以是注解
* @return Set<Class<?>>
*/
public static Set<Class<?>> scan(String[] basePackages,
Class<?>... targetTypes) {
ClassScaner cs = new ClassScaner();
for (Class<?> targetType : targetTypes){
if(TypeUtils.isAssignable(Annotation.class, targetType)){
cs.addIncludeFilter(new AnnotationTypeFilter((Class<? extends Annotation>) targetType));
}else{
cs.addIncludeFilter(new AssignableTypeFilter(targetType));
}
}
Set<Class<?>> classes = new HashSet<Class<?>>();
for (String s : basePackages){
classes.addAll(cs.doScan(s));
}
return classes;
}
/**
* 扫描指定的包,获取包下所有的Class
* @param basePackages 包名
* @return Set<Class<?>>
*/
public Set<Class<?>> doScan(String [] basePackages) {
Set<Class<?>> classes = new HashSet<Class<?>>();
for (String basePackage :basePackages) {
classes.addAll(doScan(basePackage));
}
return classes;
}
/**
* 扫描指定的包,获取包下所有的Class
* @param basePackages 包名
* @return Set<Class<?>>
*/
public Set<Class<?>> doScan(String basePackage) {
Set<Class<?>> classes = new HashSet<Class<?>>();
try {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+ ClassUtils.convertClassNameToResourcePath(
SystemPropertyUtils.resolvePlaceholders(basePackage))+"/**/*.class";
Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);
for (int i = 0; i < resources.length; i++) {
Resource resource = resources[i];
if (resource.isReadable()) {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
if ((includeFilters.size() == 0 && excludeFilters.size() == 0)|| matches(metadataReader)) {
try {
classes.add(Class.forName(metadataReader.getClassMetadata().getClassName()));
} catch (ClassNotFoundException ignore) {}
}
}
}
} catch (IOException ex) {
throw new RuntimeException("I/O failure during classpath scanning", ex);
}
return classes;
}
/**
* 处理 excludeFilters和includeFilters
* @param metadataReader
* @return boolean
* @throws IOException
*/
private boolean matches(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return false;
}
}
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, this.metadataReaderFactory)) {
return true;
}
}
return false;
}
}
5. Создайте абстрактные классы в соответствии с типами
@Component
public class HandlerContext {
@Autowired
private ApplicationContext beanFactory;
public AbstractHandler getInstance(Integer type){
Map<Integer,Class> map = (Map<Integer, Class>) beanFactory.getBean(OrderHandlerType.class.getName());
return (AbstractHandler)beanFactory.getBean(map.get(type));
}
}
6. Позвоните в подъезд, вот полученное мной сообщение MQ, которое будет обрабатывать несколько источников заказов в пакетах
@Component
@RabbitListener(queues = "OrderPipelineQueue")
public class PipelineSubscribe{
private final Logger LOGGER = LoggerFactory.getLogger(PipelineSubscribe.class);
@Autowired
private HandlerContext HandlerContext;
@Autowired
private OrderValidateService orderValidateService;
@RabbitHandler
public void subscribeMessage(MessageBean bean){
OrderBO orderBO = JSONObject.parseObject(bean.getOrderBO(), OrderBO.class);
if(null != orderBO &&CollectionUtils.isNotEmpty(bean.getType()))
{
for(int value:bean.getType())
{
AbstractHandler handler = HandlerContext.getInstance(value);
handler.handle(orderBO);
}
}
}
}
принимающая организацияMessageBean
код класса
public class MessageBean implements Serializable {
private static final long serialVersionUID = 5454831432308782668L;
private String cachKey;
private List<Integer> type;
private String orderBO;
public MessageBean(List<Integer> type, String orderBO) {
this.type = type;
this.orderBO = orderBO;
}
}
Преимущества и недостатки режима стратегии
преимущество
- Легко расширяется, добавление новой стратегии требует только добавления определенного класса стратегии, в основном не нужно изменять исходный код в соответствии с принципом открытого и закрытого
- Избегайте использования нескольких операторов условного выбора, чтобы полностью отразить идею объектно-ориентированного проектирования. Классы стратегии можно свободно переключать. Поскольку все классы стратегии реализуют один и тот же интерфейс, их можно свободно переключать между собой.
- Каждый класс политики использует один класс политики, который соответствует принципу единой ответственности.Клиент отделен от алгоритма политики, и оба полагаются на абстрактный интерфейс политики, который соответствует принципу инверсии зависимостей.
- Клиенту не нужно знать, какие классы политик доступны, что соответствует принципу минимальных знаний.
недостаток
- Режим стратегии, когда слишком много алгоритмов стратегии, это вызовет много классов стратегии
- Клиент не знает, какие существуют классы политик, и не может решить, какой класс политик использовать.Это можно решить, инкапсулировав общий общедоступный пакет или рассмотрев возможность использования
IOC容器
и依赖注入
способ решить.
Ниже приведена часть класса стратегии источника ордера.Надо сказать, что классов стратегий действительно много.
Суммировать:
У всего есть две стороны,if-else
Несколько уровней вложенности также имеют свои преимущества и недостатки:
if-else
Преимущество этого в том, что это просто, если вы хотите быстро перебирать функции, вложенность логики меньше и больше не будет увеличиваться.if-else
Более того, недостатки тоже очевидны, код раздут, громоздок и не прост в сопровождении.
策略模式
Отделите логику каждой сцены для обслуживания.Один и тот же абстрактный класс имеет несколько подклассов, которые необходимо использовать.if-else
илиswitch-case
При выборе конкретного подкласса рекомендуется выбрать режим стратегии, его недостатком является то, что он будет генерировать больше файлов классов стратегий.
Два метода реализации имеют свои преимущества и недостатки.Как выбрать, зависит от конкретного бизнес-сценария или от того, что режим построения предложений не используется для использования и должен использоваться в наиболее подходящей позиции.
Сегодня так много нужно сказать, если эта статья была вам полезна, я надеюсь получить от вас лайк 👍
Ваше одобрение является движущей силой для моего письма!
Небольшие преимущества:
Сотни различных технических электронных книг пересылаются друг другу, тсс~,бесплатноОтправить его друзьям. Ответ публичного аккаунта【666] Самовывоз
Я разобрал кое-какую архитектуру Java и материалы интервью, а нуждающиеся друзья могут обратить внимание на паблик-аккаунт [Внутри программатора】