带你认识工厂类设计模式——简单工厂工厂方法抽象工厂简单抽象工厂反射简单抽象工厂

news2024/10/7 20:29:34

工厂类设计模式

  • 简单工厂模式
    • 简单工厂模式类图
    • 简单工厂实现代码实现
    • 小结
  • 工厂方法模式
    • 工厂方法模式类图
    • 工厂方法模式代码实现
    • 小结
  • 抽象工厂模式
    • 抽象工厂模式类图
    • 抽象工厂模式代码实现
    • 小结:
  • 用简单工厂改进抽象工厂模式
    • 简单抽象工厂模式类图
    • 简单抽象工厂模式代码实现
    • 小结:
  • 反射+配置文件版简单抽象工厂模式
    • 反射+配置文件版简单抽象工厂模式代码
  • 总结

开始之前,我们需要了解三个知识点:
1.开闭原则:是说软件实体(类,模块,函数等)应该可以扩展,但是不能修改。对应扩展是开放的,对于更改是封闭的。开闭原则是面向对象设计的核心所在,遵循这个原则可以带来面向对象技术所声称的巨大好处,也就是可维护,可扩展,可复用,灵活性好。然而,对于应用程序中每个部分都刻意进行抽象同样不是一个好主意,拒接不成熟的抽象和抽象本身一样重要。
2.==代码灵活性:需要可维护,可扩展,可复用三个特性,然后考虑实现跨平台,可移植性等。==灵活性和可扩展性通常成对出现。
3.单一职责:就一个类而言,应该仅有一个引起它变化的原因。如果一个类承担的职责越多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或抑制这个类完成其他职责的能力,这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。

简单工厂模式

简单工厂模式类图

在这里插入图片描述
抽象算法类:用于被具体的算法类继承。
具体的算法类:继承了抽象算法类,根据具体的算法去重写抽象算法类中的方法。
算法工厂类:返回一个具体的算法对象。

简单工厂实现代码实现

为了后序方便理解,我们就一直使用这个例子,只是不断添加需求而已。
例子:买车 or 造车?现在我们需要一辆汽车代步。
在未学习简单工厂之前,面对一个这个需求,我们应该怎么去做?
直接写一个Car类,去实例化对象,或者写一个接口或抽象类,去实例它的实例化对象
我们这使用第二种方式:

//编写一个Car的接口
public interface Car {
    //制造车
    public void carName();
}
//编写一个BYD去实现Car接口,重写它的方法
public class BYD implements Car {
    @Override
    public void carName() {
        System.out.println("比亚迪汽车");
    }
}

//客户端代码
public class test {
    public static void main(String[] args) {
        BYD car = new BYD();
        car.carName();
    }
}
输出结果:比亚迪汽车

简单快捷,那为啥还要去写什么简单工厂?因为使创建对象和使用对象相分离,就好像现在你是客户,你需要一辆汽车代步,你是自己做还是去4s店中购买一辆?(现实要是可以这么简单自己就能做出的话,我愿意自己做!)自己new 一个对象就好像制作一样,直接使用,不用去了解具体构造才符合我们嘛。那我们去使用简单工厂试试怎么写。

//还是一个Car接口
public interface Car {
    //制造车
    public void carName();
}
//编写一个BYD去实现Car接口,重写它的方法
public class BYD implements Car {
    @Override
    public void carName() {
        System.out.println("比亚迪汽车");
    }
}
//编写一个车厂,从车厂中购买车
public class CarFactory {
    public Car buy(String type) {
        Car car = new BYD();
        return car;
    }
}
//客户端代码
public class test {
    public static void main(String[] args) {
        CarFactory carFactory = new CarFactory();
        Car car = carFactory.buy("BYD");
        car.carName();
    }
}
输出结果:比亚迪汽车

哎?确实不用去直接new 一个车对象了,但是我们不是还去new 了一个车厂类嘛?这和之前的有啥不同?别急,谁规定车厂只卖一种车的。

//还是一个Car接口
public interface Car {
    //制造车
    public void carName();
}
//编写一个BYD去实现Car接口,重写它的方法
public class BYD implements Car {
    @Override
    public void carName() {
        System.out.println("比亚迪汽车");
    }
}
//再编写一个BENZ去实现Car接口,重写它的方法
public class BENZ implements Car {
    @Override
    public void carName() {
        System.out.println("奔驰汽车");
    }
}
//编写一个车厂,从车厂中购买车
public class CarFactory {

    public Car choice(String type) {
        Car car = null;
        switch (type) {
            case "BYD":
                car = new BYD();
                break;
            case "BENZ":
                car = new BENZ();
                break;
        }
        return car;
    }
}
//客户端代码
public class test {
    public static void main(String[] args) {
        CarFactory carFactory = new CarFactory();
        Car car = carFactory.choice("BYD");
        car.carName();
        Car car1 = carFactory.choice("BENZ");
        car1.carName();
    }
}
输出结果:比亚迪汽车
		 奔驰汽车

小结

现在,是不是看出什么区别了,没错,当我们有多个对象被同一个父类修饰时,我们就可以去使用简单工厂模式去灵活的创建对象。但是它也不是没有弊端,我们可以灵活的去创建对象是因为我们使用了分支语句switch去做了逻辑判断。现在我们要再添加一个品牌的汽车,是不是再创建一个品牌类就行。但是我们要灵活的去创建对象的话就需要去修改switch语句了。这样我们就违背了一个设计模式的重要的原则——开闭原则。


工厂方法模式

简单工厂违背了开闭原则,所以工厂方法模式就诞生了。

工厂方法模式类图

在这里插入图片描述
抽象父类:具体实现类所继承或实现的公共父类
具体实现类:继承或实现公共父类
工厂抽象类:为了符合开闭原则,定义的一个工厂抽象类
子工厂类,每个指定的子工厂创建对应的对象

工厂方法模式代码实现

接着上面的例子:
上面我们使用一个工厂创建所有对象,使用switch语句来使代码更加灵活。但是,如果新增一个产品势必会去修改switch语句,这就不符合开闭原则了。
为此,我们需要学习工厂方法模式:
多话不说,上代码!

//一个公共接口
public interface Car {
    public void carName();
}
//编写一个BYD去实现Car接口,重写它的方法
public class BYD implements Car {
    @Override
    public void carName() {
        System.out.println("比亚迪汽车");
    }
}
//再编写一个BENZ去实现Car接口,重写它的方法
public class BENZ implements Car {
    @Override
    public void carName() {
        System.out.println("奔驰汽车");
    }
}
//为了不去修改switch语句,我们直接不使用它了,改为提取抽象类,调用它的子类
//所以我们抽象一个工厂类
public interface Factory {
    public Car makeCar();
}
//再写一个具体的工厂类,这个类去生成BYD汽车
public class BYDFactory implements Factory {
    @Override
    public Car makeCar() {
        return new BYD();
    }
}
//再再写一个具体的工厂类,这个类去生成BENZ汽车
public class BYDFactory implements Factory {
    @Override
    public Car makeCar() {
        return new BYD();
    }
}
//客户端代码
public class Customer {
    public static void main(String[] args) {
        Factory bydFactory = new BYDFactory();
        Car car1 = bydFactory.makeCar();
        car1.carName();

        Factory benzFactory = new BENZFactory();
        Car car2 = benzFactory.makeCar();
        car2.carName();
    }
}
输出结果:比亚迪汽车
		 奔驰汽车

小结

现在,我们如果需要新增加一个产品,那么我们只需要去新增加一个具体子类,新增一个对应的工厂类就行。现在的工厂方法类就符合开闭原则了。等等,好像它又不怎么灵活了,没错,当我们去买车时,确实不用去创建新车了,但是我们需要去创建工厂了。
那么,都是去创建对象,他们之间的差距是什么?
举个例子来说明一下:现在100个人,某公司提供每人一辆BYD汽车。
如果不使用工厂,我们需要创建100个BYD对象。
使用工厂模式,我们只需要创建一个工厂,让这些人去提车就行。虽然是通过方法去获取Car对象,好似没什么区别,但是,现在我们更改需求,BYD公司推出,现在有了BYD2.0,可以用BYD直接换BYD2.0。
如果我们没有使用工厂,那么我们需要去修改100处的代码进行换车。
但是如果我们使用了工厂方法,那么我们只需要去修改工厂中创建的对象就行了。这就是两者的差距。


抽象工厂模式

在只有一个产品类时,我们可以使用简单工厂或工厂方法去实现,但是如果产品类为两个或多个,使用简单工厂就无法满足单一职责。这时候就需要去抽象其工厂类,满足单一职责。为此,抽象工厂模式诞生。
下面就让我们去了解了解抽象工厂。

抽象工厂模式类图

在这里插入图片描述
抽象工厂类:抽象类或者接口,定义具体工厂类相同的方法
具体的工厂类:实现或继承抽象工厂类,重写其方法。使用方法实例化对应的对象。
抽象产品A/B:抽象类或者接口,定义该产品的属性和方法
具体产品A/B:根据品牌创建对应的具体产品类

抽象工厂模式代码实现

例子:我们现在去买车,车的产品从原来的汽车变为现在可以选择购买电车或者油车。

//抽象工厂类:
public interface Factory {
    //生产电车
    Tram tram();
    //生产油车
    OilTank OIL_TANK();
}
//抽象产品类A
public interface Tram {
    void manufacture();
}
//抽象产品B
public interface OilTank {
    void manufacture();
}
//具体工厂
//BENZ车厂
public class BENZFactory implements Factory {
    @Override
    public Tram tram() {
        return new BENZTram();
    }

    @Override
    public OilTank OIL_TANK() {
        return new BENZOilTank();
    }
}
//BYD车厂
public class BYDFactory implements Factory {
    @Override
    public Tram tram() {
        return new BYDTram();
    }

    @Override
    public OilTank OIL_TANK() {
        return new BYDOilTank();
    }
}
具体产品类:
//BENZ电车
public class BENZTram implements Tram {
    @Override
    public void manufacture() {
        System.out.println("奔驰电车");
    }
}
//BYD电车
public class BYDTram implements Tram {
    @Override
    public void manufacture() {
        System.out.println("比亚迪电车");
    }
}
//BENZ油车
public class BENZOilTank implements OilTank {
    @Override
    public void manufacture() {
        System.out.println("奔驰油车");
    }
}
//BYD油车
public class BYDOilTank implements OilTank {
    @Override
    public void manufacture() {
        System.out.println("比亚迪油车");
    }
}
//客户端
public class test {
    public static void main(String[] args) {
        FactoryBYDFactory = new BYDFactory();
        BYDFactory.OIL_TANK().manufacture();
        BYDFactory.tram().manufacture();

        FactoryBENZFactory = new BENZFactory();
        BENZFactory.OIL_TANK().manufacture();
        BENZFactory.tram().manufacture();
    }
}
输出结果:比亚迪油车
	   	 比亚迪电车
	 	 奔驰油车
		 奔驰电车

小结:

现在,我们可以去总结一下抽象工厂是否满足开头的三个原则:单一职责:不用说,我们就是因为这个才写的抽象工厂,那肯定是满足的。开闭原则:现在无论我们去添加一个新的品牌或者产品都是直接创建,去继承或实现对应抽象类或接口即可。所以开闭原则我们也是满足的。灵活性:现在我们客户想要去购买一辆车,好像确实不用去创建车了,想要什么品牌只要创建一个对应车厂就行。但是我们却要去了解车产具体的方法才行,不像简单工厂那样,我们只需要输入想要卖什么车就行。再说,我们无论是新增加一个品牌还是产品也好。这个要写的代码量好像有点多啊。最重要的一点,比如:某公司给每人配了一辆BYD,过了几年发现不是很好用,现在要换成BENZ,那么我们当初写的FactoryBYDFactory = new BYDFactory();就需要换成FactoryBENZFactory = new BENZFactory();之前写了100次就要改100遍。所以灵活性它不满足我们的需求。


用简单工厂改进抽象工厂模式

为了满足,多个产品下,还要足够灵活,我们可以去使用简单工厂去修改一下抽象工厂的方法。

简单抽象工厂模式类图

在这里插入图片描述
具体的工厂:去根据方法创建不同的品牌的对象。根据参数的不同创建不同产品的对象。
抽象品牌类A/B:品牌的商品的相同的方法。推荐使用接口。
具体品牌A/B下的具体商品类:实现或继承抽象品牌类。

简单抽象工厂模式代码实现

看着这个类图,和上面简单工厂对比,不得了,简直一模一样。
那就看看代码怎么样:

//车厂
public class CarFactory {

    private static final String car = "oilTank";
//    private static final String car = "tram";

    public BENZ buyBENZ() {
        BENZ benz = null;
        switch (car) {
            case "oilTank":
                benz = new BENZOilTank();
                break;
            case "tram":
                benz = new BENZTram();
                break;
        }
        return benz;
    }
    public BYD buyBYD(){
        BYD byd = null;
        switch (car) {
            case "oilTank":
                byd = new BYDOilTank();
                break;
            case "tram":
                byd = new BYDTram();
                break;
        }
        return byd;
    }
}
//品牌接口:
public interface BENZ {
    void manufacture();
}
public interface BYD {
    void manufacture();
}
//具体产品类:
public class BENZOilTank implements BENZ {
    @Override
    public void manufacture() {
        System.out.println("奔驰油车");
    }
}
public class BENZTram implements BENZ {
    @Override
    public void manufacture() {
        System.out.println("奔驰电车");
    }
}
public class BYDOilTank implements BYD {
    @Override
    public void manufacture() {
        System.out.println("比亚迪油车");
    }
}
public class BYDTram implements BYD {
    @Override
    public void manufacture() {
        System.out.println("比亚迪电车");
    }
}
//客户端:
public class test {
    public static void main(String[] args) {
        CarFactory car = new CarFactory();
        car.buyBENZ().manufacture();
        car.buyBYD().manufacture();
    }
}
输出结果:奔驰油车
		 比亚迪油车
当我们参数变为private static final String car = "tram";时
输出结果:奔驰电车
		 比亚迪电车

小结:

和抽象工厂一比,这代码量就少了好多。而且我要什么车就修改参数就行,或者不设参数,设立get/set方法直接让客户端输入。再在车厂设一个判断语句去判断调用那个方法创建对象。但是看到这有些帅哥美女就发现了问题了,这TM不是有学回去了吗?没错,它由简单工厂改进,也就继承了简单工厂的好处,但是也继承了坏处,唯一剩下属于抽象工厂的也就是可以处理多产品这个优势了
在这里插入图片描述
咋们看下来,发现是不是和图上的一模一样,这就是个轮回嘛,到最终都没有解决这个开闭原则和灵活性的问题(请先忽略反射+配置文件+简单抽象工厂,给二哥个面子)。问题又回到最初的起点:怎么解决switch语句,不使用分支语句去判断创建对象呢?
那就是使用反射+配置文件去替代分支语句。


反射+配置文件版简单抽象工厂模式

使用反射和配置文件不熟悉的帅哥美女可以去了解一下,这我就不画类图了,就是上面的类图加一个品牌抽象类的父类车类和一个读取和写入配置文件类。

反射+配置文件版简单抽象工厂模式代码

具体代码实现如下:
为满足灵活性,根据客户端用户输入的数据去创建对应的对象,所以在车厂添加了车的品牌和类型属性,为了读取配置文件所以添加了config属性。

//车厂
public class CarFactory {

    private Config config = new Config();//写入和读取配置文件对象
    private String brand;//车的品牌
    private String type;//车的类型
    public CarFactory(String brand, String type) {
        this.brand = brand;
        this.type = type;
        config.write(brand,type);
        config.read();
    }
    public Car car(){
        String s = config.getProp().getProperty(brand+type);
        Car car = null;
        try {
            car = (Car) Class.forName(s).newInstance();
        }catch (Exception e){
            e.printStackTrace();
        }
        return car;
    }
}
//写入和读取配置文件类
public class Config {

    private Properties prop = new Properties();
    //写入配置文件方法
    public void write(String brand, String type){
        //因为我们通过反射去创建对象,需要的是被创建对象的全路径,所以命名很重要
        prop.setProperty(brand+type,"com.factory.reflexAbstracFactory."+brand+type);
        try {
            FileWriter fw = new FileWriter("src/car.properties");
            prop.store(fw,null);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    //读取配置文件
    public void read(){
        try {
            InputStream is = test.class.getClassLoader().getResourceAsStream("car.properties");
            prop.load(is);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    public Properties getProp() {
        return prop;
    }
    public void setProp(Properties prop) {
        this.prop = prop;
    }
}
//接口:
//品牌接口的父接口:为了方便在车厂获取对象
public interface Car {
    public void manufacture();
}
//品牌接口:
public interface BYD extends Car {
    public void manufacture();
}
public interface BENZ extends Car  {
    public void manufacture();
}
//具体产品类:
public class BENZOilTank implements BENZ {
    @Override
    public void manufacture() {
        System.out.println("奔驰油车");
    }
}
public class BENZTram implements BENZ {
    @Override
    public void manufacture() {
        System.out.println("奔驰电车");
    }
}
public class BYDOilTank implements BYD {
    @Override
    public void manufacture() {
        System.out.println("比亚迪油车");
    }
}
public class BYDTram implements BYD {
    @Override
    public void manufacture() {
        System.out.println("比亚迪电车");
    }
}
//客户端
public class test {
    public static void main(String[] args) {

        System.out.println("请输入你要购买的汽车品牌");
        Scanner sc = new Scanner(System.in);
        String brand = sc.nextLine();
        System.out.println("请输入你要购买的汽车类型");
        String type = sc.nextLine();
        CarFactory carFactory = new CarFactory(brand,type);

        Car car = carFactory.car();
        car.manufacture();
    }
}
输出结果:
请输入你要购买的汽车品牌
BYD
请输入你要购买的汽车类型
Tram
比亚迪电车
//配置文件
BYDTram=com.factory.reflexAbstracFactory.BYDTram

总结

现在,反射+配置文件+简单抽象工厂,灵活性不用说:可以随客户的需求更改随时切换,满足单一职责:为了满足单一职责,我们都把读取和写入配置文件都独立出来了,所以也满足开闭原则:我们做这个就是为了解决开闭原则的,现在没有switch语句了,所以当然也是满足的。
好了,兄弟们,工厂模式就学完了。但是有一点我们要注意:学习设计模式是为了我们代码具备高维护、高复用等等特性,而不是一昧的滥用。从上面代码也可以看出有些地方不是很合理,我只是为了让大家更好了解,所以一直只使用买车这个例子。在我们实际开发中应该去深度了解代码逻辑需要使用些什么模式,而不是乱用。好了,工厂模式学完了,祝大家度过美好快乐的一天!


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

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

相关文章

高项 人力资源管理论文

4个过程: 人力资源管理简单可以归纳为以下四点:明确需要的人((制定人力资源管理计划),找到合适的人(组建项目团队),用好身边的人(建设项目团队)&…

宝塔面板一键部署芸众商城智慧商业系统 打造多终端直播分销商城

芸众商城社交电商系统前端基于vue开发,后端基于laravel开发,免费版本全开源,支持商用,可同时支持多端口部署运行;本教程将使用宝塔面板一键部署的方式搭建芸众商城系统,使用宝塔面板搭建,大大提…

ShardingSphere实现数据库读写分离,主从库分离,docker详细教程

一.什么是 ShardingSphere 引用官方的话: Apache ShardingSphere 是一款分布式的数据库生态系统, 可以将任意数据库转换为分布式数据库,并通过数据分片、弹性伸缩、加密等能力对原有数据库进行增强。 Apache ShardingSphere 设计哲学为 Dat…

计算机毕业设计ssm+vue基本微信小程序的购物商城系统

项目介绍 随着互联网的趋势的到来,各行各业都在考虑利用互联网将自己的信息推广出去,最好方式就是建立自己的平台信息,并对其进行管理,随着现在智能手机的普及,人们对于智能手机里面的应用购物平台小程序也在不断的使用,本文首先分析了购物平台小程序应用程序的需求,从系统开发…

希望所有计算机专业学生都去这些网站刷题

LeetCode 力扣,强推!力扣虐我千百遍,我待力扣如初恋! 从现在开始,每天一道力扣算法题,坚持几个月的时间,你会感谢我的(傲娇脸) 我刚开始刷算法题的时候,就选…

[vue] nodejs安装教程

介绍:nodejs 是一个开源的跨平台的JavaScript运行时环境,因此在运行前端项目时是需要安装配置相应的环境变量。 一、下载nodejs 二、安装nodejs 三、配置nodejs的环境变量 四、验证配置的nodejs 一、下载nodejs nodejs下载官网地址:下载 …

【C++基础】this指针

this指针 this指针作用: c的数据和操作也是分开存储,并且每一个非内联成员函数只会诞生一份函数实例,也就是说多个同类型的对象会共用同一块代码。所以,用this指针表明哪个对象调用自己。 定义: this指针指向被调用的…

Day08--自定义组件的behaviors(等用于vue中的mixins)

1.啥子是behaviors呢? ************************************ ************************************ ************************************ ************************************ ************************************ ************************************ 2…

基地树洞 | 自动化小系列之番外篇

程序员或许只是一份工作,编码或许是为了生存,但是归根结底,我们为什么要写代码? 有没有⼀种可能,在我们的日常工作生活中,代码的初衷就是为了提升工作作效率,减少不必要的重复! 今…

钱包追踪分析的 3 个使用案例

Nov. 2022, Vincy Data Source: Footprint Analytics - Wallet Profile 钱包跟踪分析让分析师了解区块链用户的链上活动和持仓情况。 在本文中,我们将介绍钱包分析器发现的一些指标。 Footprint Analytics - Wallet Profile Footprint Analytics 从中挑选相对比较…

JVM 核心技术 - 知识点整理

JVM 核心技术 JAVA 前言 JDK (Java Development Kit) JRE 开发工具JRE(Java Runtime Environment) JVM (Java Virtual Machine) 类库一次编译,到处执行的原理: java字节码可以在有JVM的环境中运行,不关心操作系统的版本,减少…

Spring Cloud版本,Spring Boot版本详细对应关系

目录 一、官网(网页版) 二、官网(API接口) 三、根据历史官方文档梳理、保存的表格 四、官方(wiki)Spring Cloud的各个组件与Spring Boot支持、对应关系 有多个方式可以查看Spring Boot和Spring Cloud版本…

嵌入式分享合集107

一、Wi-Fi HaLow Wi-Fi HaLow很快就会出现在我们日常生活中的智慧门锁、安保摄影机、可穿戴设备和无线传感器网络上。什么是Wi-Fi HaLow?与传统的Wi-Fi(4/5/6)有何不同?究竟是什么让Wi-Fi HaLow成为物联网的理想协议?…

【初阶数据结构】——带头双向循环链表(C描述)

文章目录前言带头双向循环链表实现1. 结构介绍2. 结点创建3. 初始化4. 销毁5. 头插6. 头删7. 尾插8. 尾删9. 打印10. 查找11. 在pos之前插入数据12. 删除pos位置13. 判空14. 计算大小源码展示1. DoubleList.h2. DoubleList.c3. Test.c前言 上一篇文章我们学习了单链表&#xff…

SpringBoot自动装配原理

目录一、前言二、SpringBoot自动装配核心源码2.1、SpringBootApplication2.2、EnableAutoConfiguration2.3、Import(AutoConfigurationImportSelector.class)2.3.1、selectImports方法2.3.2、getAutoConfigurationEntry方法2.3.3、getCandidateConfigurations方法2.3.4、Spring…

在阿里云 ACK 上部署 EMQX MQTT 服务器集群

云进入以「应用为中心」的云原生阶段,Operator 模式的出现,则为 Kubernetes 中的自动化任务创建配置与管理提供了一套行之有效的标准规范。通过将运维知识固化成高级语言 Go/Java 代码,使得运维知识可以像普通软件一样交付,并能支…

欧姆龙NJ/NX基于Sysmac Studio的EIP通讯 方式

目录 Omorn - NJ301-1100 AND NX102-9000 EIP - Sysmac Studio 测试案例IP 创建变量类型 通讯配置 控制器程序下载 通讯测试 Omorn - NJ301-1100 AND NX102-9000 EIP - Sysmac Studio 测试案例IP 创建变量类型 通讯配置 控制器程序下载 通讯测试 Omorn - NJ301-1100…

Go语言快速入门笔记

文章目录import匿名导包和别名导包的方式defer语句数组和动态数组固定长度数组切片(动态数组)切片的容量追加和截取map面向对象struct继承多态interface空接口万能类型与类型断言机制变量的内置pair结构变量结构reflect包(反射)reflect反射解析结构体标签…

【Java毕设】基于idea Java的在线考试系统(附源码+课件)

项目介绍: 本系统是一个基于java的在线考试系统。它的用户由学生、教师和系统管理员组成。学生登陆系统可以进行在线测试和成绩查询。当学生登陆时,系统会随机地为学生选取试题组成考卷。当学生提交考卷后,系统会自动批改客观题,…

html实现爱情告白(附源码)

文章目录1.设计来源1.1 主界面1.2 执子之手,与子偕老1.3 死生契阔,与子成说1.4 生当复来归,死当长相思1.5 自君之出矣,明镜暗不治1.6 思君如流水,何有穷已时1.7 南有乔木,不可休思1.8 汉有游女,…