虾皮一面:手写一个Strategy模式(策略模式)

news2025/1/17 21:48:46

说在前面

在40岁老架构师 尼恩的读者交流区(50+)中,最近有指导一个小伙伴面试架构师,面试的公司包括虾皮、希音、美团等大厂,目标薪酬50K以上,遇到了一个比较初级的问题:

  • 请手写一个Strategy模式(策略模式)
  • 或者请手写一个template模式(模板模式)
  • 或者请手写一个proxy模式(代理模式)

小伙伴却忘了, 其他都准备的好好的,结果在这个基础知识的地方,摔了大跟头

这里尼恩给大家做一下系统化、体系化的梳理,使得大家可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”

也一并把这个题目以及参考答案,收入咱们的 《尼恩Java面试宝典》V85版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。

最新《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》 的PDF文件,请到公众号【技术自由圈】获取。

文章目录

    • 说在前面
    • 策略模式(Strategy Pattern)的定义
    • 策略模式的场景分析
    • 策略模式的主要角色
    • 策略模式的Java实现
      • step1:创建抽象策略类
      • step2:创建具体策略
      • step3:创建环境类
      • step4:创建客户类
    • 策略模式的GO代码实现
    • 策略模式的优缺
      • 优点
      • 缺点
    • 关于策略模式的讨论
    • 策略模式的应用场景
    • 策略模式和工厂模式的区别
      • 工厂模式
      • 策略模式
    • 说在最后
    • 推荐相关阅读

策略模式(Strategy Pattern)的定义

策略模式是属于设计模式中的行为模式中的一种,策略模式主要解决选项过多的问题,避免大量的if else 和 switch下有太多的case。

策略模式的重心不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性

策略(Strategy)模式:

  • 该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换
  • 策略模式让算法独立于使用它的客户而变化。

策略是个形象的表述,所谓策略就是方案,日常生活中,要实现目标,有很多方案,每一个方案都被称之为一个策略

打个比方说,我们出门的时候会选择不同的出行方式,比如骑自行车、坐公交、坐火车、坐飞机、坐火箭等等,这些出行方式,每一种都是一个策略。

再比如我们去逛商场,商场现在正在搞活动,有打折的、有满减的、有返利的等等,其实不管商场如何进行促销,说到底都是一些算法,这些算法本身只是一种策略,并且这些算法是随时都可能互相替换的,比如针对同一件商品,今天打八折、明天满100减30,这些策略间是可以互换的。

在软件开发中也常常遇到类似的情况,实现某一个功能有多个途径,此时可以使用一种设计模式来使得系统可以灵活地选择解决途径,也能够方便地增加新的解决途径,这就是策略模式。

策略模式的场景分析

这个模式使得我们可以在根据环境或者条件的不同选择不同的策略来完成该任务。

先看下面的图片,我们去旅游选择出行模式有很多种,可以骑自行车、可以坐汽车、可以坐火车、可以坐飞机。

作为一个程序猿,开发需要选择一款开发工具,当然可以进行代码开发的工具有很多,可以选择Idea进行开发,也可以使用eclipse进行开发,也可以使用其他的一些开发工具。

在软件开发中,我们也常常会遇到类似的情况,实现某一个功能有多条途径,每一条途径对应一种算法,此时我们可以使用一种设计模式来实现灵活地选择解决途径,也能够方便地增加新的解决途径。

策略模式的的最大优势: 方便代码的功能横向扩展,策略模式将解决途径进行封装有利于我们对解决方式的增加或删除。

同时,策略模式(Strategy Pattern) 也符合开闭原则

策略模式的主要角色

在策略模式中,我们可以定义一些独立的类来封装不同的算法,每一个类封装一种具体的算法,在这里,每一个封装算法的类我们都可以称之为一种策略(Strategy),为了保证这些策略在使用时具有一致性,一般会提供一个抽象的策略类来做规则的定义,而每种算法则对应于一个具体策略类。

策略模式涉及到三个角色,具体如下:

  • 抽象策略(Strategy)类:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口,所有具体的策略类都要实现这个接口。环境(上下文)类Context 使用这个接口调用具体的策略类。
  • 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现或行为。
  • 环境(Context)类:用于配置一个具体的算法策略对象 ,维持一个策略接口类型的引用( Reference ),并且可以定义一个让接口 Strategy 的具体对象访问的接口。在简单情况下,Context 类可以省略。

策略模式是一个比较容易理解和使用的设计模式,策略模式是对算法的封装,它把算法的责任和算法本身分割开,委派给不同的对象管理。

策略模式通常把一个系列的算法封装到一系列具体策略类里面,作为抽象策略类的子类。

在策略模式中,对环境类和抽象策略类的理解非常重要,环境类是需要使用算法的类。在一个系统中可以存在多个环境类,它们可能需要重用一些相同的算法。

在客户端代码中只需注入一个具体策略对象,可以将具体策略类类名存储在配置文件中,通过反射来动态创建具体策略对象,从而使得用户可以灵活地更换具体策略类,增加新的具体策略类也很方便。

策略模式提供了一种可插入式(Pluggable)算法的实现方案。

策略模式的主要目的是将算法的定义与使用分开,也就是将算法的行为和环境分开,将算法的定义放在专门的策略类中,每一个策略类封装了一种实现算法,使用算法的环境类针对抽象策略类进行编程,符合“依赖倒转原则”。在出现新的算法时,只需要增加一个新的实现了抽象策略类的具体策略类即可。

策略模式的Java实现

1.创建抽象策略类

2.创建具体策略

(1)具体策略A

(2)具体策略B

(3)具体策略N…

3.创建环境类

step1:创建抽象策略类

  • 定义所有持的算法的公共接口。
  • 所有具体的策略类都要实现这个接口。
  • context使用这个接口来调用某concreteStrategy定义的算法;

定义百货公司所有促销活动的共同接口

package com.crazymakercircle.designpattern.strategy;

//抽象策略类
public interface Strategy {
    void show();
}

step2:创建具体策略

进一步拆分策略类 ,将每个促销算法都单独封装在一个类中,也就是将一个类拆分成几个类,每个类都单独封装一个促销策略算法。

这样一来,修改一个算法只需重新编译算法所涉及的那个类,而不需要重新编译其他类。如果想要添加一个新的算法 只需在子类的集合中再添加一个新的封装该算法的类即可。

定义具体策略角色(Concrete Strategy):每个节日具体的促销活动

//为春节准备的促销活动A
public class StrategyA implements Strategy {

    public void show() {
        System.out.println("买一送一");
    }
}

//为中秋准备的促销活动B
public class StrategyB implements Strategy {

    public void show() {
        System.out.println("满200元减50元");
    }
}

//为圣诞准备的促销活动C
public class StrategyC implements Strategy {

    public void show() {
        System.out.println("满1000元加一元换购任意200元以下商品");
    }
}

step3:创建环境类

Context 通常根据配置, 加载和初始化具体的 ConcreteStrategy, 配置的方式是多样化的:

  • 系统环境变量
  • xml文件
  • 数据库
  • 等等

Context将它的客户的请求转发给它的Strategy。

client 仅与Context交互。客户通常从 context 获取 ConcreteStrategy,这样, Context 通常有一系列的ConcreteStrategy类可供 客户从中选择。

package com.crazymakercircle.designpattern.strategy;

import lombok.Data;

@Data
public class Context {

    String type = System.getenv("strategy");
    Strategy strategy = null;

    public Context() {
        switch (type) {
            case "1":
                strategy = new StrategyA();
                break;
            case "2":
                strategy = new StrategyB();
                break;
            case "3":
                strategy = new StrategyC();
                break;
            default:
                strategy = new StrategyA();
        }
    }
}

运行的时候,设置好环境变量

step4:创建客户类

策略模式的GO代码实现

下面我们就开始以GO代码的形式来展示一下策略模式吧,代码很简单,我们用一个加减乘除法来模拟。

首先,我们看到的将会是策略接口和一系列的策略,这些策略不要依赖高层模块的实现。

package strategy
/**
 * 策略接口
 */
type Strategier interface {
    Compute(num1, num2 int) int
}

很简单的一个接口,定义了一个方法Compute,接受两个参数,返回一个int类型的值,很容易理解,我们要实现的策略将会将两个参数的计算值返回。
接下来,我们来看一个我们实现的策略,

package strategy
import "fmt"

type Division struct {}

func (p Division) Compute(num1, num2 int) int {
    defer func() {
        if f := recover(); f != nil {
            fmt.Println(f)
            return
        }
    }()

    if num2 == 0 {
        panic("num2 must not be 0!")
    }

    return num1 / num2
}

为什么要拿除法作为代表呢?因为除法特殊嘛,被除数不能为0,其他的加减乘基本都是一行代码搞定,除法我们需要判断被除数是否为0,如果是0则直接抛出异常。
ok,基本的策略定义好了,我们还需要一个工厂方法,根据不用的type来返回不同的策略,这个type我们准备从命令好输入。

func NewStrategy(t string) (res Strategier) {
    switch t {
        case "s": // 减法
            res = Subtraction{}
        case "m": // 乘法
            res = Multiplication{}
        case "d": // 除法
            res = Division{}
        case "a": // 加法
            fallthrough
        default:
            res = Addition{}
    }

    return
}

这个工厂方法会根据不用的类型来返回不同的策略实现,当然,哪天我们需要新增新的策略,我们只需要在这个函数中增加对应的类型判断就ok。

现在策略貌似已经完成了,接下来我们来看看主流程代码,一个Computer,

package compute

import (
    "fmt"
    s "../strategy"
)

type Computer struct {
    Num1, Num2 int
    strate s.Strategier
}

func (p *Computer) SetStrategy(strate s.Strategier) {
    p.strate = strate
}

func (p Computer) Do() int {
    defer func() {
        if f := recover(); f != nil {
            fmt.Println(f)
        }
    }()

    if p.strate == nil {
        panic("Strategier is null")
    }

    return p.strate.Compute(p.Num1, p.Num2)
}

这个Computer中有三个参数,Num1Num2当然是我们要操作的数了,strate是我们要设置的策略,可能是上面介绍的Division,也有可能是其他的,在main函数中我们会调用SetStrategy方法来设置要使用的策略,Do方法会执行运算,最后返回运算的结果,可以看到在Do中我们将计算的功能委托给了Strategier

貌似一切准备就绪,我们就来编写main的代码吧。

package main

import (
    "fmt"
    "flag"
    c "./computer"
    s "./strategy"
)

var stra *string = flag.String("type", "a", "input the strategy")
var num1 *int = flag.Int("num1", 1, "input num1")
var num2 *int = flag.Int("num2", 1, "input num2")

func init() {
    flag.Parse()
}

func main() {
    com := c.Computer{Num1: *num1, Num2: *num2}
    strate := s.NewStrategy(*stra)

    com.SetStrategy(strate)
    fmt.Println(com.Do())
}

首先我们要从命令行读取要使用的策略类型和两个操作数,在main函数中,我们初始化Computer这个结构体,并将输入的操作数赋值给ComputerNum1Num2,接下来我们根据策略类型通过调用NewStrategy函数来获取一个策略,并调用ComputerSetStrategy方法给Computer设置上面获取到的策略,最后执行Do方法计算结果,最后打印。

就是这么简单,现在我们在命令行定位到main.go所在的目录,并执行一下命令来编译文件

go build main.go

继续执行命令

main -type d -num1 4 -num2 2

来尝试一下使用加法策略操作4和2这两个数,来看看结果如何,

结果很正确,换一个策略试试,来个乘法吧,执行命令

main -type m -num1 4 -num2 2

结果也是正确的。

策略模式的优缺

优点

  1. 策略模式的关注点不是如何实现算法,而是如何组织、调用这些算法,从而让程序结构更灵活,具有更好的维护性和扩展性。
  2. 策略模式中各个策略算法是平等的。对于一系列具体的策略算法,地位是完全一样的。正因为这个平等性,才能实现算法之间可以相互替换。所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。所以可以这样描述这一系列策略算法:策略算法是相同行为的不同实现。
  3. 运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。

如果所有的具体策略类都有一些公有的行为。这时候,就应当把这些公有的行为放到共同的抽象策略角色 Strategy 类里面。当然这时候抽象策略角色必须要用 Java 抽象类实现,而不能使用接口。但是,编程中没有银弹,策略模式也不例外,也有一些缺点,先来回顾总结下优点:

  1. 策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
  2. 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免代码重复。
  3. 使用策略模式可以避免使用多重条件(if-else)语句。多重条件语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重条件语句里面,比使用继承的办法还要原始和落后。

缺点

  1. 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。这种策略类的创建及选择其实也可以通过工厂模式来辅助进行。
  2. 由于策略模式把每个具体的策略实现都单独封装成为类,如果备选的策略很多的话,那么对象的数目就会很可观。可以通过使用享元模式在一定程度上减少对象的数量。

关于策略模式的讨论

策略模式还是算比较容易理解的,策略模式的核心就是将容易变动的代码从主逻辑中分离出来,通过一个接口来规范它们的形式,在主逻辑中将任务委托给策略。这样做既减少了我们对主逻辑代码修改的可能性,也增加了系统的可扩展性。

设计的核心原则:对扩展开发,对修改关闭

使用策略模式主要有两个出发点:

(1) 将一组相关的算法封装为各个策略分支,从而将策略分支相关的代码隐藏起来。

(2) 希望可以提升程序的可扩展性。

下面我们就策略模式的可扩展性进行简单的讨论,实际上 策略模式的初衷是要减少与各个分支下的行为相关的条件语句。这已经通过将一个具有条件相关的多种行为的类拆分成一个策略超类与若干个策略子类得到了解决。也就是说,将原来的一个单独的但是包含多个条件语句的类改变为一个没有条件语句的策略层次类。

这里虽然看似条件语句消失了,但是在客户程序与 Context 类中是否也不存在与策略子类相关的条件语句了呢?答案当然不是。

实际上一般在策略模式的设计中 客户类根据不同的条件负责创建不同的策略子类的对象,然后再将该对象传递给 Context 环境类,Context 类的作用可以理解为:为被调用策略子类的一些方法提供一些参数,以及使用该由 Client 类传入的对象去调用 Strategy 类的某些方法。

这说明 在客户类 Client 中 存在许多与策略分支子类相关的条件语句,而在 Context 类中,没有这样的语句。

那么 是否可以将创建策略子类的对象的责任交给 Context 类,而客户类 Client 只为 Context 类提供一些代表客户请求的参数呢?

(1) 客户类负责创建策略子类的对象的情况

客户类根据用户提供的不同的请求,负责创建不同的策略子类的对象 ,然后再将该对象传递给 Context 类。在这种情况下,客户类中通常包含与策略相关的条件语句,而在 Context 类中不必使用任何与策略有关的条件语句,因此,修改或者添加一个策略子类都不必修改 Context 类。但是,在添加一个新的策略子类的情况下,如果客户类需要使用该子类,往往需要在客户类中添加一个新的条件语句,即客户类需要修改。

(2) Context 类负责创建策略子类的对象的情况

将创建策略子类的对象的责任交给 Context 类, 而客户类 Client 只为 Context 类提供一些代表客户请求的参数 ;在此情况下,Context 类在创建策略子类的对象时,必然会使用与策略子类有关的条件语句。此时,修改一个策略子类不需要修改客户类与 Context 类。而在添加一个新的策略子类时,如果此时客户类暂时不使用该新的子类,则新子类的添加不会影响客户类与 Context 类的源代码。但是,如果客户类要使用新的策略子类,则必须同时在客户类与 Con-text 类中添加新的条件分支,也就是说,需要同时修改客户类与 Context 类

在以上两种情况下,当只是需要修改策略子类的代码时,客户类与 Context 类都不需要进行修改。

综上所述 由客户类创建对象的设计可扩展性好一些。这样,可以做到在 Context 类中出现与策略子类相关的条件语句,从而可扩展性也得到了提高。

策略模式的应用场景

  • 多个类只有算法或行为上稍有不同的场景
  • 算法需要自由切换的场景
  • 需要屏蔽算法规则的场景
  • 出行方式,自行车、汽车等,每一种出行方式都是一个策略
  • 商场促销方式,打折、满减等

策略模式和工厂模式的区别

工厂模式

  1. 目的是创建不同且相关的对象
  2. 侧重于"创建对象"
  3. 实现方式上可以通过父类或者接口
  4. 一般创建对象应该是现实世界中某种事物的映射,有它自己的属性与方法

策略模式

  1. 目的实现方便地替换不同的算法类
  2. 侧重于算法(行为)实现
  3. 实现主要通过接口
  4. 创建对象对行为的抽象而非对对象的抽象,很可能没有属于自己的属性

说在最后

手写一些基础的设计模式,是非常常见的面试题。

以上2大方案,如果大家能对答如流,如数家珍,基本上 面试官会被你 震惊到、吸引到。

最终,让面试官爱到 “不能自已、口水直流”, 同时 offer, 也就来了。

学习过程中,如果有啥问题,大家可以来 找 40岁老架构师尼恩沟通。

推荐相关阅读

《从0开始,手写Redis》

《从0开始,手写MySQL事务管理器TM》

《从0开始,手写MySQL数据管理器DM》

《京东太猛,手写hashmap又一次重现江湖》

《网易一面:如何设计线程池?请手写一个简单线程池?》

《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》PDF,请到下面公号【技术自由圈】取↓↓↓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/755317.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于物联网技术的养老院管理系统设计与实现_kai

基于物联网技术的养老院管理系统设计与 实现 摘 要 随着我国老年人口数量的逐年增加,人口抚养比也在迅速攀升,越来越多的老年人将走 出家门进入养老院安度自己的晚年。同时国家和地方也相继出台了加快发展老龄事业的政策 方针,作为机构养老…

Shell之循环语句 —— For 实验

循环 循环就是重复执行一段代码的结构,通过循环可在满足一定的条件下,多次执行相同的代码。 循环语句:循环体 —— 代码的总结构 循环条件 —— 当循环条件满足时,循环体代码才会被执行,否则条件不满足…

SpringCloud Alibaba——Nacos中的Distro协议

一、Nacos中的Distro协议 Nacos 每个节点自己负责部分的写请求。每个节点会把自己负责的新增数据同步给其他节点。每个节点定时发送自己负责数据的校验值到其他节点来保持数据一致性每个节点独立处理读请求,及时从本地发出响应。新加入的 Distro 节点会进行全量数据…

【高并发网络通信架构】3.引入IO多路复用(select,poll,epoll)实现高并发tcp服务端

目录 一,往期文章 二,基本概念 IO多路复用 select 模型 poll 模型 epoll 模型 select,poll,epoll 三者对比 三,函数清单 1.select 方法 2.fd_set 结构体 3.poll 方法 4.struct pollfd 结构体 5.epoll_cre…

前端uni-app自定义精美全端复制文本插件,支持全端文本复制插件 可设置复制按钮颜色

随着技术的发展,开发的复杂度也越来越高,传统开发方式将一个系统做成了整块应用,经常出现的情况就是一个小小的改动或者一个小功能的增加可能会引起整体逻辑的修改,造成牵一发而动全身。 通过组件化开发,可以有效实现…

读数据压缩入门笔记07_自适应统计编码

1. 位置对熵的重要性 1.1. 为了计算概率总需要多遍历一次数据集,而在计算出整个数据集中各符号的出现概率后,还要继续处理这些数值 1.1.1. 如果是相对较小的数据集,那么这些就不是什么问题 1.2. 随着要压缩的数据集变大,统计编…

Python异常值检测——案例分析

目录 1.单个变量异常值检测 2. 双变量关系中的异常值检测 3. 使用线性回归来确定具有重大影响的数据点 4. 使用k最近邻算法找到离群值 5. 使用隔离森林算法查找异常 1.单个变量异常值检测 如果某个值离平均值有多个标准偏差,并且远离近似标准正态分布的值&#…

Office如何通过VSTO进行WORD插件开发?

文章目录 0.引言1.工具准备2.WORD外接程序创建和生成3.外接程序生成并使用 0.引言 VSTO(Visual Studio Tools for Office )是VBA的替代,是一套用于创建自定义Office应用程序的Visual Studio工具包。VSTO可以用Visual Basic 或者Visual C#扩展…

在 3ds max 中创建逼真的镜像材质

推荐: NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 选项 1.平面镜面材料 步骤 1 首先,我们需要包含镜像对象和一个或多个镜像对象的场景。您可以在此处下载本教程中使用的场景,也可以使用您自己的场景和对象。对于第一个镜像选项&…

Unreal Engine 与 Blender - 比较指南

虚幻引擎和 Blender 是游戏开发人员中最常用的两种软件,它们在游戏开发工作流程中都有自己的用途和地位。作为进入视频游戏行业的初学者,可能很难从数十种软件中筛选找到最适合您需求的一款。希望本指南能够缓解这一困难并帮助您决定选择哪个软件。 虚幻…

【c++源码】瑞佳飞飞彩虹端分享老飞飞源码

里面功能包含。离线摆摊,内挂,宠物系统,宠物进阶,任意商店,回收装备,模型查看,个人排行榜,物品分解,全物品升级,钥匙开箱子,外观变更,…

电商数据采集方式有哪些

不管是做渠道管控、还是价格监测,数据采集都是基础,只有数据准确了,品牌才能更好的管控乱价、治理渠道。同时当品牌有数据分析需求时,对数据采集的要求也会越高。 力维网络有自主开发的数据采集监测系统,可为品牌提供多…

SpringCloud整合Sentinel

文章目录 1、Sentinel介绍2、安装Sentinel控制台3、微服务整合Sentinel 1、Sentinel介绍 阿里开源的流量控制组件官网:https://sentinelguard.io/zh-cn/index.html承接了阿里双十一大促流量的核心场景,如秒杀、消息削峰填谷、集群流量控制、实时熔断下游…

关于Java的网络编程

网络的一些了解 网络通信协议 链路层:链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。网络层:网络层是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组&…

【EXCEL】数据录入的快捷键和正确格式

目录 0.环境 1.内容概述 2.具体内容 2.1数据录入换行换列的快捷键(标准的数据输入方式) 2.2日期的正确格式和使用(标准日期格式与长日期) 2.2.1 标准日期 2.2.2 长日期 2.2.3 显示当前日期和时间的快捷键 2.3百分比的正确…

华为Mate60 Pro曝光:麒麟芯片9100 or 骁龙8Gen2+5G,7699元起,你觉得如何?

最近网上关于华为Mate60系列的爆料逐渐增多,尤其是对于新机到底支不支持5G,众说纷纭,而且老是变动。7月14日,有数码博主爆料称,华为Mate60系列确实分前期和后期版本,前期为了秀肌肉,会展示新的成…

更改el-select-dropdown_item selected选中颜色

更改el-select-dropdown_item selected选中颜色 默认为element主题色 在修改element select下拉框选中颜色时会发现不生效,原因是:el-select下拉框插入到了body中 解决办法: 在select标签里填写:popper-append-to-body"false"属性…

window关闭固定端口号

查看所有:netstat -ano 查看对应端口:netstat -ano|findstr "9004"关闭端口: 任务管理器中的详细信息 对应的PID就是占用的端口 关闭即可 命令行关闭端口: taskkill -PID 进程号 -F

基于weka手工实现多层感知机(BPNet)

一、BP网络 1.1 单层感知机 单层感知机,就是只有一层神经元,它的模型结构如下1: 对于权重 w w w的更新,我们采用如下公式: w i w i Δ w i Δ w i η ( y − y ^ ) x i (1) w_iw_i\Delta w_i \\ \Delta w_i\eta(y…

Java Jsp+Json+阿贾克斯

0目录 1.补充阿贾克斯 2.实战(加入Json) 1.补充阿贾克斯 创建工程,加入jason依赖和数据库 新建数据库,表和实体类 先新建一个查询方法 FruitServlet 修改Web.xml 加入Js包(版本1.9.1) …