Patrones de diseño: patrones compuestos (árboles de decisión)

1. Como a primera vista

        El modo combinación puede ser lo primero que se te ocurra es combinar dos módulos. De hecho, parece ser el caso, pero no es el caso. No hablemos tonterías. Para aprender algo nuevo, primero debes entender su concepto. Las reglas antiguas primero Sobre el concepto (de la Enciclopedia Baidu):

Modo compuesto_Enciclopedia Baidu Modo compuesto, que combina objetos en una estructura de árbol para representar la jerarquía "parte-todo". https://baike.baidu.com/item/%E7%BB%84%E5%90%88%E6%A8%A1%E5%BC%8F/1441281?fromModule=lemma_inlink

       Después de leer el concepto y pensarlo, es completamente diferente de lo que pensaba. Recientemente hablé sobre este patrón de diseño cuando valoro aprender patrones de diseño de Java. Es fácil de entender (sin oscuridad oficial), y saca la esencia de Compártalo con todos, la sugerencia para todos es que puede sentirse medio entendido después de leerlo de nuevo, pero lo encontrará repentinamente claro cuando lo escriba de nuevo.

2. Entrada

        Creo que todos han jugado con bloques de construcción o juguetes Lego, y cada parte tiene sus propias responsabilidades y funciones. Por ejemplo, un automóvil no puede andar solo con ruedas, debe estar compuesto por motor, chasis, carrocería, equipo eléctrico y otros componentes.

        El uso de la combinación de funciones ABCD para proporcionar servicios externos como este es similar al modo de combinación. ¿Cuáles son las características de la implementación del código? Entonces, ¿cuáles son los beneficios de usarlo para el proyecto? ¿Cuáles son los beneficios de unirse a él para el equipo? Tres preguntas del alma, tal vez tienes preguntas similares circulando en tu mente, como esta.

Solo una broma para que todos relajen su pensamiento tenso, pongámonos manos a la obra.

3. Pelar los capullos

3.1 Funciones de implementación

¿Qué? Todavía estás un poco confundido después de leer esto. De hecho, esto es un poco oficial. Si esto no es fácil de entender, puede mirar esta imagen:

Esto es probablemente fácil de explicar. Suponiendo que el producto tiene un requisito comercial, primero encontré al gerente. El gerente dijo que sé quién puede hacer esto. Encontré al líder del equipo A. Después de comprender las necesidades, el líder del equipo A asignó tareas específicas a los ingenieros correspondientes. ; Creo que después de leer lo que dije, probablemente tengas un concepto un poco borroso en tu mente, y ya estás ansioso por probarlo; no te preocupes, sigamos leyendo .

3.2 Ventajas de incorporarse al proyecto/beneficios para el equipo

        Aprendimos anteriormente que este patrón de diseño es en realidad una estructura similar a un árbol. La búsqueda recursiva de las funciones correspondientes puede hacer que el código sea fácil de expandir y mantener, y reducir el costo de mantenimiento del equipo. Lo más importante es evitar quejas de los socios sucesores. . En este momento, alguien lo refutó. No lo creo. ¿No es esto solo porque agregué un if else? ¿Tiene que ser tan impredecible? Es normal tener dudas, yo también tuve dudas similares cuando lo leí por primera vez, pero creo que ustedes no tendrán dudas similares después de leer la última parte.

Cuarto, sacar inferencias de una instancia

        Mencionamos anteriormente que este patrón de diseño en realidad no es beneficioso. Es una cuestión de if else para implementar funciones. Vamos a dar un ejemplo para que todos piensen por qué se usa este ejemplo.

4.1 Contraejemplo     

El siguiente es un ejemplo de un escenario comercial real de producto e I+D:

fecha necesidad Programador (monólogo interior)
lunes por la mañana) Hermano, el negocio dijo que hay una necesidad urgente, y necesitamos agregar un juicio aquí para emitir diferentes incentivos según diferentes canales. Bien. (No es difícil, solo agregue un juicio aquí y puede conectarse)

Martes

(tarde)

Hermano, el efecto en línea es muy bueno. El negocio dijo que debería subdividirse según los diferentes tipos de negocios para motivar al equipo. Tampoco es difícil. (Agregue un tipo para juzgar la línea)

Miércoles

(noche)

Hola, estas dormido? El negocio dijo que la división realizada esta vez es muy buena y debe subdividirse de acuerdo con el volumen de ventas del equipo bajo la subdivisión. Bien, agrega. (Ya me di cuenta si más es un poco demasiado)

Jueves

(temprano en la mañana)

Wow, ustedes son geniales, se conectaron en línea muy rápido, hay un pequeño requisito, deben ajustar los incentivos de acuerdo con las ventas individuales en el equipo. Bueno, además. (mucho si más para modificar)

Viernes

(medianoche)

Oye, está roto. ¿Por qué se envió mal la recompensa? La parte comercial comenzó a quejarse. Por favor, comprueba cuál es el problema. (deja lagrimas de arrepentimiento)

Código:

public class EngineController {

    private Logger logger = LoggerFactory.getLogger(EngineController.class);

    public String process(final String channelId, final String userId, final BigDecimal teamSalesVolume,final BigDecimal salesVolume) {

        logger.info("ifelse实现方式判断用户结果。channelId:{} userId:{} teamSalesVolume:{} salesVolume:{}", channelId, userId, teamSalesVolume,salesVolume);

        if ("0001".equals(channelId)) {
            if (new BigDecimal("1000").compareTo(teamSalesVolume)>0||new BigDecimal("1000").compareTo(salesVolume)>0) {
                return "奖励A";
            }

            if (new BigDecimal("1000").compareTo(teamSalesVolume)<=0||new BigDecimal("1000").compareTo(salesVolume)<=0) {
                return "奖励B";
            }
        }

        if ("0002".equals(channelId)) {
            if (new BigDecimal("1000").compareTo(teamSalesVolume)>0||new BigDecimal("1000").compareTo(salesVolume)>0) {
                return "奖励C";
            }

            if (new BigDecimal("1000").compareTo(teamSalesVolume)<=0||new BigDecimal("1000").compareTo(salesVolume)<=0) {
                return "奖励D";
            }
        }

        return null;

    }


}

        A juzgar por los resultados anteriores, es sin duda la forma más rápida de realizar la lógica correspondiente, pero si hay demasiados if else en el seguimiento, se convertirá en el código incorrecto final, que tendrá diversos grados de impacto en el mantenimiento posterior. e iteración.

4.2 Ejemplo positivo

Directorio de proyectos

Comencemos explicando las funciones y funciones de los módulos correspondientes según el nivel. 

4.2.1  Interfaz de filtro original LogicFilter

LogicFilter : la interfaz de filtrado original, que define el método de comportamiento original, el método de toma de decisiones lógicas y el método de obtención del valor de decisión.Todo nodo que proporcione capacidades de toma de decisiones debe implementar esta interfaz.

package cn.test.design.domain.service.logic;

import java.util.List;
import java.util.Map;

import cn.test.design.domain.model.vo.TreeNodeLink;

/**
 * 原始决策过滤器
 */
public interface LogicFilter {

    /**
     * 逻辑决策器
     *
     * @param matterValue          决策值
     * @param treeNodeLineInfoList 决策节点
     * @return 下一个节点Id
     */
    Long filter(String matterValue, List<TreeNodeLink> treeNodeLineInfoList);

    /**
     * 获取决策值
     *
     * @param decisionMatter 决策物料
     * @return 决策值
     */
    String matterValue(Long treeId, String userId, Map<String, String> decisionMatter);

}

4.2.2  Implementación básica de la abstracción de BaseLogic

BaseLogic: La abstracción básicamente implementala lógica de decisión básica en LogicFilter según la lógica de juicio de mayor o igual que, menor que, etc. según diferentes tipos. Al mismo tiempo, define un método abstracto para que todas las clases que implementen debe implementar el método para obtener un valor de decisión.Este valor de decisión se utiliza para la comparación lógica .

package cn.test.design.domain.service.logic;


import java.util.List;
import java.util.Map;

import cn.test.design.domain.model.vo.TreeNodeLink;

/**
 * 过滤器抽象基本实现实现,实现基本基本决策逻辑
 */
public abstract class BaseLogic implements LogicFilter {
	
	/**
	 * 实现基本基本决策逻辑
	 */
    @Override
    public Long filter(String matterValue, List<TreeNodeLink> treeNodeLinkList) {
        for (TreeNodeLink nodeLine : treeNodeLinkList) {
            if (decisionLogic(matterValue, nodeLine)) return nodeLine.getNodeIdTo();
        }
        return 0L;
    }
    
    /**
     * 让子类必须实现获取决策值的方法用于对比获取最终的结果
     */
    @Override
    public abstract String matterValue(Long treeId, String userId, Map<String, String> decisionMatter);

    private boolean decisionLogic(String matterValue, TreeNodeLink nodeLink) {
        switch (nodeLink.getRuleLimitType()) {
            case 1:
                return matterValue.equals(nodeLink.getRuleLimitValue());
            case 2:
                return Double.parseDouble(matterValue) > Double.parseDouble(nodeLink.getRuleLimitValue());
            case 3:
                return Double.parseDouble(matterValue) < Double.parseDouble(nodeLink.getRuleLimitValue());
            case 4:
                return Double.parseDouble(matterValue) <= Double.parseDouble(nodeLink.getRuleLimitValue());
            case 5:
                return Double.parseDouble(matterValue) >= Double.parseDouble(nodeLink.getRuleLimitValue());
            default:
                return false;
        }
    }

}

4.2.3 Implementación del nodo raíz del árbol (ChannelGenderFilter, UserSalesVolumeFilter)

Aquí, nuestro escenario comercial actual solo usa canales y ventas, por lo que solo hay dos definidos en la actualidad, y se pueden definir más si las necesidades reales, por supuesto, en la actualidad, el valor material se obtiene directamente. En el desarrollo real, debe ser basado en el archivo de configuración o desde la interfaz rpc o desde el Obtener la información requerida de la base de datos.

ChannelGenderFilter: nodo de canal

package cn.test.design.domain.service.logic.impl;

import java.util.Map;

import cn.test.design.domain.service.logic.BaseLogic;

/**
 * 
 * 渠道基本过滤器
 *
 */
public class ChannelGenderFilter extends BaseLogic {

	@Override
	public String matterValue(Long treeId, String userId, Map<String, String> decisionMatter) {
		// 目前是直接获取物料值,实际开发中肯定是根据配置文件或从rpc接口或从数据库中获取对应需要的信息。
		return decisionMatter.get("channel");
	}

}

UserSalesVolumeFilter: ventas de usuarios

package cn.test.design.domain.service.logic.impl;

import java.util.Map;

import cn.test.design.domain.service.logic.BaseLogic;
/**
 * 用户销售额过滤器
 *
 */
public class UserSalesVolumeFilter extends BaseLogic {

    @Override
    public String matterValue(Long treeId, String userId, Map<String, String> decisionMatter) {
    	// 目前是直接获取物料值,实际开发中肯定是根据配置文件或从rpc接口或从数据库中获取对应需要的信息.
    	return decisionMatter.get("userSalesVolume");
    }

}

4.2.4 Motor de decisión IEngine

        La interfaz del motor de decisión proporcionada a la persona que llama Después de definir el método correspondiente, si hay una nueva lógica de decisión, se puede implementar el método correspondiente.

package cn.test.design.domain.service.engine;

import java.util.Map;

import cn.test.design.domain.model.aggregates.TreeRich;
import cn.test.design.domain.model.vo.EngineResult;

/**
 * 决策引擎接口
 *
 */
public interface IEngine {
	
    EngineResult process(final Long treeId, final String userId, TreeRich treeRich, final Map<String, String> decisionMatter);

}

4.2.5 Configuración del nodo de decisión EngineConfig

        La configuración de toma de decisiones aquí actualmente está fijada con dos implementaciones de nodo raíz de árbol ( ChannelGenderFilter , UserSalesVolumeFilter ). El escenario real es configurar la implementación requerida en la tabla, que se puede configurar convenientemente en el fondo de la operación.

package cn.test.design.domain.service.engine;


import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import cn.test.design.domain.service.logic.LogicFilter;
import cn.test.design.domain.service.logic.impl.ChannelGenderFilter;
import cn.test.design.domain.service.logic.impl.UserSalesVolumeFilter;

/**
 * 
 * 决策节点配置,此处可以配置至数据库中方便后续界面操作维护
 *
 */
public class EngineConfig {

    static Map<String, LogicFilter> logicFilterMap;

    static {
        logicFilterMap = new ConcurrentHashMap<>();
        logicFilterMap.put("channel", new ChannelGenderFilter());
        logicFilterMap.put("userSalesVolume", new UserSalesVolumeFilter());
    }

    public Map<String, LogicFilter> getLogicFilterMap() {
        return logicFilterMap;
    }

    @SuppressWarnings("static-access")
	public void setLogicFilterMap(Map<String, LogicFilter> logicFilterMap) {
        this.logicFilterMap = logicFilterMap;
    }

}

4.2.6 Motor de decisión básico EngineBase

        Este es el flujo de procesamiento del árbol de decisión principal, un poco como buscar el fruto de las hojas. Al mismo tiempo, se implementa el motor de decisión básico IEngine

Pero solo proporciona abstracción y no la implementa, y es implementada por el motor de clase de implementación de toma de decisiones final.

package cn.test.design.domain.service.engine;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.test.design.domain.model.aggregates.TreeRich;
import cn.test.design.domain.model.vo.EngineResult;
import cn.test.design.domain.model.vo.TreeNode;
import cn.test.design.domain.model.vo.TreeRoot;
import cn.test.design.domain.service.logic.LogicFilter;

/**
 * 决策树引擎
 */
public abstract class EngineBase extends EngineConfig implements IEngine {

    private Logger logger = LoggerFactory.getLogger(EngineBase.class);

    @Override
    public abstract EngineResult process(Long treeId, String userId, TreeRich treeRich, Map<String, String> decisionMatter);

    protected TreeNode engineDecisionMaker(TreeRich treeRich, Long treeId, String userId, Map<String, String> decisionMatter) {
        TreeRoot treeRoot = treeRich.getTreeRoot();
        Map<Long, TreeNode> treeNodeMap = treeRich.getTreeNodeMap();
        // 规则树根ID
        Long rootNodeId = treeRoot.getTreeRootNodeId();
        TreeNode treeNodeInfo = treeNodeMap.get(rootNodeId);
        //循环获取对应的处理节点直到获取到对应的结果
        //节点类型[NodeType];1子叶、2果实 我们只需要使用果实
        while (treeNodeInfo.getNodeType().equals(1)) {
            //对应处理规则key用于获取对应实现LogicFilter 的处理节点主要用来获取物料中用于对比的相关值
        	String ruleKey = treeNodeInfo.getRuleKey();
        	//实际的处理节点
            LogicFilter logicFilter = logicFilterMap.get(ruleKey);
            String matterValue = logicFilter.matterValue(treeId, userId, decisionMatter);
            //基础决策抽象中的能力,使用物料值判断使用那个决策节点(获取的是下一个节点)
            Long nextNode = logicFilter.filter(matterValue, treeNodeInfo.getTreeNodeLinkList());
            //赋值对应的处理节点,直到找到期望的处理节点(我们这里是最终的果实节点)
            treeNodeInfo = treeNodeMap.get(nextNode);
            logger.info("决策树引擎=>{} userId:{} treeId:{} treeNode:{} ruleKey:{} matterValue:{}", treeRoot.getTreeName(), userId, treeId, treeNodeInfo.getTreeNodeId(), ruleKey, matterValue);
        }
        return treeNodeInfo;
    }

}

4.2.7 Implementación básica del motor de decisiones TreeEngineHandle

        Básicamente, es relativamente simple usar el valor correspondiente pasado por el usuario directamente al método correspondiente para obtener el resultado correspondiente.

package cn.test.design.domain.service.engine.impl;

import java.util.Map;

import cn.test.design.domain.model.aggregates.TreeRich;
import cn.test.design.domain.model.vo.EngineResult;
import cn.test.design.domain.model.vo.TreeNode;
import cn.test.design.domain.service.engine.EngineBase;
/**
 * 基础决策引擎实现
 *
 */
public class TreeEngineHandle extends EngineBase {

    @Override
    public EngineResult process(Long treeId, String userId, TreeRich treeRich, Map<String, String> decisionMatter) {
        // 决策流程
        TreeNode treeNode = engineDecisionMaker(treeRich, treeId, userId, decisionMatter);
        // 决策结果
        return new EngineResult(userId, treeId, treeNode.getTreeNodeId(), treeNode.getNodeValue());
    }

}

4.2.8 Pruebas unitarias

        La configuración inicial aquí actualmente se configura manualmente, y el código real puede usar la configuración de la base de datos para configurar dinámicamente la información de nodo requerida.

package cn.test.design.test;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;

import cn.test.design.domain.model.aggregates.TreeRich;
import cn.test.design.domain.model.vo.EngineResult;
import cn.test.design.domain.model.vo.TreeNode;
import cn.test.design.domain.model.vo.TreeNodeLink;
import cn.test.design.domain.model.vo.TreeRoot;
import cn.test.design.domain.service.engine.IEngine;
import cn.test.design.domain.service.engine.impl.TreeEngineHandle;

public class ApiTest {

    private Logger logger = LoggerFactory.getLogger(ApiTest.class);

    private TreeRich treeRich;

    @Before
    public void init() {

        // 节点:1
        TreeNode treeNode_01 = new TreeNode();
        treeNode_01.setTreeId(10001L);
        treeNode_01.setTreeNodeId(1L);
        treeNode_01.setNodeType(1);
        treeNode_01.setNodeValue(null);
        treeNode_01.setRuleKey("channel");
        treeNode_01.setRuleDesc("渠道");

        // 链接:1->11
        TreeNodeLink treeNodeLink_11 = new TreeNodeLink();
        treeNodeLink_11.setNodeIdFrom(1L);
        treeNodeLink_11.setNodeIdTo(11L);
        treeNodeLink_11.setRuleLimitType(1);
        treeNodeLink_11.setRuleLimitValue("0001");

        // 链接:1->12
        TreeNodeLink treeNodeLink_12 = new TreeNodeLink();
        treeNodeLink_12.setNodeIdTo(1L);
        treeNodeLink_12.setNodeIdTo(12L);
        treeNodeLink_12.setRuleLimitType(1);
        treeNodeLink_12.setRuleLimitValue("0002");

        List<TreeNodeLink> treeNodeLinkList_1 = new ArrayList<>();
        treeNodeLinkList_1.add(treeNodeLink_11);
        treeNodeLinkList_1.add(treeNodeLink_12);

        treeNode_01.setTreeNodeLinkList(treeNodeLinkList_1);

        // 节点:11
        TreeNode treeNode_11 = new TreeNode();
        treeNode_11.setTreeId(10001L);
        treeNode_11.setTreeNodeId(11L);
        treeNode_11.setNodeType(1);
        treeNode_11.setNodeValue(null);
        treeNode_11.setRuleKey("userSalesVolume");
        treeNode_11.setRuleDesc("销售额A");

        // 链接:11->111
        TreeNodeLink treeNodeLink_111 = new TreeNodeLink();
        treeNodeLink_111.setNodeIdFrom(11L);
        treeNodeLink_111.setNodeIdTo(111L);
        treeNodeLink_111.setRuleLimitType(3);
        treeNodeLink_111.setRuleLimitValue("25");

        // 链接:11->112
        TreeNodeLink treeNodeLink_112 = new TreeNodeLink();
        treeNodeLink_112.setNodeIdFrom(11L);
        treeNodeLink_112.setNodeIdTo(112L);
        treeNodeLink_112.setRuleLimitType(5);
        treeNodeLink_112.setRuleLimitValue("25");

        List<TreeNodeLink> treeNodeLinkList_11 = new ArrayList<>();
        treeNodeLinkList_11.add(treeNodeLink_111);
        treeNodeLinkList_11.add(treeNodeLink_112);

        treeNode_11.setTreeNodeLinkList(treeNodeLinkList_11);

        // 节点:12
        TreeNode treeNode_12 = new TreeNode();
        treeNode_12.setTreeId(10001L);
        treeNode_12.setTreeNodeId(12L);
        treeNode_12.setNodeType(1);
        treeNode_12.setNodeValue(null);
        treeNode_12.setRuleKey("userSalesVolume");
        treeNode_12.setRuleDesc("销售额B");

        // 链接:12->121
        TreeNodeLink treeNodeLink_121 = new TreeNodeLink();
        treeNodeLink_121.setNodeIdFrom(12L);
        treeNodeLink_121.setNodeIdTo(121L);
        treeNodeLink_121.setRuleLimitType(3);
        treeNodeLink_121.setRuleLimitValue("25");

        // 链接:12->122
        TreeNodeLink treeNodeLink_122 = new TreeNodeLink();
        treeNodeLink_122.setNodeIdFrom(12L);
        treeNodeLink_122.setNodeIdTo(122L);
        treeNodeLink_122.setRuleLimitType(5);
        treeNodeLink_122.setRuleLimitValue("25");

        List<TreeNodeLink> treeNodeLinkList_12 = new ArrayList<>();
        treeNodeLinkList_12.add(treeNodeLink_121);
        treeNodeLinkList_12.add(treeNodeLink_122);

        treeNode_12.setTreeNodeLinkList(treeNodeLinkList_12);

        // 节点:111
        TreeNode treeNode_111 = new TreeNode();
        treeNode_111.setTreeId(10001L);
        treeNode_111.setTreeNodeId(111L);
        treeNode_111.setNodeType(2);
        treeNode_111.setNodeValue("果实A");

        // 节点:112
        TreeNode treeNode_112 = new TreeNode();
        treeNode_112.setTreeId(10001L);
        treeNode_112.setTreeNodeId(112L);
        treeNode_112.setNodeType(2);
        treeNode_112.setNodeValue("果实B");

        // 节点:121
        TreeNode treeNode_121 = new TreeNode();
        treeNode_121.setTreeId(10001L);
        treeNode_121.setTreeNodeId(121L);
        treeNode_121.setNodeType(2);
        treeNode_121.setNodeValue("果实C");

        // 节点:122
        TreeNode treeNode_122 = new TreeNode();
        treeNode_122.setTreeId(10001L);
        treeNode_122.setTreeNodeId(122L);
        treeNode_122.setNodeType(2);
        treeNode_122.setNodeValue("果实D");

        // 树根
        TreeRoot treeRoot = new TreeRoot();
        treeRoot.setTreeId(10001L);
        treeRoot.setTreeRootNodeId(1L);
        treeRoot.setTreeName("规则决策树");

        Map<Long, TreeNode> treeNodeMap = new HashMap<>();
        treeNodeMap.put(1L, treeNode_01);
        treeNodeMap.put(11L, treeNode_11);
        treeNodeMap.put(12L, treeNode_12);
        treeNodeMap.put(111L, treeNode_111);
        treeNodeMap.put(112L, treeNode_112);
        treeNodeMap.put(121L, treeNode_121);
        treeNodeMap.put(122L, treeNode_122);

        treeRich = new TreeRich(treeRoot, treeNodeMap);

    }

    @Test
    public void test_tree() {
        logger.info("决策树组合结构信息:\r\n" + JSON.toJSONString(treeRich));

        IEngine treeEngineHandle = new TreeEngineHandle();

        /**
         * 测试数据
         * 果实A:gender=man、age=22
         * 果实B:gender=man、age=29
         * 果实C:gender=woman、age=22
         * 果实D:gender=woman、age=29
         */
        Map<String, String> decisionMatter = new HashMap<>();
        decisionMatter.put("channel", "0001");
        decisionMatter.put("userSalesVolume", "29");

        EngineResult result = treeEngineHandle.process(10001L, "Oli09pLkdjh", treeRich, decisionMatter);
        logger.info("测试结果:{}", JSON.toJSONString(result));

    }

    @Test
    public void t() {
        
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01000011", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01101111", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01100100", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01101001", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01101110", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01100111", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01001000", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01100101", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01101100", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01110000", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01110011", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01001100", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01101001", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01100110", 2)).trim()));
        System.out.println(hexStringToString(String.format("%21X", Long.parseLong("01100101", 2)).trim()));
    }

    public static String hexStringToString(String s) {
        if (s == null || s.equals("")) {
            return null;
        }
        s = s.replace(" ", "");
        byte[] baKeyword = new byte[s.length() / 2];
        for (int i = 0; i < baKeyword.length; i++) {
            try {
                baKeyword[i] = (byte) (0xff & Integer.parseInt(s.substring(i * 2, i * 2 + 2), 16));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        try {
            s = new String(baKeyword, "UTF-8");
            new String();
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return s;
    }
}

4.2.9 Clases de nodos básicos relacionados

        Anote las clases básicas relevantes aquí

cn.test.design.dominio.modelo.agregados TreeRich

agregación de árbol de reglas

Organizar cada nodo del árbol (hojas, frutos)

cn.test.design.dominio.modelo.vo Resultado del motor resultado de la decisión
cn.test.design.dominio.modelo.vo TreeNode Información del nodo del árbol de reglas
cn.test.design.dominio.modelo.vo ÁrbolNodoEnlace La información de la línea del árbol de reglas vincula los nodos de hojas y los nodos de frutas
cn.test.design.dominio.modelo.vo Raíz del arbol información raíz

Agregación de árbol de reglas TreeRich

package cn.test.design.domain.model.aggregates;

import java.util.Map;

import cn.test.design.domain.model.vo.TreeNode;
import cn.test.design.domain.model.vo.TreeRoot;

/**
 * 规则树聚合
 */
public class TreeRich {
	// 树根信息
	private TreeRoot treeRoot;
	// 树节点ID -> 子节点
	private Map<Long, TreeNode> treeNodeMap;

	public TreeRich(TreeRoot treeRoot, Map<Long, TreeNode> treeNodeMap) {
		this.treeRoot = treeRoot;
		this.treeNodeMap = treeNodeMap;
	}

	public TreeRoot getTreeRoot() {
		return treeRoot;
	}

	public void setTreeRoot(TreeRoot treeRoot) {
		this.treeRoot = treeRoot;
	}

	public Map<Long, TreeNode> getTreeNodeMap() {
		return treeNodeMap;
	}

	public void setTreeNodeMap(Map<Long, TreeNode> treeNodeMap) {
		this.treeNodeMap = treeNodeMap;
	}
}

Resultado de la decisión EngineResult

package cn.test.design.domain.model.vo;

/**
 * 决策结果
 */
public class EngineResult {

	// 执行结果
	private boolean isSuccess;
	// 用户ID
	private String userId;
	// 规则树ID
	private Long treeId;
	// 果实节点ID
	private Long nodeId;
	// 果实节点值
	private String nodeValue;

	public EngineResult() {
	}

	public EngineResult(boolean isSuccess) {
		this.isSuccess = isSuccess;
	}

	public EngineResult(String userId, Long treeId, Long nodeId, String nodeValue) {
		this.isSuccess = true;
		this.userId = userId;
		this.treeId = treeId;
		this.nodeId = nodeId;
		this.nodeValue = nodeValue;
	}

	public boolean isSuccess() {
		return isSuccess;
	}

	public void setSuccess(boolean success) {
		isSuccess = success;
	}

	public String getUserId() {
		return userId;
	}

	public void setUserId(String userId) {
		this.userId = userId;
	}

	public Long getTreeId() {
		return treeId;
	}

	public void setTreeId(Long treeId) {
		this.treeId = treeId;
	}

	public Long getNodeId() {
		return nodeId;
	}

	public void setNodeId(Long nodeId) {
		this.nodeId = nodeId;
	}

	public String getNodeValue() {
		return nodeValue;
	}

	public void setNodeValue(String nodeValue) {
		this.nodeValue = nodeValue;
	}
}

Información del nodo del árbol de reglas TreeNode

package cn.test.design.domain.model.vo;

import java.util.List;

/**
 * 规则树节点信息
 */
public class TreeNode {

	// 规则树ID
	private Long treeId;
	// 规则树节点ID
	private Long treeNodeId;
	// 节点类型;1叶子、2 果实
	private Integer nodeType;
	// 节点值[nodeType=2];果实值
	private String nodeValue;
	// 规则Key
	private String ruleKey;
	// 规则描述
	private String ruleDesc;
	// 节点链路
	private List<TreeNodeLink> treeNodeLinkList; 

	public Long getTreeId() {
		return treeId;
	}

	public void setTreeId(Long treeId) {
		this.treeId = treeId;
	}

	public Long getTreeNodeId() {
		return treeNodeId;
	}

	public void setTreeNodeId(Long treeNodeId) {
		this.treeNodeId = treeNodeId;
	}

	public Integer getNodeType() {
		return nodeType;
	}

	public void setNodeType(Integer nodeType) {
		this.nodeType = nodeType;
	}

	public String getNodeValue() {
		return nodeValue;
	}

	public void setNodeValue(String nodeValue) {
		this.nodeValue = nodeValue;
	}

	public String getRuleKey() {
		return ruleKey;
	}

	public void setRuleKey(String ruleKey) {
		this.ruleKey = ruleKey;
	}

	public String getRuleDesc() {
		return ruleDesc;
	}

	public void setRuleDesc(String ruleDesc) {
		this.ruleDesc = ruleDesc;
	}

	public List<TreeNodeLink> getTreeNodeLinkList() {
		return treeNodeLinkList;
	}

	public void setTreeNodeLinkList(List<TreeNodeLink> treeNodeLinkList) {
		this.treeNodeLinkList = treeNodeLinkList;
	}

}

La información de la línea del árbol de reglas vincula los nodos de hojas y los nodos de frutas TreeNodeLink

package cn.test.design.domain.model.vo;

/**
 * 规则树线信息 链接叶子节点和果实节点
 */
public class TreeNodeLink {

	// 节点From
	private Long nodeIdFrom;
	// 节点To
	private Long nodeIdTo;
	// 限定类型;1:=;2:>;3:<;4:>=;5<=;6:enum[枚举范围]
	private Integer ruleLimitType;
	// 限定值
	private String ruleLimitValue;

	public Long getNodeIdFrom() {
		return nodeIdFrom;
	}

	public void setNodeIdFrom(Long nodeIdFrom) {
		this.nodeIdFrom = nodeIdFrom;
	}

	public Long getNodeIdTo() {
		return nodeIdTo;
	}

	public void setNodeIdTo(Long nodeIdTo) {
		this.nodeIdTo = nodeIdTo;
	}

	public Integer getRuleLimitType() {
		return ruleLimitType;
	}

	public void setRuleLimitType(Integer ruleLimitType) {
		this.ruleLimitType = ruleLimitType;
	}

	public String getRuleLimitValue() {
		return ruleLimitValue;
	}

	public void setRuleLimitValue(String ruleLimitValue) {
		this.ruleLimitValue = ruleLimitValue;
	}
}

Información sobre la raíz del árbol TreeRoot

package cn.test.design.domain.model.vo;

/**
 * 树根信息
 */
public class TreeRoot {

	// 规则树ID
	private Long treeId;
	// 规则树根ID
	private Long treeRootNodeId;
	// 规则树名称
	private String treeName;

	public Long getTreeId() {
		return treeId;
	}

	public void setTreeId(Long treeId) {
		this.treeId = treeId;
	}

	public Long getTreeRootNodeId() {
		return treeRootNodeId;
	}

	public void setTreeRootNodeId(Long treeRootNodeId) {
		this.treeRootNodeId = treeRootNodeId;
	}

	public String getTreeName() {
		return treeName;
	}

	public void setTreeName(String treeName) {
		this.treeName = treeName;
	}
}

5. Zarpar

        Al final, ¿encontró que este modo es como un host de computadora, y se pueden combinar y conectar diferentes interfaces, y se pueden configurar diferentes configuraciones en cualquier momento? Este modo garantiza el principio de apertura y cierre. la estructura correspondiente se define en la etapa inicial, cada nuevo Para aumentar la demanda, solo necesita agregar los nodos correspondientes, o ambos pueden usarse como el modo de fondo de la operación, y las reglas de enrutamiento correspondientes pueden ser configuradas dinámicamente por la operación para facilitar la subsiguiente mantenimiento.

Referencias en este artículo:

"Reaprender patrones de diseño de Java" - Comisario Político Fu.

  Enciclopedia Baidu.

Supongo que te gusta

Origin blog.csdn.net/m0_37506254/article/details/128051240
Recomendado
Clasificación