设计模式之工厂模式(万字长文)
文章目录
- 概述
- 工厂模式的优点包括
- 工厂模式有几种主要的变体
- 看一个具体需求
- 使用传统的方式来完成
- 传统的方式的优缺点
- 简单工厂模式基本介绍
- 使用简单工厂模式
- 简单工厂模式的优缺点
- 优点:
- 缺点:
- 工厂方法模式
- 看一个新的需求
- 思路 1
- 思路 2
- 工厂方法模式介绍
- 工厂方法模式应用案例
- 抽象工厂模式
- 基本介绍
- 抽象工厂模式应用实例
- 工厂模式小结
概述
工厂模式是一种创建型设计模式,它提供了一种创建对象的接口,但将对象的实例化过程推迟到子类或具体的实现类中。工厂模式的主要目的是将对象的创建与使用分离,从而降低代码的耦合性,增强代码的可维护性和可扩展性。
工厂模式的优点包括
- 对象的封装:将对象的创建细节封装在具体的工厂类中,使客户端不需要了解具体的创建过程,只需通过工厂来获取所需的对象。
- 代码重用:由于对象的创建过程在工厂类中集中管理,可以避免在多个地方重复创建相同类型的对象。
- 易于扩展:当需要添加新的产品或变体时,只需创建新的具体工厂类和产品类,而不需要修改现有代码。
- 降低耦合:客户端只与抽象工厂类进行交互,不直接依赖于具体产品类,从而降低了代码的耦合性。
工厂模式有几种主要的变体
- 简单工厂模式:不是正式的设计模式,更像是一种编程习惯,将对象的创建封装在一个静态方法中。
- 工厂方法模式:定义了一个用于创建对象的抽象方法,由具体的子类工厂来实现创建逻辑。
- 抽象工厂模式:提供一个创建一组相关或相互依赖对象的接口,每个具体工厂类负责创建一组具体产品。
看一个具体需求
看一个披萨的项目:要便于披萨种类的扩展,要便于维护
- 披萨的种类很多(比如 GreekPizz、CheesePizz 等)
- 披萨的制作有 prepare,bake, cut, box
- 完成披萨店订购功能。
使用传统的方式来完成
- 思路分析(类图)
新建一个tradition.pizzastore包
编写 OrderPizza.java 去订购需要的各种 Pizza
- 代码展示:
package com.lh.factory.tradition.pizzastore.order;import java.io.BufferedReader;import java.io.IOException;
import java.io.InputStreamReader;import com.lh.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.lh.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.lh.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.lh.factory.simplefactory.pizzastore.pizza.Pizza;public class OrderPizza {// 构造器public OrderPizza() {//比萨的Pizza pizza = null;String orderType; // 订购披萨的类型do {orderType = getType();if (orderType.equals("greek")) {pizza = new GreekPizza();pizza.setName("胡椒披萨");} else if (orderType.equals("cheese")) {pizza = new CheesePizza();pizza.setName("奶酪披萨");// 新写的代码} else if (orderType.equals("pepper")) {pizza = new PepperPizza();pizza.setName("希腊披萨");} else {System.out.println("不存在!");break;}// 输出 Pizza 制作过程pizza.prepare();pizza.bake();pizza.cut();pizza.box();} while (true);}// 写一个方法,可以获取客户希望订购的披萨种类private String getType() {try {BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));System.out.println("input pizza 种类:");String str = strin.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}
}
Pizza类,作为抽象类,功能参考类图
package com.lh.factory.tradition.pizzastore.pizza;//将Pizza 类做成抽象类
public abstract class Pizza {//名字protected String name;public void setName(String name) {this.name = name;}//原材料(不同的披萨,不一样的原材料),做成抽象方法,自定义实现public abstract void prepare();//烘烤public void bake() {System.out.println(name + "baking");}//切割public void cut() {System.out.println(name + "cuting");}//打包public void box() {System.out.println(name + "boxing");}
}
三个子类继承Pizza类
package com.lh.factory.tradition.pizzastore.pizza;public class CheesePizza extends Pizza{@Overridepublic void prepare() {System.out.println("给胡椒披萨,制作原材料");}
}package com.lh.factory.tradition.pizzastore.pizza;public class GreekPizza extends Pizza{@Overridepublic void prepare() {System.out.println("奶酪准备原材料");}
}package com.lh.factory.tradition.pizzastore.pizza;public class PepperPizza extends Pizza {@Overridepublic void prepare() {System.out.println(" 给希腊披萨 准备原材料 ");}
}
客户端:
package com.lh.factory.tradition.pizzastore.order;//相当于一个客户端,发出订购
public class PizzaStore {public static void main(String[] args) {//传统方法new OrderPizza();}
}
传统的方式的优缺点
- 优点是比较好理解,简单易操作。
- 缺点是违反了设计模式的 ocp 原则,即对扩展开放,对修改关闭。即当我们给类增加新功能的时候,尽量不修改代码,或者尽可能少修改代码.
- 比如我们这时要新增加一个 Pizza 的种类(Pepper 披萨),我们需要做如下修改.如果我们增加一个 Pizza 类,只要是订购 Pizza 的代码都需要修改.
在orderType中新增的代码如下图:参考上方的orderType代码,代码块中有如下功能:
- 改进的思路分析
分析:修改代码可以接受,但是如果我们在其它的地方也有创建 Pizza 的代码,就意味着,也需要修改,而创建 Pizza的代码,往往有多处。
思路:把创建 Pizza 对象封装到一个类中,这样我们有新的 Pizza 种类时,只需要修改该类就可,其它有创建到 Pizza对象的代码就不需要修改了.-> 简单工厂模式
简单工厂模式基本介绍
-
简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
-
简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
-
在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式
使用简单工厂模式
- 简单工厂模式的设计方案: 定义一个可以实例化 Pizaa 对象的类,封装创建对象的代码。
uml类图如下:
- 看代码示例
简单工厂模式的pizza包下的类,均不做改动,参考如上代码即可 (需要细心观看哦)
这里只展示修改后的OrderPizza和客户端了,以及新的简单工厂模式
package com.lh.factory.simplefactory.pizzastore.order;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;import com.lh.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.lh.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.lh.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.lh.factory.simplefactory.pizzastore.pizza.Pizza;public class OrderPizza {SimlpleFactory simlpleFactory;Pizza pizza = null;//构造器public OrderPizza(SimlpleFactory simlpleFactory) {//接受简单工厂setFactory(simlpleFactory);}public void setFactory(SimlpleFactory simlpleFactory) {String orderType = ""; // 用户输入的this.simlpleFactory = simlpleFactory; // 设置简单工厂对象do {orderType = getType();pizza = this.simlpleFactory.createPizza(orderType);//输出pizzaif (pizza != null) { //订购成功pizza.prepare();pizza.bake();pizza.cut();pizza.box();}else {System.out.println("订购披萨失败!");break;}} while (true);}// 写一个方法,可以获取客户希望订购的披萨种类private String getType() {try {BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));System.out.println("input pizza 种类:");String str = strin.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}
}
好处:只需要修改工厂类的代码即可,不需要在业务场景下进行修改
下面的工厂类写了两个相同的方法,没别的意思,就是告诉大家,简单工厂模式,也叫静态工厂模式
package com.lh.factory.simplefactory.pizzastore.order;import com.lh.factory.simplefactory.pizzastore.pizza.CheesePizza;
import com.lh.factory.simplefactory.pizzastore.pizza.GreekPizza;
import com.lh.factory.simplefactory.pizzastore.pizza.PepperPizza;
import com.lh.factory.simplefactory.pizzastore.pizza.Pizza;//简单工厂类
public class SimlpleFactory {//返回对应的Pizza public Pizza createPizza(String orderType) {Pizza pizza = null;if (orderType.equals("greek")) {pizza = new GreekPizza();pizza.setName("希腊披萨");} else if (orderType.equals("cheese")) {pizza = new CheesePizza();pizza.setName("奶酪披萨");// 新写的代码} else if (orderType.equals("pepper")) {pizza = new PepperPizza();pizza.setName("胡椒披萨");}return pizza;}//简单工厂模式也叫静态工厂模式public static Pizza createPizza2(String orderType) {Pizza pizza = null;System.out.println("使用简单工厂模式2");if (orderType.equals("greek")) {pizza = new GreekPizza();pizza.setName("希腊披萨");} else if (orderType.equals("cheese")) {pizza = new CheesePizza();pizza.setName("奶酪披萨");// 新写的代码} else if (orderType.equals("pepper")) {pizza = new PepperPizza();pizza.setName("胡椒披萨");}return pizza;}
}
静态工厂模式的OrderPizza类(静态工厂模式看起来更加方便,减少了一部分代码)
package com.lh.factory.simplefactory.pizzastore.order;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;import com.lh.factory.simplefactory.pizzastore.pizza.Pizza;public class OrderPizza2 {Pizza pizza = null;String orderType = "";// 构造器public OrderPizza2() {// 接受简单工厂do {orderType = getType();pizza = SimlpleFactory.createPizza2(orderType);// 输出pizzaif (pizza != null) { // 订购成功pizza.prepare();pizza.bake();pizza.cut();pizza.box();} else {System.out.println("订购披萨失败!");break;}} while (true);}// 写一个方法,可以获取客户希望订购的披萨种类private String getType() {try {BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));System.out.println("input pizza 种类:");String str = strin.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}}
简单工厂模式的优缺点
优点:
封装对象的创建逻辑:通过将对象的创建逻辑封装在静态工厂方法中,客户端代码无需了解对象的具体创建过程,降低了对象创建的复杂度。
代码组织:简单工厂模式可以集中管理对象的创建逻辑,使代码更加清晰、简洁,并且易于维护。
灵活性:如果需要更改或替换产品,只需修改工厂方法的实现,不会影响客户端代码,从而实现了产品变化对客户端的透明性。
缺点:
不符合开闭原则:当需要添加新的产品类型时,可能需要修改工厂方法的代码,这违背了开闭原则(对扩展开放,对修改关闭)。
工厂类职责过重:工厂类通常负责创建多种不同类型的对象,导致工厂类职责变得较重,随着产品种类的增加,工厂类会变得越来越复杂。
不支持多个工厂类:在简单工厂模式中,只有一个工厂类负责所有对象的创建,这可能会导致工厂类变得庞大,难以管理。
不够灵活:由于所有对象的创建逻辑集中在一个工厂类中,如果不同的产品有复杂的创建过程,可能无法很好地适应。
工厂方法模式
看一个新的需求
披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪 pizza、北京的胡椒 pizza 或者是伦敦的奶酪 pizza、伦敦的胡椒 pizza。
思路 1
使用简单工厂模式,创建不同的简单工厂类,比如 BJPizzaSimpleFactory、LDPizzaSimpleFactory 等等。从当前这个案例来说,也是可以的,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好 (考验大家抽象能力)
思路 2
使用工厂方法模式
工厂方法模式介绍
- 工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。
- 工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
工厂方法模式应用案例
-
披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如 北京的奶酪 pizza、北京的胡椒 pizza 或者是伦敦的奶酪 pizza、伦敦的胡椒 pizza
-
思路分析图解
Pizza类与它的子类
package com.lh.factory.factorymethod.pizzastore.pizza;//将Pizza 类做成抽象类
public abstract class Pizza {//名字protected String name;//原材料(不同的披萨,不一样的原材料),做成抽象方法,自定义实现public abstract void prepare();//烘烤public void bake() {System.out.println(name + "baking");}//切割public void cut() {System.out.println(name + "cuting");}//打包public void box() {System.out.println(name + "boxing");}public void setName(String name) {this.name = name;}
}public class LDPepperPizza extends Pizza{@Overridepublic void prepare() {setName("伦敦胡椒披萨...");System.out.println("伦敦胡椒pizza,准备原材料");}
}public class LDCheesePizza extends Pizza{@Overridepublic void prepare() {setName("伦敦奶酪披萨...");System.out.println("伦敦奶酪pizza,准备原材料");}}public class BJPepperPizza extends Pizza{@Overridepublic void prepare() {setName("北京胡椒披萨...");System.out.println("北京pizza,准备原材料");}
}public class BJCheesePizza extends Pizza{@Overridepublic void prepare() {setName("北京奶酪披萨...");System.out.println("北京pizza,准备原材料");}
}
工厂抽象类,定义一个工厂的抽象方法,让其子类自己实现,这样可以不需要动工厂自身的代码,如果想添加新的品种,可以新创建一个,继承工厂抽象类重写其方法就可以
package com.lh.factory.factorymethod.pizzastore.order;import java.io.BufferedReader;import java.io.IOException;
import java.io.InputStreamReader;import com.lh.factory.factorymethod.pizzastore.pizza.Pizza;public abstract class OrderPizza {// 构造器public OrderPizza() {Pizza pizza = null;String orderType; // 订购披萨的类型do {orderType = getType();//抽象方法,由工厂子类完成pizza = createPizza(orderType);// 输出 Pizza 制作过程pizza.prepare();pizza.bake();pizza.cut();pizza.box();} while (true);}// 定义一个抽象方法,createPizza,让各个工厂子类自己实现abstract Pizza createPizza(String orderType);// 写一个方法,可以获取客户希望订购的披萨种类private String getType() {try {BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));System.out.println("input pizza 种类:");String str = strin.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}
}
两个分工厂分别继承OrderPizza 类,分别实现各自的功能
package com.lh.factory.factorymethod.pizzastore.order;import com.lh.factory.factorymethod.pizzastore.pizza.LDCheesePizza;
import com.lh.factory.factorymethod.pizzastore.pizza.LDPepperPizza;
import com.lh.factory.factorymethod.pizzastore.pizza.Pizza;public class LDOrderPizza extends OrderPizza{@OverridePizza createPizza(String orderType) {Pizza pizza = null;if (orderType.equals("cheese")) {pizza = new LDCheesePizza();}else if (orderType.equals("pepper")) {pizza = new LDPepperPizza();} return pizza;}
}package com.lh.factory.factorymethod.pizzastore.order;import com.lh.factory.factorymethod.pizzastore.pizza.BJCheesePizza;
import com.lh.factory.factorymethod.pizzastore.pizza.BJPepperPizza;
import com.lh.factory.factorymethod.pizzastore.pizza.Pizza;public class BJOrderPizza extends OrderPizza{@OverridePizza createPizza(String orderType) {Pizza pizza = null;if (orderType.equals("cheese")) {pizza = new BJCheesePizza();}else if (orderType.equals("pepper")) {pizza = new BJPepperPizza();}return pizza;}
}
客户端:
package com.lh.factory.factorymethod.pizzastore.order;public class PizzaStore {public static void main(String[] args) {//创建北京口味的各种Pizzanew BJOrderPizza();//创建伦敦口味的各种Pizzanew LDOrderPizza();}
}
抽象工厂模式
基本介绍
- 抽象工厂模式:定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类
- 抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
- 从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。
- 将工厂抽象成两层,AbsFactory(抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应
的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。 - 类图
抽象工厂模式应用实例
Pizza类与它的子类,与抽象工厂方法模式中的Pizza类和它的子类代码一样,这里不做复制粘贴,耐心可观看
工厂接口:
package com.lh.factory.absfactory.pizzastore.order;import com.lh.factory.absfactory.pizzastore.pizza.Pizza;//一个抽象工厂模式的抽象层(接口)
public interface AbsFactory {//让下面的工厂子类具体实现Pizza createFactory(String orderType);}
OrderType工厂类,将业务需求写好之后,不动此代码。直接调用即可
package com.lh.factory.absfactory.pizzastore.order;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;import com.lh.factory.absfactory.pizzastore.pizza.Pizza;public class OrderPizza {// 是聚合AbsFactory factory;//构造器public OrderPizza(AbsFactory factory) {setFactory(factory);}//指向子类实例化private void setFactory(AbsFactory factory) {Pizza pizza = null;String orderType; // 用户输入披萨this.factory = factory;do {orderType = getType();//可能是北京,或者是伦敦pizza = factory.createFactory(orderType);if (pizza != null) { //订购 okpizza.prepare();pizza.bake();pizza.cut();pizza.box();}else {System.out.println("订购失败!");break;}} while (true);}// 写一个方法,可以获取客户希望订购的披萨种类private String getType() {try {BufferedReader strin = new BufferedReader(new InputStreamReader(System.in));System.out.println("input pizza 种类:");String str = strin.readLine();return str;} catch (IOException e) {e.printStackTrace();return "";}}
}
两个工厂各自实现AbsFactory,各自实现自己的功能
package com.lh.factory.absfactory.pizzastore.order;import com.lh.factory.absfactory.pizzastore.pizza.BJCheesePizza;
import com.lh.factory.absfactory.pizzastore.pizza.BJPepperPizza;
import com.lh.factory.absfactory.pizzastore.pizza.Pizza;//北京工厂子类
public class BJFactory implements AbsFactory{ @Overridepublic Pizza createFactory(String orderType) {// TODO Auto-generated method stubSystem.out.println("使用的是抽象工厂模式");Pizza pizza = null;if (orderType.equals("cheese")) {pizza = new BJCheesePizza();}else if (orderType.equals("pepper")) {pizza = new BJPepperPizza();}return pizza;}
}package com.lh.factory.absfactory.pizzastore.order;import com.lh.factory.absfactory.pizzastore.pizza.LDCheesePizza;
import com.lh.factory.absfactory.pizzastore.pizza.LDPepperPizza;
import com.lh.factory.absfactory.pizzastore.pizza.Pizza;//伦敦工厂子类
public class LDFactory implements AbsFactory{@Overridepublic Pizza createFactory(String orderType) {// TODO Auto-generated method stubSystem.out.println("使用的是抽象工厂模式");Pizza pizza = null;if (orderType.equals("cheese")) {pizza = new LDCheesePizza();}else if (orderType.equals("pepper")) {pizza = new LDPepperPizza();}return pizza;}
}
工厂模式小结
- 工厂模式的意义
将实例化对象的代码提取出来,放到一个类中统一管理和维护,达到和主项目的依赖关系的解耦。从而提高项目的扩展和维护性。 - 三种工厂模式 (简单工厂模式、工厂方法模式、抽象工厂模式)
- 设计模式的依赖抽象原则
- 创建对象实例时,不要直接 new 类, 而是把这个 new 类的动作放在一个工厂的方法中,并返回。有的书上说,
变量不要直接持有具体类的引用。 - 不要让类继承具体类,而是继承抽象类或者是实现 interface(接口)
- 不要覆盖基类中已经实现的方法。
- 创建对象实例时,不要直接 new 类, 而是把这个 new 类的动作放在一个工厂的方法中,并返回。有的书上说,
相关文章:
设计模式之工厂模式(万字长文)
文章目录 概述工厂模式的优点包括工厂模式有几种主要的变体看一个具体需求使用传统的方式来完成传统的方式的优缺点 简单工厂模式基本介绍使用简单工厂模式简单工厂模式的优缺点优点:缺点: 工厂方法模式看一个新的需求思路 1思路 2工厂方法模式介绍工厂方…...
CNN 02(CNN原理)
一、卷积神经网络(CNN)原理 1.1 卷积神经网络的组成 定义 卷积神经网络由一个或多个卷积层、池化层以及全连接层等组成。与其他深度学习结构相比,卷积神经网络在图像等方面能够给出更好的结果。这一模型也可以使用反向传播算法进行训练。相比较其他浅层或深度神经…...
Android View动画整理
View 动画相关内容可参考官网 动画资源 此前也有写 View 动画相关的内容,但都只是记录代码,没有特别分析。以此篇作为汇总、整理、分析。 Android View 动画有4中,分别是 平移动画 TranslateAnimation缩放动画 ScaleAnimation旋转动画 Rot…...
阿里云架构
负载均衡slb 分类以及应用场景 负载均衡slb clb 传统的负载均衡(原slb) 支持4层和7层(仅支持对uri(location),域名进行转发) 一般使用slb(clb) alb 应用负载均衡 只支持7层,整合了nginx负载均衡的各种功能,可以根据用户请求头,响应头 如果需要详细处理用户请求(浏…...
【C语言】操作符大全(保姆级介绍)
🚩纸上得来终觉浅, 绝知此事要躬行。 🌟主页:June-Frost 🚀专栏:C语言 🔥该篇将详细介绍各种操作符的功能。 目录: 📘 前言① 算术操作符②移位操作符③位操作符④赋值操…...
ruoyi-cloud部署
默认你已经安装mysql,nacos,seata,sentinel等(没有的可以先找教程安装) 1、下载源码:git clone https://gitee.com/zhangmrit/ruoyi-cloud 2、项目依赖导入,选择自己的maven环境等,创…...
Vue3(开发h5适配)
在开发移动端的时候需要适配各种机型,有大的,有小的,我们需要一套代码,在不同的分辨率适应各种机型。 因此我们需要设置meta标签 <meta name"viewport" content"widthdevice-width, initial-scale1.0">…...
图的存储:邻接矩阵法
1.邻接矩阵的实现 邻接矩阵的定义:在无向图和有向图中,使用二维数组表示各个顶点的相邻情况:1代表相邻,0表示不相邻。 代码实现: #define MaxVertexNum 100//顶点数目的最大值 typedef struct {char Vex [MaxVertexN…...
如何优雅的使用Git?
第一部分:Git的基本概念和初始设置 Git是一个分布式版本控制系统,它允许多人共同工作,同时跟踪和管理项目的版本历史。使用Git,您可以恢复旧版本、创建新分支进行实验,并与其他开发者进行协作,而不会影响主…...
【【STM32分析IO该设置什么模式的问题】】
STM32分析IO该设置什么模式的问题 我们分析而言 我们对于PA0 的设计就从此而来 对于边沿触发的选择我们已经有所了解了 我们下拉,但是当我们摁下开关的时候 从0到1 导通了 所以这个是下拉 上升沿触发 而对于KEY0 我们摁下是使得电路从原来悬空高阻态到地就是0 所以…...
飞天使-k8s基础组件分析-服务与ingress
文章目录 服务的介绍服务代理服务发现连接集群外服务服务发布无头服务 服务,pod和dns的关系端口转发通过expose 暴露应用服务案例INGRESSMetalLB使用参考文档 服务的介绍 服务的作用是啥? 提供外部调用,保证podip的真实性看看服务解决了什么…...
Unity——拖尾特效
拖尾是一种很酷的特效。拖尾的原理来自人类的视觉残留:观察快速移动的明亮物体,会看到物体移动的轨迹。摄像机通过调整快门时间,也可以拍出具有拖尾效果的照片,如在城市的夜景中,汽车的尾灯拖曳出红色的线条。 在较老…...
java开发之fastjson
依赖 <!-- fastjson依赖 --> <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.76</version> <…...
第一个C语言程序:HelloWorld
第一个C语言程序 注释 注释 对代码的解释和说明 特点 ○ 不会被执行 目的 让人们能够更加轻松地看懂代码 分类 行注释 // 快键键 ctrl/ 块注释 /**/ 快捷键 shiftalta 示例代码: #include <stdio.h>int main() {// 行注释/*块注释*/printf("hello w…...
golang 使用 viper 加载配置文件 自动反序列化到结构
文章博客地址:golang 使用 viper 加载配置 自动反序列化到结构 golang使用 viper 无需设置 mapstructure tag 根据配置文件后缀 自动返序列化到结构解决结构有下划线的字段解析不成功问题 viper 正常加载配置文件 golang viper 其中可以用来 查找、加载和反序列化JSON、TOML…...
C#设计模式六大原则之--接口隔离原则
设计模式六大原则是单一职责原则、里氏替换原则、依赖倒置原则、接口隔离原则、迪米特法则、开闭原则。它们不是要我们刻板的遵守,而是根据实际需要灵活运用。只要对它们的遵守程度在一个合理的范围内,努为做到一个良好的设计。本文主要介绍一下.NET(C#)…...
【面试题】:axios二次封装都进行了哪些配置以及如果项目里面有两个baseURL你怎么解决?
一.axios的概念 Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。 二.axios的特点…...
谈谈对 GMP 的简单认识
犹记得最开始学习 golang 的时候,大佬们分享 GMP 模型的时候,总感觉云里雾里,听了半天,并没有一个很清晰的概念,不知 xmd 是否会有这样的体会 虽然 golang 入门很简单,但是对于理解 golang 的设计思想和原…...
Java正则表达式系列--从字符串中提取字符串或数字
原文网址:Java正则表达式系列--从字符串中提取字符串或数字_IT利刃出鞘的博客-CSDN博客 简介 本文用示例介绍Java如何使用正则表达式从字符串中提取想要的内容(字符串或者数字等)。 例1:提取一次不同内容 需求 从字符串中找到…...
机器学习实战之模型的解释性:Scikit-Learn的SHAP和LIME库
概要 机器学习模型的“黑箱”困境 机器学习模型的崛起让我们惊叹不已!不论是预测房价、识别图片中的猫狗,还是推荐给你喜欢的音乐,这些模型都表现得非常出色。但是,有没有想过,这些模型到底是如何做出这些决策的呢&a…...
Go 语言进阶与依赖管理 | 青训营
Powered by:NEFU AB-IN 文章目录 Go 语言进阶与依赖管理 | 青训营 语言进阶依赖管理测试 Go 语言进阶与依赖管理 | 青训营 GO语言工程实践课后作业:实现思路、代码以及路径记录 语言进阶 Go可以充分发挥多核优势,高效运行 Goroutine是Go语言中的协程…...
hyperf 十三 视图
教程:Hyperf composer地址:hyperf/view - Packagist 本次测试使用twig twig composedr地址:twig/twig - Packagist twig 文档地址:Home - Twig - The flexible, fast, and secure PHP template engine 一、安装 composer re…...
请你说说前端图形图像的框架
前端图形图像方面有许多强大的框架和库,使得开发者能够更容易地创建丰富的视觉效果和复杂的图形应用。下面列举了一些主要的框架和库: 1. Three.js Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它创建各种三维场景,包括了…...
C++数据结构学习——栈
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、栈二、C语言实现1.声明代码2.实现增删查改代码3.测试代码 总结 前言 栈(Stack)是计算机科学中一种常见的数据结构,它是…...
【C++笔记】C++之类与对象(下)
【C笔记】C之类与对象(下) 1、再看构造函数1.1、构造函数的初始化列表1.2、C支持单参数的构造函数的隐式类型转换1.3、匿名对象 2、Static成员2.1、为什么要有静态成员变量?2.2、一个类的静态成员变量属于这个类的所有对象2.3、静态成员函数 3、友元3.1、…...
管理类联考——英语——实战篇——大作文——图表——动态图表——整体效果
动态图表模板 What is clearly presented in the above 图表类型 is that dramatic changes have taken place in 主题词1 from 年份1 to 年份2.During the period, there was a marked jump from 数字1 to 数字2 in 事物1,while that of 事物2 declined significantly from 数…...
threejs纹理加载三(视频加载)
threejs中除了能把图片作为纹理进行几何体贴图以外,还可以把视频作为纹理进行贴图设置。纹理的类型有很多,我们可以用不同的加载器来加载,而对于视频作为纹理,我们需要用到今天的主角:VideoTexture。我们先看效果&…...
VUE笔记(三)vue的语法
一、计算属性 1、计算属性的概念 计算属性是依赖于源数据(data或者属性中的数据),在元数据的基础上进行逻辑运算后得到的新的数据,计算属性要依赖于源数据,源数据数据变化计算属性也会变化 2、计算属性的语法 在vue2中使用computed这个选…...
探讨uniapp的路由与页面生命周期问题
1 首先我们引入页面路由 2 页面生命周期函数 onLoad() {console.log(页面加载)},onShow() {console.log(页面显示)},onReady(){console.log(页面初次显示)},onHide() {console.log(页面隐藏)},onUnload() {console.log(页面卸载)},onBackPress(){console.log(页面返回)}3 页面…...
咸鱼之王俱乐部网站开发
我的俱乐部 最新兑换码 *注意区分大小写,中间不能有空格! APP666 HAPPY666 QQ888 QQXY888 vip666 VIP666 XY888 app666 bdvip666 douyin666 douyin777 douyin888 happy666 huhushengwei888 taptap666 周活动 宝箱周 宝箱说明 1.木质宝箱开启1个…...
深圳石岩建网站/优化大师手机版下载
今日头条自媒体运营推广视频教程学习资料短视频运营从零到精通今日头条趣东方头条凤凰新浪看点网易企鹅UC大鱼一点资讯自媒体快传视频处理软件今日头条推广视频教程自媒体推广短视频教程今日头条引流小白入门视频解析下载支持今日头条快手抖音火山映客陌陌西瓜美拍微博等快手今…...
哪个网站做简历比较好/品牌营销策划公司排名
使用Objective-C的文档生成工具:appledoc FEB 1ST, 2012 前言 做项目的人多了,就需要文档了。今天开始尝试写一些项目文档。但是就源代码来说,文档最好和源码在一起,这样更新起来更加方便和顺手。象Java语言本身就自带javadoc命令,…...
广州网站建设推广公司/营销型网站建设设计
身为职场人,收集上万条表格数据做商业分析,裁剪上千张图片,发送数百封邮件...这些都是经常会遇到的场景。我一直期待能有个工具解放我,直到我遇到了Python。Python的魅力很多小伙伴入坑Python都是从爬虫开始的,在简单了…...
优质做网站公司/bt磁力搜索引擎
在bitbucket上使用https协议,经常会在提交代码的时候出错,让人很着急上火,但是用ssh就要方便很多。下面介绍一下设置ssh的方法:1.在终端中运行ssh-keygen。2.然后一路enter,直接到结束。不要理会中间的输入。3 打开用户…...
wordpress 免费插件/谈谈你对网络营销的看法
一、硬件材料 1*Arduino UNO R3开发板 1*光敏电阻 1*人体热释红外传感器 1*舵机模块 G90舵机 二、硬件接线图 CSDN 赤鱼科技...
wordpress数据库设计优缺点/怎么优化标题和关键词排名
2019独角兽企业重金招聘Python工程师标准>>> 在 输入/输出流体系中,有两个特殊的流 PushbackInputStreamPushbackReader方法: void unread(byte[]/char[] buf) : 将一个字节或者字符数组内容推回到推回缓冲区中,从而可以重复读取刚…...