七种方法增强代码可扩展性(多图详解)


1 六大原则

在设计模式中有六大设计原则:

单一职责原则:一个类只做一件事

里式替换原则:子类可以扩展父类

依赖倒置原则:面向接口编程

接口隔离原则:高内聚低耦合

迪米特法则:最少知道原则

开闭原则:关闭修改,开放新增

我认为在这六个原则中开闭原则最为重要,开闭原则是可扩展性的重要基石。

第一个原因是需求变化时应该通过新增而不是修改已有代码实现,这样保证了代码稳定性,避免牵一发而动全身。

第二个原因是可以事先定义代码框架,扩展也是根据框架扩展,体现了用抽象构建框架,用实现扩展细节,保证了稳定性也保证了灵活性。

第三个原因是其它五个原则虽然侧重点各有不同,但是都可以包含于开闭原则。

第四个原因是标准二十三种设计模式最终都是在遵循开闭原则。

既然开闭原则如此重要,我们应该怎么在系统设计时遵循开闭原则呢?


2 数据库维度

2.1 设计类型字段

数据表设计时新增两列:biz_type、biz_sub_type,这两个列即使目前用不上,但是后续扩展可以派上大用场,可以先设置一个默认值。

biz_type可以指业务类型,业务渠道、租户等等,归根结底是用来隔离大业务类型,假设后续业务新增了一个大业务类型,那么可以通过这个字段隔离。

biz_sub_type可以在大业务类型中细分小业务,使得业务更加细化,灵活性更好。


2.2 设计扩展字段

数据表设计时新增三列:extend1、extend2、extend3,可以先设置为空。扩展字段存储JSON类型信息,存放一些扩展信息、附加信息、松散信息或者是之前未预估到的信息,保证了灵活性。

之所以设置三个扩展字段是为了增加隔离性,例如extend1存放订单扩展,extend2存放商品扩展,extend3存放营销扩展。


2.3 设计业务二进制字段

2.3.1 需求背景

数据表设计时新增业务二进制,这个字段可以很大程度上扩展业务表意能力。假设在系统中用户一共有三种角色:普通用户、管理员、超级管理员,现在需要设计一张用户角色表记录这类信息。我们不难设计出如下方案:


id name super admin normal
101 用户一 1 0 0
102 用户二 0 1 0
103 用户三 0 0 1
104 用户四 1 1 1

观察上表不难得出,用户一具有超级管理员角色,用户二具有管理员角色,用户三具有普通用户角色,用户四同时具有三种角色。如果此时新增加一种角色呢?那么新增一个字段即可。


2.3.2 发现问题

按照上述一个字段表示一种角色进行表设计功能上是没有问题的,优点是容易理解结构清晰,但是我们想一想有没有什么问题?笔者遇到过如下问题:在复杂业务环境一份数据可能会使用在不同的场景,例如上述数据存储在MySQL数据库,这一份数据还会被用在如下场景:

检索数据需要同步一份到ES

业务方使用此表通过Flink计算业务指标

业务方订阅此表Binlog消息进行业务处理

如果表结构发生变化,数据源之间就要重新进行对接,业务方也要进行代码修改,这样开发成本比较非常高。有没有办法避免此类问题?


2.3.3 解决方案

我们可以使用位图法,这样同一个字段可以表示多个业务含义。首先设计如下数据表,userFlag字段暂时不填。

id name user_flag
101 用户一 暂时不填
102 用户二 暂时不填
103 用户三 暂时不填
104 用户四 暂时不填

设计位图每一个bit表示一种角色:


00 初始位图.jpg


使用位图法表示如下数据表:


id name super admin normal
101 用户一 1 0 0
102 用户二 0 1 0
103 用户三 0 0 1
104 用户四 1 1 1

用户一位图如下其十进制数值等于4:


01 用户一.jpg


用户二位图如下其十进制数值等于2:


02 用户二.jpg


用户三位图如下其十进制数值等于1:


03 用户三.jpg


用户四位图如下其十进制数值等于7:


04 用户四.jpg


现在我们可以填写数据表第三列:


id name user_flag
101 用户一 4
102 用户二 2
103 用户三 1
104 用户四 7

2.3.4 代码实例

定义枚举时不要直接定义为1、2、4这类数字,而应该采用位移方式进行定义,这样使用者可以明白设计者的意图。

/**
 * 用户角色枚举
 *
 * @author 微信公众号「JAVA前线」
 *
 */
public enum UserRoleEnum {

    // 1 -> 00000001
    NORMAL(1, "普通用户"),

    // 2 -> 00000010
    MANAGER(1 << 1, "管理员"),

    // 4 -> 00000100
    SUPER(1 << 2, "超级管理员")

    ;

    private int code;
    private String description;

    private UserRoleEnum(Integer code, String description) {
        this.code = code;
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public int getCode() {
        return this.code;
    }
}

假设用户已经具有普通用户角色,我们需要为其增加管理员角色,这就是新增角色,与之对应还有删除角色和查询角色,这些操作需要用到为位运算,详见代码注释。

/**
 * 用户角色枚举
 *
 * @author 微信公众号「JAVA前线」
 *
 */
public enum UserRoleEnum {

    // 1 -> 00000001
    NORMAL(1, "普通用户"),

    // 2 -> 00000010
    MANAGER(1 << 1, "管理员"),

    // 4 -> 00000100
    SUPER(1 << 2, "超级管理员")

    ;

    // 新增角色 -> 位或操作
    // oldRole -> 00000001 -> 普通用户
    // addRole -> 00000010 -> 新增管理员
    // newRole -> 00000011 -> 普通用户和管理员
    public static Integer addRole(Integer oldRole, Integer addRole) {
        return oldRole | addRole;
    }

    // 删除角色 -> 位异或操作
    // oldRole -> 00000011 -> 普通用户和管理员
    // delRole -> 00000010 -> 删除管理员
    // newRole -> 00000001 -> 普通用户
    public static Integer removeRole(Integer oldRole, Integer delRole) {
        return oldRole ^ delRole;
    }

    // 是否有某种角色 -> 位与操作
    // allRole -> 00000011 -> 普通用户和管理员
    // qryRole -> 00000001 -> 是否有管理员角色
    // resRole -> 00000001 -> 有普通用户角色
    public static boolean hasRole(Integer allRole, Integer qryRole) {
        return qryRole == (role & qryRole);
    }

    private int code;
    private String description;

    private UserRoleEnum(Integer code, String description) {
        this.code = code;
        this.description = description;
    }

    public String getDescription() {
        return description;
    }

    public int getCode() {
        return this.code;
    }

    public static void main(String[] args) {
        System.out.println(addRole(1, 2));
        System.out.println(removeRole(3, 1));
        System.out.println(hasRole(3, 1));
    }
}

假设在运营后台查询界面中,需要查询具有普通用户角色的用户数据,可以使用如下SQL语句:

select * from user_role where (user_flag & 1) = user_flag;
select * from user_role where (user_flag & b'0001') = user_flag;

我们也可以使用MyBatis语句:

<select id="selectByUserRole" resultMap="BaseResultMap" parameterType="java.util.Map">
  select * from user_role 
  where user_flag & #{userFlag} = #{userFlag}
</select>

<select id="selectByUserIdAndRole" resultMap="BaseResultMap" parameterType="java.util.Map">
  select * from user_role 
  where id = #{userId} and user_flag & #{userFlag} = #{userFlag}
</select>

3 接口维度

3.1 设计类型入参

接口输入参数一定要设计类型入参,可以与数据库biz_type、biz_sub_type相对应,也可以自定义类型最终翻译为与数据库类型相对应,

如果一开始不用区分类型可以设置为默认值,但是其核心思想是一定要可以通过类型对输入参数进行区分。

public class OrderDTO {
    private Integer bizType;
    private Integer bizSubType;
    private Long amount;
    private String goodsId;
}

public Response<String> createOrder(OrderDTO order);

3.2 设计松散入参

接口输入参数可以设计Map类型松散参数,松散参数缺点是表意能力弱,优点是灵活性强,可以以较低成本新增参数。

public class OrderDTO {
    private Integer bizType;
    private Integer bizSubType;
    private Long amount;
    private String goodsId;
    private Map<String, String> params;
}

public Response<String> createOrder(OrderDTO order);

3.3 设计接口版本号

对外接口需要设计版本号,对于同一个接口,允许外部业务逐渐切到新版本,新老版本接口会共存一段时间,通过版本号区分。

/order/1.0/createOrder
/order/1.1/createOrder

3.4 纵横做设计

我们分析一个下单场景。当前有ABC三种订单类型:A订单价格9折,物流最大重量不能超过9公斤,不支持退款。B订单价格8折,物流最大重量不能超过8公斤,支持退款。C订单价格7折,物流最大重量不能超过7公斤,支持退款。按照需求字面含义平铺直叙地写代码也并不难:

public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderMapper orderMapper;

    @Override
    public void createOrder(OrderBO orderBO) {
        if (null == orderBO) {
            throw new RuntimeException("参数异常");
        }
        if (OrderTypeEnum.isNotValid(orderBO.getType())) {
            throw new RuntimeException("参数异常");
        }
        // A类型订单
        if (OrderTypeEnum.A_TYPE.getCode().equals(orderBO.getType())) {
            orderBO.setPrice(orderBO.getPrice() * 0.9);
            if (orderBO.getWeight() > 9) {
                throw new RuntimeException("超过物流最大重量");
            }
            orderBO.setRefundSupport(Boolean.FALSE);
        }
        // B类型订单
        else if (OrderTypeEnum.B_TYPE.getCode().equals(orderBO.getType())) {
            orderBO.setPrice(orderBO.getPrice() * 0.8);
            if (orderBO.getWeight() > 8) {
                throw new RuntimeException("超过物流最大重量");
            }
            orderBO.setRefundSupport(Boolean.TRUE);
        }
        // C类型订单
        else if (OrderTypeEnum.C_TYPE.getCode().equals(orderBO.getType())) {
            orderBO.setPrice(orderBO.getPrice() * 0.7);
            if (orderBO.getWeight() > 7) {
                throw new RuntimeException("超过物流最大重量");
            }
            orderBO.setRefundSupport(Boolean.TRUE);
        }
        // 保存数据
        OrderDO orderDO = new OrderDO();
        BeanUtils.copyProperties(orderBO, orderDO);
        orderMapper.insert(orderDO);
    }
}

上述代码从功能上完全可以实现业务需求,但是程序员不仅要满足功能,还需要思考代码的可维护性。如果新增一种订单类型,或者新增一个订单属性处理逻辑,那么我们就要在上述逻辑中新增代码,如果处理不慎就会影响原有逻辑。

如何改变平铺直叙的思考方式?这就要为问题分析加上纵向和横向两个维度,我选择使用分析矩阵方法,其中纵向表示策略,横向表示场景:


05 订单_分析矩阵.jpg


(1) 纵向做隔离

纵向维度表示策略,不同策略在逻辑上和业务上应该是隔离的,本实例包括优惠策略、物流策略和退款策略,策略作为抽象,不同订单类型去扩展这个抽象,策略模式非常适合这种场景。本文详细分析优惠策略,物流策略和退款策略同理。

// 优惠策略
public interface DiscountStrategy {
    public void discount(OrderBO orderBO);
}

// A类型优惠策略
@Component
public class TypeADiscountStrategy implements DiscountStrategy {

    @Override
    public void discount(OrderBO orderBO) {
        orderBO.setPrice(orderBO.getPrice() * 0.9);
    }
}

// B类型优惠策略
@Component
public class TypeBDiscountStrategy implements DiscountStrategy {

    @Override
    public void discount(OrderBO orderBO) {
        orderBO.setPrice(orderBO.getPrice() * 0.8);
    }
}

// C类型优惠策略
@Component
public class TypeCDiscountStrategy implements DiscountStrategy {

    @Override
    public void discount(OrderBO orderBO) {
        orderBO.setPrice(orderBO.getPrice() * 0.7);
    }
}

// 优惠策略工厂
@Component
public class DiscountStrategyFactory implements InitializingBean {
    private Map<String, DiscountStrategy> strategyMap = new HashMap<>();

    @Resource
    private TypeADiscountStrategy typeADiscountStrategy;
    @Resource
    private TypeBDiscountStrategy typeBDiscountStrategy;
    @Resource
    private TypeCDiscountStrategy typeCDiscountStrategy;

    public DiscountStrategy getStrategy(String type) {
        return strategyMap.get(type);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        strategyMap.put(OrderTypeEnum.A_TYPE.getCode(), typeADiscountStrategy);
        strategyMap.put(OrderTypeEnum.B_TYPE.getCode(), typeBDiscountStrategy);
        strategyMap.put(OrderTypeEnum.C_TYPE.getCode(), typeCDiscountStrategy);
    }
}

// 优惠策略执行
@Component
public class DiscountStrategyExecutor {
    private DiscountStrategyFactory discountStrategyFactory;

    public void discount(OrderBO orderBO) {
        DiscountStrategy discountStrategy = discountStrategyFactory.getStrategy(orderBO.getType());
        if (null == discountStrategy) {
            throw new RuntimeException("无优惠策略");
        }
        discountStrategy.discount(orderBO);
    }
}

(2) 横向做编排

横向维度表示场景,一种订单类型在广义上可以认为是一种业务场景,在场景中将独立的策略进行串联,模板方法设计模式适用于这种场景。

模板方法模式一般使用抽象类定义算法骨架,同时定义一些抽象方法,这些抽象方法延迟到子类实现,这样子类不仅遵守了算法骨架约定,也实现了自己的算法。既保证了规约也兼顾灵活性,这就是用抽象构建框架,用实现扩展细节。

// 创建订单服务
public interface CreateOrderService {
    public void createOrder(OrderBO orderBO);
}

// 抽象创建订单流程
public abstract class AbstractCreateOrderFlow {

    @Resource
    private OrderMapper orderMapper;

    public void createOrder(OrderBO orderBO) {
        // 参数校验
        if (null == orderBO) {
            throw new RuntimeException("参数异常");
        }
        if (OrderTypeEnum.isNotValid(orderBO.getType())) {
            throw new RuntimeException("参数异常");
        }
        // 计算优惠
        discount(orderBO);
        // 计算重量
        weighing(orderBO);
        // 退款支持
        supportRefund(orderBO);
        // 保存数据
        OrderDO orderDO = new OrderDO();
        BeanUtils.copyProperties(orderBO, orderDO);
        orderMapper.insert(orderDO);
    }

    public abstract void discount(OrderBO orderBO);

    public abstract void weighing(OrderBO orderBO);

    public abstract void supportRefund(OrderBO orderBO);
}

// 实现创建订单流程
@Service
public class CreateOrderFlow extends AbstractCreateOrderFlow {

    @Resource
    private DiscountStrategyExecutor discountStrategyExecutor;
    @Resource
    private ExpressStrategyExecutor expressStrategyExecutor;
    @Resource
    private RefundStrategyExecutor refundStrategyExecutor;

    @Override
    public void discount(OrderBO orderBO) {
        discountStrategyExecutor.discount(orderBO);
    }

    @Override
    public void weighing(OrderBO orderBO) {
        expressStrategyExecutor.weighing(orderBO);
    }

    @Override
    public void supportRefund(OrderBO orderBO) {
        refundStrategyExecutor.supportRefund(orderBO);
    }
}

4 文章总结

本文介绍了设计类型字段、设计扩展字段、设计业务二进制字段、设计类型入参、设计松散入参、设计接口版本号、纵横做设计七种增加系统可扩展性具体方案,希望本文对大家有所帮助。


本文转载于网络 如有侵权请联系删除

相关文章

  • java获取上传的文件_java 文件上传到读取文件内容的实例

    大家好,又见面了,我是你们的朋友全栈君。1.下载文件,将文件保存到本地。(只试用excel);2.对文件的标题进行检验;3.获取导入的批次(取一个表的一个值,加1);4.循环获取文件某一个行,某一列的值,set到对象中;5.检验值的合法性;6.循环保存到对象中。7.用map将错误的信息和正确的信息,JSONObject.fromObject(map);publicStringuploadFile()throwsException{ logger.info(“开始导入规则文件:”+fileInputFileName);InputStreamis=newFileInputStream(fileInput);StringuploadPath=ServletActionContext.getServletContext().getRealPath(“/upload”);System.out.println(uploadPath);FiletargetFile=newFile(uploadPath,this.getFileInputFileName());OutputStreamos=newFi

  • 分布式之缓存击穿(下)

    布隆过滤器1.原理 布隆过滤器的巨大用处就是,能够迅速判断一个元素是否在一个集合中。因此他有如下三个使用场景:网页爬虫对URL的去重,避免爬取相同的URL地址反垃圾邮件,从数十亿个垃圾邮件列表中判断某邮箱是否垃圾邮箱(同理,垃圾短信)缓存击穿,将已存在的缓存放到布隆过滤器中,当黑客访问不存在的缓存时迅速返回避免缓存及DB挂掉。OK,接下来我们来谈谈布隆过滤器的原理其内部维护一个全为0的bit数组,需要说明的是,布隆过滤器有一个误判率的概念,误判率越低,则数组越长,所占空间越大。误判率越高则数组越小,所占的空间越小。假设,根据误判率,我们生成一个10位的bit数组,以及2个hash函数(f1,f2),如下图所示(生成的数组的位数和hash函数的数量,我们不用去关心是如何生成的,有数学论文进行过专业的证明)。 假设输入集合为(N1,N2),经过计算f1(N1)得到的数值得为2,f2(N1)得到的数值为5,则将数组下标为2和下表为5的位置置为1,如下图所示 同理,经过计算f1(N2)得到的数值得为3,f2(N2)得到的数值为6,则将数组下标为3和下表为6的位置置为1,如下图所示 这个时候,我

  • 手把手教你用Python打造一款属于你自己的个性二维码

    /前言/在现代社会中,我们出行坐公交经常会看到二维码,支付宝微信收款也会有二维码扫一扫,那么这些二维码是怎样生成的了,今天我们不研究二维码的原理,只教大家如何制作属于自己的二维码。/项目目标/自己用程序打造一款属于自己的个性二维码。/项目准备/编辑器:sublimetext3浏览器:360浏览器模块:MyQR/实现步骤/一、分析网站二维码生成在实践前我们可以先看看网站上的二维码生成。在这里我要分享一个二维码网址,算是知名度比较大的二维码在线生成工具:草料二维码。它支持很多种生成二维码的方式:可以看出生成种类还是挺丰富的,基本上能满足我们所有的要求,而且他还有很多其他丰富的功能。最重要的是所有功能都免费。 这样就完成了一个文本二维码,我们只要用扫码工具一扫就能看到‘任性的90后boy’这几个字。 二、模块生成下面我们来用命令集制作属于自己的二维码,今天给大家介绍一个神器:myqr模块。它的操作方法比较简单,只需在cmd窗口中操作即可。1.安装pipinstallmyqr复制2.基本用法 可以看出它生成一张照片,而且我把它找出来了,真的太机智啦~打开我的微信一扫,显示的就是‘/?’,原谅我

  • 基于FPGA的以太网控制器(MAC)设计(下)

    大侠好,欢迎来到FPGA技术江湖,江湖偌大,相见即是缘分。大侠可以关注FPGA技术江湖,在“闯荡江湖”、"行侠仗义"栏里获取其他感兴趣的资源,或者一起煮酒言欢。 今天给大侠带来基于FPGA的以太网控制器(MAC)设计,由于篇幅较长,分三篇。今天带来第三篇,下篇,程序的仿真与测试和总结。话不多说,上货。导读当前,互联网已经极大地改变了我们的生产和生活。与之相适应的,在嵌入式系统的研究开发方面,也越来越重视网络功能。嵌入式系统已经不再局限于一个个孤立的控制、处理单元,而是走向网络集成化,从而实现了多个系统的集中控制、信息共享。以太网(Ethernet)技术在嵌入式系统上的开发应用,已经成为当前嵌入式研究领域的技术热点之一。一方面,与传统的RS-485、CAN等相比较,以太网更加高速、通用,而且还可以直接与Internet相连接,提供更大范围的远程访问;此外,经过适当剪裁和优化的TCP/IP协议栈,也完全可以适应工业用途的需求。另一方面,相对于新兴的USB2.0、IEEE1394等总线,以太网技术在传输距离、布线成本以及控制软件的通用性上都有明显的优势。基于以太网的嵌入式

  • 2020.7.2日报:禁用IE的证书管理弹窗

    IE有很多比较恶心的弹窗。一般是用putsilient禁用。但ie的证书弹窗,禁用了的话,页面就不继续加载了。目前发现有三种方法。一种是直接hook掉InternetErrorDlg。直接不弹窗。注意hook函数里不是直接返回0,要:    DWORDold_flags=0;     DWORDreturn_bytes=sizeof(DWORD);     InternetQueryOption(hRequest,99,&old_flags,&return_bytes);    ignore_flags|=old_flags;     InternetSetOption(hRequest,99,&ignore_flags,sizeof(ignore_flags));这样设置一下。第二种方法,翻了下windows源码,见:private\inet\urlmon\iapp\cnethttp.cxxHRESULTCINetHttp::HttpSecurityProblem(HWND*phwnd,DWORDdwProblem)里面有句_pHttSecurity->

  • 13块钱DIY微信小程序远程浇花神器

    前言去年7月的时候,公司办了一场王者荣耀大赛,我和同事们也报名参加了。首局比赛就给我们泼了冷水,“深圳湾一号业主”无情摧残了“祖国的花朵”。作为“祖国的花朵”队的替补射手,我心如刀割。“为什么这样对祖国的花朵?你们平常不种花的吗?” “没办法啊,你知道深圳湾一号这种房子很大的,每天浇花得走好久。” “哼!总有一天我会让你们明白!”小能手当时就下了决心,必须要让“深圳湾一号业主”明白,要让他们明白,房子再大也是可以轻松浇花的!​没过几天,小能手就基于腾讯云物联网开发平台做出来一个浇花器,随时随地打开微信小程序就可以查看盆栽的土壤情况,并且进行远程浇花。这样,长期出差的朋友,以及阳台路程达10分钟的业主们,都得以轻松呵护自己的花花草草。这篇文章梳理了当时的方案设计和实现,给朋友们做个参考。腾讯云IoTExplorer是腾讯云主推的一站式物联网开发平台,IoT小能手从设备侧开发、平台功能操作、应用侧开发三个部分来进行学习分享,另外还分享了一些动手实践作品及收录官方发布的产业合作案例,帮助读者更好地理解整个开发链路。详情可点此查看。 1方案简介1.1总体方案端侧通过TencentOStiny定

  • SAP C4C计价(Pricing)中折扣(Discount)的使用

    SAPCloudforCustomer允许为某一个特定的客户创建折扣主数据。工作中心Products,视图DiscountLists,新建一个CustomerDiscount: 下图的含义是ID为1的客户享受10%的折扣。 下面创建一个新的销售订单,Account字段选择成上述ID为1的Account,果然发现10%的折扣生效了。从ListPrice10USD1ea能看出,本来这个产品的单价是10美元1个,但是因为10%的折扣对这个ID为1的客户生效,因此最后只需要9美元。 这个折扣基于销售订单的级别也是可以手动修改的,比如再加1个百分点的折扣。当然,Manuallychanged的标志位会打上,说明这个priceelement是人工修改过的。 关键字:SAP,SAP成都研究院,SAPCloudPlatform,CloudforCustomer,定价,pricing

  • Github 十个小时狂揽千赞:机器学习完整路线图

    导读:GitHub上一份机器学习完整路线引起了广泛关注,在短短的十个小时里已经收获了一千多个点赞。作者Giacomo回顾了自己三四年间学习机器学习的心路历程,毫无保留的分享出自己收藏的各种学习资源,工程,工具,awosome集合,教程以及各种实践经验。Github链接:https://github.com/clone95/Machine-Learning-Study-Path-March-2019/tree/master/Career%20Paths/Machine%20Learning%20Engineer%20Career%20Path作者强烈建议购买由Oreilly撰写的《用SciKit学习和TensorFlow进行机器学习》这本书,它给作者很强的激励,并推动了他所列出的大部分内容的组织和层次结构。所有内容都是开源和免费的,其中大部分来自世界著名的大学和开源协会。整个机器学习完整路线图被分为四个部分:1.预备知识• Python• JupyterNotebook• TheMathyouneed• TheMachineLearninglandscape2.基于Scikit-Lear

  • Oracle Net Services - Tracing and Logging at a Glance

       OracleNettrace用于跟踪或调试oracle连接故障,连接异常断开或者连接超时等情形,通过产生详细的跟踪信息来进行分析和诊断OracleNet相关故障。关于这个网络调试主要是通过为相关的网络配置文件添加相关的参数来实现。MetaLink上ID219968.1有详尽的描述。一、Oracletrace的相关参数 TRACE_LEVEL_[CLIENT|SERVER|LISTENER]    =[0-16|USER|ADMIN|SUPPORT|OFF]  TRACE_FILE_[CLIENT|SERVER|LISTENER]     =<FILENAME>  TRACE_DIRECTORY_[CLIENT|SERVER|LISTENER]=<DIRECTORY>  TRACE_UNIQUE_[CLIENT|SERVER|LISTENER]   =[ON|TRUE|OFF|FALSE]  TRACE_TIMESTAMP_[CLIENT|SERVER|LISTENER]=[ON|TRUE|OFF|FALSE]#Oracle8i+  TRACE_FILELE

  • 每个人都应该知道的十个机器学习常识

    当别人在高谈阔论机器学习时,你却插不上嘴,这是一种怎样的体验?不懂机器学习没有关系,但你一定要知道下面的十个机器学习基本常识。曾经在Endeca、谷歌和LinkedIn领导机器学习开发的DanielTunkelang为我们概括总结了这十个常识。1.机器学习就是从数据中挖掘洞见,而人工智能是炒作。只要使用了正确的训练数据和算法,机器学习可以解决大部分问题。而所谓的人工智能,只不过是一种包装。只要有助于营销,你要把它叫作什么都可以。2.数据和算法是机器学习的核心,而数据更为重要。虽然人们热衷于研究机器学习算法,但数据才是机器学习的关键要素。机器学习可以没有复杂完备的算法,但没有高质量的数据就不行。3.如果你没有大量数据,就不要使用太复杂的模型。机器学习根据输入参数来探索模型空间,参数越多,越有可能出现过拟合,所以应该要尽量遵循简单模型的原则。4.机器学习的成果取决于数据的质量。种瓜得瓜,种豆得豆。机器学习只能发现已经存在于数据中的模式。比如在解决分类问题时,就要求训练数据具有清晰的特征。5.只有当训练数据具有代表性时,机器学习才能奏效。过去不能代表未来。要时刻警惕训练数据和生产数据之间出现

  • 老九门——任务交接博客

    老九门——任务交接博客 这个作业属于哪个课程 2021春软件工程实践S班(福州大学) 这个作业要求在哪里 (https://edu.cnblogs.com/campus/fzu/FZUSESPR21/homework/12108) 团队名称 老九门 这个作业的目标 用于下个学期的任务交接 其他参考文献 CSDN、博客园 目录老九门——任务交接博客文档链接及项目仓库文档链接项目仓库项目的可运行链接配图功能介绍和使用说明1.资源管理2.课程活动3.答疑讨论4.学科成绩5.学生管理6.作业页面(学生)7.总成绩分析(学生)设想在已有基础上可以迭代开发的新功能 文档链接及项目仓库 文档链接 代码规范+Alpha冲刺任务与计划 Alpha冲刺第一天 Alpha冲刺第二天 Alpha冲刺第三天 Alpha冲刺第四天 Alpha冲刺第五天 Alpha冲刺第六天 Alpha冲刺第七天 Alpha冲刺第八天 Alpha冲刺第九天 Alpha冲刺第十天 Alpha测试随笔 Alpha冲刺总结 换组交接博客 alpha阶段问题总结随笔 凡事预则立随笔 代码规范 Bet

  • 一、对象导论

    一、Java语言的五个基本特性: 1.万物皆为对象 2.程序是对象的集合,他们通过发送消息来告知彼此所要做的 3.每个对象都有自己的由其他对象所构成的存储 4.每个对象都有其类型 5.某一特定类型的所有对象都可以接收同样的消息   二、每个对象都只能满足某些请求,这些请求由对象的接口所定义。   三、每个对象都提供服务,将对象看成服务者,有助于提高对象的内聚性。   四、访问控制 1.让客户端程序员无法触及他们不应该触及的部分 2.允许库设计者更可以改变内部的工作方式而不用担心会影响到使用者 3.四种权限publicprivateprotecteddefault   五、代码复用是面向对象编程最大的优点,引用对象就是最简单的复用。   六、类型不仅仅只是描述了作用于一个对象集合上的约束条件,同时还有与其他类型之间的联系   两种可以使基类和子类产生差异的方法     1.直接添加新方法     2.覆盖原有方法   七、多态性。被将导出类看做他的基类的过程称为向上转型 (P10)   八、Java具有单根继

  • {VS2010C#}{WinForm}{ActiveX}VS2010C#开发基于WinForm的ActiveX控件

    在VS2010中使用C#开发基于WinForm的ActiveX控件 常见的一些ActiveX大部分是使用VB、Delphi、C++开发,使用C#开发ActiveX要解决下面三个问题: 使.NET组件可以被COM调用 在客户机上注册后,ActiveX控件能通过IE的安全认证 已在客户机上注册时,安装包能通过IE的签名认证 配置:win7,VS2010 步骤第一步,创建控件 1.创建WinForm控件,命名为WebForm,如图1:   2.设置项目的Assembly属性,如图2所示,并对MakeAssemblyCom-Visible选项划钩 并且设置项目的编译选项,如图3所示,对RegisterforCOMInterop选中对COM组件进行注册。(注意,此处如果实在debug状态下修改的,那在调到release状态下还需要再设置一次。)   3.打开AssemblyInfo文件添加引用usingSystem.Security;并且添加[assembly:AllowPartiallyTrustedCallers()]语句 usingSystem.Reflec

  • zookeeper、solrcloud、rediscluster集群解决方案

                集群解决方案                     课程目标 目标1:说出什么是集群以及与分布式的区别 目标2:能够搭建Zookeeper集群 目标3:能够搭建SolrCloud集群 目标4:能够搭建RedisCluster集群 1.集群概述 1.1什么是集群 1.1.1集群概念 集群是一种计算机系统,它通过一组松散集成的计算机软件和/或硬件连接起来高度紧密地协作完成计算工作。在某种意义上,他们可以被看作是一台计算机。集群系统中的单个计算机通常称为节点,通常通过局域网连接,但也有其它的可能连接方式。集群计算机通常用来改进单个计算机的计算速度和/或可靠性。一般情况下集群计算机比单个计算机,比如工作站或超级计算机性能价格比要高得多。     1.1.2集群的特点 集群拥有以下两个特点: 1.   可扩展性:集群的性能不限制于单一的服务实体,新的服务实体可以动

  • 第四章 模块化React和Redux应用

    第四章模块化React和Redux应用 4.1模块化应用要点 构建一个应用的基础:   代码文件的组织结构;   确定模块的边界;   Store的状态树设计。 4.2代码文件的组织方式 4.2.1按角色组织   在MVC中,应用代码分为Controller、Model、View,分别代表三种模块角色。分别放到controllers、models、views目录下。   在Redux应用的构建中,把目录换成了:   reducer:目录中包含所有的Redux的reducer;   actions:包含所有action构造函数;   components:包含所有的傻瓜组件;   containers:包含所有的容器组件。 4.2.2按功能组织   Redux应用适合于“按功能组织”,也就是把完成同一应用功能的代码放在一个目录下,一个应用功能包含多个角色的代码。应用功能对应的就是用户界面上的交互模块。    4.3模块接口 低耦合性:不同功能模块之间的依赖关系应该简单而助清晰; 高内聚性:一个模块应该把自己的功能封装的很好,让外界不要太依赖于自己内部的结构,这样

  • 微信小程序及各种平台对接常用可逆加密算法aes256

    不同程序之间经常会交换数据,我们经常采用的套路是: 假设要传输的信息是json,我们假设其为json_data,通过http传递信息为 json_data_encode=json_data&sign=md5(json_data+key) 接收方通过验证sign就知道内容有没有被篡改. 但是,这样json_data作为明码传送会让我们不太开心,所以今天的我们要介绍的aes256出马了,他是一强度很高的可逆加密算法! aes256加密出来的内容是二进制的,不好通过http协议传输,所以我们再配合上base64转成ascii码 加密前,aes256要求字节数必须是32字节的倍数,所以使用pkcs7进行填充可以解决问题..介绍完原理,直接贴代码 写了3个版本,openresty及python和php的...请查收 localaes=require'resty.aes' localbase64_encode=ngx.encode_base64 localbase64_decode=ngx.decode_base64 localkey="a12e93c9edadeaa47eb1aeab

  • kmp dp hdu 3336

    Countthestring TimeLimit:2000/1000MS(Java/Others)    MemoryLimit:32768/32768K(Java/Others)TotalSubmission(s):17918    AcceptedSubmission(s): 8106 http://acm.hdu.edu.cn/showproblem.php?pid=3336 ProblemDescription ItiswellknownthatAekdyCoinisgoodatstring problemsaswellasnumbertheoryproblems.Whengivenastrings,wecanwrite downallthenon-emptyprefixesofthisstring.Forexample:s:"abab"The prefixesare:"a","ab","aba","abab"Foreachprefix,wecancountthe timesitmatchesins

  • SFTP 文件上传下载工具类

    SFTPUtils.java importcom.jcraft.jsch.*; importcom.jcraft.jsch.ChannelSftp.LsEntry; importlombok.extern.slf4j.Slf4j; importorg.springframework.stereotype.Component; importjava.io.File; importjava.io.FileInputStream; importjava.io.FileOutputStream; importjava.util.Properties; importjava.util.Vector; @Component @Slf4j publicclassSFTPUtils{ privateSFTPUtilsinstance=null; privateChannelSftpsftp; publicFiledownloadFtpFile(StringftpHost,StringftpUserName,StringftpPassword,intftpPort,StringftpPath,

  • 将数据库的坐标集封装进百度地图显示

      举个例子:大家都使用过摩拜单车吧,打开首页就是一对红点,红点就是单车的坐标   静态页面就不分享了,大家引入一个百度地图。 下面就撸代码了 <scripttype="text/javascript"src="//api.map.baidu.com/api?v=2.0&ak=********"></script>复制   百度地图的Ak需要自己申请,   直接上代码了,由于没有什么技术难度 //百度地图API功能 varmap=newBMap.Map("allmap"); map.enableScrollWheelZoom(true); //定位,获取位置,并添加图标 getCurrent(); functiongetCurrent(){ map.clearOverlays(); vargeolocation=newBMap.Geolocation(); geolocation.getCurrentPosition(function(r){ if(this.getStatus()==BMAP_STATUS_SUCCESS){ //由于地

  • java servlet 中遇到的编码问题

    1.get request 编码问题 ccc111 2.getresponse 编码问题 3.post 编码问题  

  • 释放你的潜能

    ​世界上大部分人都是在平庸中度过一生,他们上班应付工作,回家上网,看电视。他们既没有目标,也没有计划,更没有尝过成功的滋味,不知成就感为何物。你是他们中的一员吗?你甘愿过这样的生活吗?如果你的答案是否定的,那么就学着给自己确定目标并制定行动计划吧! ​ 人生重要的不是所站的位置,而是所朝的方向。——奥利弗.温德尔.霍姆斯 目标可以使你跨越任何障碍,让你的前途不可限量。假如天赋和能力可以让你实现你为自己制定的任何目标,那么你究竟想成为什么样的人?你想拥有什么?做到什么呢? 为了释放你的全部潜能,你应该培养这样一个习惯,就是每天都制定计划并加以实施,直到你的生命的最后时刻。 目标可以让我们获得幸福,可以让我们的生活变得更好,还可以让我们成为世界顶尖的3%中的一员。制定目标,每天朝着它努力,最后实现,是我们获得幸福的关键。对于你想得到的东西,要不停的努力去获取它,除此之外没有什么能确保你生活得长久,幸福,健康,富有。 古希腊哲学家亚里士多德曾经这样说:人是一种为目的而生存的生物。“目的”这个词源自于古希腊语,它的词根在古希腊语里的意思就是“目标”。只有当你所做的事情让你离你想得到的东

相关推荐

推荐阅读