设计模式之创建型模式(单例、工厂方法、抽象工厂、原型、建造者)

文章目录

    • 一、设计模式
    • 二、设计模式的六大原则
    • 三、设计模式分类
    • 四、单例设计模式
    • 五、工厂方法
    • 六、抽象工厂
    • 七、原型模式
    • 八、建造者模式

一、设计模式

设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。项目中合理地运用设计模式可以完美地解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式都描述了一个在我们周围不断重复发生的问题,以及该问题的核心解决方案,这也是设计模式能被广泛应用的原因。

二、设计模式的六大原则

  • 开闭原则(Open Close Principle)
    开闭原则的意思是:对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。

  • 里氏代换原则(Liskov Substitution Principle)
    里氏代换原则是面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP 是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

  • 依赖倒转原则(Dependence Inversion Principle)
    这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体

  • 接口隔离原则(Interface Segregation Principle)
    这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。

  • 迪米特法则,又称最少知道原则(Demeter Principle)
    最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。

  • 合成复用原则(Composite Reuse Principle)
    合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。

三、设计模式分类

设计模式常见的有23类,分为创建型结构型行为型

  • 创建型模式主要用于创建对象,为设计类实例化对象做指导。

  • 结构型主要处理类或对象之间的组合,为如何设计类以形成更大的结构做指导。

  • 行为型主要描述类或对象的交互和职责的分类,为类的交互和职责分类做指导。

四、单例设计模式

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

单例的实现方式也有多种,包括:饿汉式、懒汉式、静态内部方式、枚举单例、双重检测锁方式 。

  1. 懒汉式

类初始化时,不会初始化该对象,真正需要使用的时候才会创建该对象,具备懒加载功能。
在设计单例时,首先需要私有化无参构造函数,避免使用 new 创建对象。

public class Singleton {  private static Singleton instance;  private Singleton (){}  public static synchronized Singleton getInstance() {  if (instance == null) {  instance = new Singleton();  }  return instance;  }  
}

这种情况如果并发获取对象的时候,因为加了synchronized 锁,会抢夺锁导致一些性能的下降。

  1. 饿汉式

类初始化时,会立即加载该对象,线程天生安全,调用效率高,这种方式比较常用,但容易产生垃圾对象。
它基于 classloader 机制避免了多线程的同步问题,不过,instance 在类装载时就实例化,虽然导致类装载的原因有很多种,在单例模式中大多数都是调用 getInstance() 方法, 但是也不能确定有其他的方式(或者其他的静态方法)导致类装载,这时候初始化 instance 显然没有达到 lazy loading 的效果。

public class Singleton {  private static Singleton instance = new Singleton();  private Singleton (){}  public static Singleton getInstance() {  return instance;  }  
}

这种方式在加载时就创建好了对象,相对于上面的懒汉式,性能会更高。但是对于一些不常用的类,在一开始就加载好,浪费内存,容易产生垃圾对象。

  1. 双检锁/双重校验锁 DCL

上面可以看出,使用懒汉式由于在方法上加了synchronized 会导致请求排队,使用饿汉式,又会有可能造成浪费内存产生垃圾对象,带着问题来看下双重校验锁机制。

public class Singleton {  private volatile static Singleton singleton;  private Singleton (){}  public static Singleton getSingleton() {  if (singleton == null) {  synchronized (Singleton.class) {  if (singleton == null) {  singleton = new Singleton();  }  }  }  return singleton;  }  
}

这种形式,在获取对象时先判断有无实例,有的话就直接返回,相对于懒汉式消除了锁争夺等待。如果没有被实例化,就使用synchronized 锁住当前对象,那么,都锁住了为什么在里面还要再判断一次是否有实例呢,这是因为假如并发有两个线程获取对象,都判断为null,那下面就会争夺锁,抢到锁的就可以安心的实例化对象了,当创建好释放锁后,另一个线程走下去再创建对象不就创建重复了嘛,上一个线程已经创建好了呀,所以在这里再判断一次,就是为了在刚开始创建对象的时候防止并发重复实例化对象。解决了懒汉式和饿汉式的弊端。

  1. 静态内部类

上面双重校验锁机制似乎就已经很好了,但还有没有办法解决懒汉式和饿汉式的弊端呢,那就是静态内部类;
这种方式能达到双检锁方式一样的功效,但实现更简单。对静态域使用延迟初始化,应使用这种方式而不是双检锁方式。这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。

public class Singleton {  private static class SingletonHolder {  private static final Singleton INSTANCE = new Singleton();  }  private Singleton (){}  public static final Singleton getInstance() {  return SingletonHolder.INSTANCE;  }  
}
  • 优势:解决懒汉式和饿汉式的弊端
  • 劣势:需要两个类去做到这一点,虽然不会创建静态内部类的对象,但是其 Class 对象还是会被创建,而且是属于永久带的对象。
  1. 枚举

这种实现方式还没有被广泛采用,但这是实现单例模式的最佳方法,因为枚举本身是单例的。它更简洁,自动支持序列化机制,绝对防止多次实例化。
这种方式不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。不过,由于 JDK1.5 之后才加入 enum 特性,用这种方式写不免让人感觉生疏,在实际工作中,也很少用。

public enum Singleton {  INSTANCE;  public void whateverMethod() {  }  
}
public class Singleton {public static Singleton getInstance() {return SingletonEnum.INSTANCE.getInstance();}private static enum SingletonEnum{INSTANCE;private Singleton instance;private SingletonEnum() {instance= new Singleton ();}public Singleton getInstance() {return instance;}}
Singleton s = Singleton.getInstance();
  • 优点:实现简单、枚举本身就是单例,由jvm从根本上提供保障!避免通过反射和反序列化的漏洞
  • 缺点:没有延迟加载

五、工厂方法

工厂方法,使用工厂可以像使用人员屏蔽对象创建的细节,使用者无需指定具体的类即可使用功能,达到信息隐蔽的作用,便于后期的维护,修改和扩展

在看工厂方法前还有一类是 简单工厂,相当于是一个工厂中有各种产品,创建在一个类中,客户无需知道具体产品的名称,只需要知道产品类所对应的参数即可。但是工厂的职责过重,而且当类型过多时不利于系统的扩展维护。
在这里插入图片描述

比如我们在聚合支付的时候有,微信支付和支付宝支付,在不同的选择要获取不同的对象,如果用简单方法来实现的话:

  1. 先定义统一的支付抽象类,定义支付和取消支付抽象方法
public interface PayInterFace {//支付void pay();//取消支付void cancelPay();
}
  1. 定义微信支付类
public class WxPay implements PayInterFace {@Overridepublic void pay() {System.out.println("微信支付中...");}@Overridepublic void cancelPay() {System.out.println("微信取消支付!");}
}
  1. 定义支付宝类
public class ZfbPay implements PayInterFace {@Overridepublic void pay() {System.out.println("支付宝支付中...");}@Overridepublic void cancelPay() {System.out.println("支付宝取消支付!");}
}
  1. 创建简单工厂
public class SimplePayFactory {public static PayInterFace getPay(String payType) {if (Objects.equals(payType, "wx")) {return new WxPay();} else if (Objects.equals(payType, "zfb")) {return new ZfbPay();} else {return null;}}
}
  1. 使用
public class demo {public static void main(String[] args) {PayInterFace pay = SimplePayFactory.getPay("wx");pay.pay();pay.cancelPay();PayInterFace pay1 = SimplePayFactory.getPay("zfb");pay1.pay();pay1.cancelPay();}
}

在这里插入图片描述

通过传入不同的标识获取不同的对象,且无需指定具体对象,让使用者无需关注创建对象的细节,增加对象需要在工厂中添加对应的实例化程序,当类型过多时不利于系统的扩展维护。

那下面来看下工厂方法的做法:

  1. 在上面的基础上,再建立 支付工厂接口:
public interface PayFactory {PayInterFace getPay();
}
  1. 建立微信支付工厂
public class WxPayFactory implements PayFactory {@Overridepublic PayInterFace getPay() {return new WxPay();}
}
  1. 建立支付宝工厂
public class ZfbPayFactory implements PayFactory {@Overridepublic PayInterFace getPay() {return new ZfbPay();}
}
  1. 使用
public class demo {public static void main(String[] args) {PayInterFace pay = new WxPayFactory().getPay();pay.pay();pay.cancelPay();PayInterFace pay1 = new ZfbPayFactory().getPay();pay1.pay();pay1.cancelPay();}
}

这种方式同样屏蔽了对象建立的细节,且无需指定具体对象,但相对于上面的简单工厂,更易于做扩展,比如要引入新的支付,只需要创建新的工厂并实现PayFactory 即可,更利于系统的扩展。

六、抽象工厂

上面学习了简单工厂工厂方法,下面来看下抽象工厂
抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

在上面的场景中,加入支付后需要扣除库存,就需要引入库存工厂,并调用扣除库存的方法,库存工厂和支付工厂貌似不相干,但在抽象工厂中,抽象工厂相当于一个公司,库存和支付相当与部门,相对于公司来看,支付和库存都是公司下的部门,是一个整体。所以抽象工厂就是定义一个产品组,可以完成一系列的过程,而不是单一的活动。

下面使用抽象工厂定义支付后扣除库存的设计:

  1. 定义库存操作接口
public interface RepertoryInterFace {void deductRepertory();
}
  1. 以苹果为例,定义具体库存为苹果的库存
public class AppleRepertory implements RepertoryInterFace {@Overridepublic void deductRepertory() {System.out.println("苹果库存 扣除库存...");}
}
  1. 定义抽象工厂,定义支付和扣库存抽象方法
public interface BuyAbstractFactory {//支付PayInterFace pay();//扣库存RepertoryInterFace deductRepertory();
}
  1. 定义抽象工厂实现,这里演示效果,直接采用微信支付对象
public class BuyAbstractFactoryImpl implements BuyAbstractFactory {@Overridepublic PayInterFace pay() {return new WxPay();}@Overridepublic RepertoryInterFace deductRepertory() {return new AppleRepertory();}
}
  1. 使用
public class demo {public static void main(String[] args) {BuyAbstractFactory factory = new BuyAbstractFactoryImpl();factory.pay().pay();factory.deductRepertory().deductRepertory();}
}

在这里插入图片描述

使用抽象工厂方式,颗粒化程度大,让使用者无需知道整个工作组的对象,即可完成一连串的操作,对可扩展性,可修改修都很友好

七、原型模式

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。它提供了一种创建对象的最佳方式
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。
例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

例如:

创建一个可复制的支付类:

public class WxPay implements Cloneable{public WxPay(){System.out.println("创建支付对象");}public WxPay clone() throws CloneNotSupportedException {System.out.println("复制对象!");return (WxPay) super.clone();}
}

使用:

public class demo {public static void main(String[] args) throws CloneNotSupportedException {WxPay pay = new WxPay();WxPay pay1 = pay.clone();System.out.println(pay);System.out.println(pay1);}
}

在这里插入图片描述

可以看到,创建了两个不同的对象,只进行了一次构件函数的执行,当直接创建对象的代价比较大时,就可以采用这种模式。

另外,原型的拷贝又有浅拷贝深拷贝两个层次,上面的方式就是浅拷贝,只把当前对象做了拷贝,如果对象中有其他对象的引用,就不会进行拷贝,修改任意一个对象中的引用,对其他都会有影响

比如上面的WxPay类做如下修改:

  1. 先定义其他操作类
public class OtherOperation {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}
  1. 再修改WxPay类
public class WxPay implements Cloneable {private OtherOperation otherOperation = new OtherOperation();public WxPay() {System.out.println("创建支付对象");}public WxPay clone() throws CloneNotSupportedException {System.out.println("复制对象!");return (WxPay) super.clone();}public OtherOperation getOperation() {return otherOperation;}public String getName() {return otherOperation.getName();}}
  1. 演示
public class demo {public static void main(String[] args) throws CloneNotSupportedException {WxPay pay = new WxPay();WxPay pay1 = pay.clone();System.out.println(pay);System.out.println(pay1);System.out.println(pay.getOperation());System.out.println(pay1.getOperation());pay.getOperation().setName("abc");System.out.println(pay1.getOperation().getName());}
}

在这里插入图片描述

上面可以看出,WxPay确实是复制出了一个实例,但是WxPay里面的OtherOperation实例没有复制,还只向同一个地址,导致只要修改任意一个对象中的OtherOperation对其他实例都会有影响。

上面已经看出默认是浅拷贝,但有的时候,我们又需要其中引用的对象也要为新实例,那怎么做呢,下面就来看下深拷贝的实现方式:

深拷贝实现方式 1:重写 clone 方法来实现深拷贝
深拷贝实现方式 2:通过对象序列化实现深拷贝(推荐)

实现方式 1,重写 clone 方法来实现深拷贝

  1. 修改 OtherOperation类
public class OtherOperation implements Cloneable{private String name;public OtherOperation clone() throws CloneNotSupportedException {System.out.println("复制OtherOperation对象!");return (OtherOperation) super.clone();}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
  1. 修改WxPay,在clone中再复制OtherOperation ,以达到深拷贝的效果
public class WxPay implements Cloneable {private OtherOperation otherOperation = new OtherOperation();public WxPay() {System.out.println("创建支付对象");}public WxPay clone() throws CloneNotSupportedException {System.out.println("复制对象!");WxPay wxPay = (WxPay) super.clone();wxPay.otherOperation = otherOperation.clone();return wxPay;}public OtherOperation getOperation() {return otherOperation;}public String getName() {return otherOperation.getName();}}
  1. 演示
public class demo {public static void main(String[] args) throws CloneNotSupportedException {WxPay pay = new WxPay();WxPay pay1 = pay.clone();System.out.println(pay);System.out.println(pay1);System.out.println(pay.getOperation());System.out.println(pay1.getOperation());pay.getOperation().setName("abc");System.out.println(pay1.getOperation().getName());}
}

在这里插入图片描述

可以看到,WxPay 和 OtherOperation 都是新实例。

深拷贝实现方式 2:通过对象序列化实现深拷贝

  1. OtherOperation 实现 Serializable
public class OtherOperation implements  Serializable {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}
  1. WxPay 实现Serializable,并提供方法对当前对象进行序列化操作
public class WxPay implements Serializable {private OtherOperation otherOperation = new OtherOperation();public WxPay() {System.out.println("创建支付对象");}public OtherOperation getOperation() {return otherOperation;}public String getName() {return otherOperation.getName();}public WxPay deepClone() {//创建流对象ByteArrayOutputStream bos = null;ObjectOutputStream oos = null;ByteArrayInputStream bis = null;ObjectInputStream ois = null;try {//序列化bos = new ByteArrayOutputStream();oos = new ObjectOutputStream(bos);oos.writeObject(this); //当前这个对象以对象流的方式输出//反序列化bis = new ByteArrayInputStream(bos.toByteArray());ois = new ObjectInputStream(bis);return (WxPay) ois.readObject();}catch (Exception e) {return null;}finally {//关闭流try {bos.close();oos.close();bis.close();ois.close();}catch (Exception e2) {System.out.println(e2.getMessage());}}}
}
  1. 效果
public class demo {public static void main(String[] args) throws CloneNotSupportedException {WxPay pay = new WxPay();WxPay pay1 = pay.deepClone();System.out.println(pay);System.out.println(pay1);System.out.println(pay.getOperation());System.out.println(pay1.getOperation());pay.getOperation().setName("abc");System.out.println(pay1.getOperation().getName());}
}

在这里插入图片描述

和上面我们手动的方式是一样的效果。

八、建造者模式

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

例如,在游戏场景中,需要构建人物模型,可能要先构建头部、再构建身体、然后四肢部分,最后才是一个完整的人物,如果都写在一起,肯定会导致代码复杂不易其他开发人员理解,对后期维护扩展难度都大,如果使用构建者模式,便可以将头部、身体、四肢,写在不同的人物实现里面,最后由一个构建类去按照一定的顺序加载它们,然后组成了一个更大的复杂的对象,这样便有利于维护扩展。

下面我们借助上面的例子简单用构建者模式实现下

  1. 定义人物对象,这里直接将头、身体、四肢简化为属性的形式表达。
@Data
public class Person {private String head;private String body;private String foot;
}
  1. 定义人物构建接口,并定义具体的抽象方法。
public interface PersonBuilder {//构建入口Person Builder();//构建头部void builderHead();//构建身体void builderBody();//构建四肢void builderFoot();
}
  1. 定义一个男孩人物的具体构建实现
public class BoyBuilder implements PersonBuilder {private Person person;public BoyBuilder() {person = new Person();}@Overridepublic Person Builder() {builderHead();builderBody();builderFoot();System.out.println("构建完成!");return person;}@Overridepublic void builderHead() {System.out.println("开始构建男孩头部...");person.setHead("男孩头部信息");}@Overridepublic void builderBody() {System.out.println("开始构建男孩身体...");person.setBody("男孩身体信息");}@Overridepublic void builderFoot() {System.out.println("开始构建男孩四肢...");person.setFoot("男孩四肢部分信息");}}
  1. 演示
public class demo {public static void main(String[] args) {PersonBuilder personBuilder = new BoyBuilder();Person person = personBuilder.Builder();System.out.println(StringFormatter.concat("构建对象:", person.toString()).getValue());}}

在这里插入图片描述

上面就是将一个人物的不同部分分别构建(实际中每个小的构建都应该在具体的实现中去表达,这里简化为了一个属性),一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

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

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

相关文章

JSP 设置静态文件资源访问路径

这里 我们先在 WEB目录webapp 下创建一个包 叫 static 就用它来存静态资源 然后 我们扔一张图片进去 我们直接这样写 如下图 找到父级目录 然后寻找下面的 static 下的 img.png 运行代码 很明显 它没有找到 这边 我们直接找到 webapp目录下的 WEB-INF目录下的 web.xml 加入…

temu最近数据:拼多多旗下跨境电商平台的业绩持续增长

据最近的报道和数据显示,拼多多旗下的跨境电商平台Temu在2023年第三季度取得了显著的业绩增长。销售额突破50亿美元,市场份额不断扩大,用户数量迅速增长。本文将深入探讨Temu的业绩增长、市场份额、用户增长以及其营销策略。 先给大家推荐一款…

3d家居产品虚拟三维展示提升企业的品牌竞争力

2D展示逐渐难以满足消费者需求,因此基于3D三维展示制作平台将产品或服务以三维形式呈现的3D三维展示更受客户和企业青睐,也大幅提升企业的营销推广效果。那么3D三维展示制作平台如何赋能企业营销推广呢? 首先,3D三维展示制作平台能够提供更加…

Avalonia开发之HelloWrold

前言 本文所有讲解是以VS2022为开发工具,官方提供了VS2022和2019的扩展支持,大家根据自己的是实际情况下载相应的扩展进行安装。 安装扩展 如下图,我们在扩展菜单里面找到扩展管理,如下图: 在扩展管理的搜索栏里面…

一文带你了解Java中synchronized原理

🌈🌈🌈今天给大家分享的是Java中 synchronized 的基本原理 清风的CSDN博客 🛩️🛩️🛩️希望我的文章能对你有所帮助,有不足的地方还请各位看官多多指教,大家一起学习交流&#xff…

分享Python给自己写的函数添加注释的小功能

def get_ips(prefix: str, suffix: int) -> List[str]:"""获取 IP 地址段。Args:prefix: IP 地址的前缀。suffix: IP 地址的后缀。Returns:IP 地址列表。"""... """ """ 就是注释开始以及注释结束。 效果&a…

C语言学习笔记之数组篇

数组是一组相同类型元素的集合。 目录 一维数组 数组的创建 数组的初始化 数组的使用 数组在内存中的存储 二维数组 数组的创建 数组的初始化 数组的使用 数组在内存中的存储 数组名 数组名作函数参数 一维数组 数组的创建 type_t arr_name [const_n]; //type_…

华为 ArkTS 边框怎么设置,单边边框怎么设置以及条件设置边框(鸿蒙开发)

一、实例代码: border(params) 接收一个对象参数,对象参数的属性为width?: Lenght,color?: ,radius?: Length,style?: BorderStyle 注意:以下实例包含了我说知道的 边框的单位 以及 颜色 的各种用法 Column() {Im…

【已解决】MySQL:执行存储过程报错(MySQL字符集和排序方式冲突)

目录 问题现象: 问题分析: 解决方法: 拓展: 1、转换条件两边的字段或值为二进制数据: 2、转换条件两边的字段或值的字符集和排序方式: 3、修改列、表、库的字符集和排序方式 参考链接: 问…

微信商城小程序怎么制作?做一个小程序需要什么流程?

小程序商城对商家有哪方面的帮助? 随着移动互联网的快速发展,小程序商城已经成为了越来越多商家的选择。那么,小程序商城到底对商家有哪些方面的帮助呢? 一、提高商家曝光度 在小程序平台上开设自己的小程序商城,可以…

AI之火是如何燎原的?始于马斯克与佩奇的一场激辩

丨划重点 ①在2015年, 马斯克44岁生日派对上,他与谷歌联合创始人佩奇曾就AI产生严重分歧,甚至终结了十多年的友谊。佩奇认为人类最终将与AI机器融合,将会有许多种智能争夺资源, 马斯克则担心机器可能会毁灭人类。 ②在收购AI创企DeepMind时…

acwing1209.带分数暴力与优化(java版)

//n a b / c n是确定的,只需找到其中两个。判断剩下一个数是否满足条件即可 //由题目条件可知,每个数不能重复使用,需要一个st全局数组判断每个数是否使用过 //递归实现排列型枚举,cn ac b //对于枚举出来的每一个a,再去枚举每一个c,再在c的枚举里判断b是否满足条件 //…

人工智能学习3(特征变换:特征数值化)

编译工具:PyCharm 有些编译工具不用写print可以直接将数据打印出来,pycharm需要写print才会打印出来。 文章目录 编译工具:PyCharm 概念1.特征类型分类型二值型顺序型数值型 2.特征数值化练习13.特征数值化练习24.特征二值化使用sklearn库自…

day69

今日回顾 Django与Ajax 一、什么是Ajax AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在…

YOLOv8优化策略:简单高效的模块-现代反向残差移动模块 (iRMB) | | ICCV2023 EMO

🚀🚀🚀本文改进:设计了一种面向移动端应用的简单而高效的现代反向残差移动模块 (Inverted Residual Mobile Block, iRMB),它吸收了类似 CNN 的效率来模拟短距离依赖和类似 Transformer 的动态建模能力来学习长距离交互,引入YOLOV8 🚀🚀🚀YOLOv8改进专栏:http:…

三个角度(握手、挥手、传输)优化TCP

TCP 三次握手的性能提升 客户端的优化 当客户端发起 SYN 包时,可以通过 tcp_syn_retries 控制其重传的次数。 服务端的优化 当服务端 SYN 半连接队列溢出后,会导致后续连接被丢弃,可以通过 netstat -s 观察半连接队列溢出的情况,如…

对标Gen-2!Meta发布新模型进军文生视频赛道

随着扩散模型的飞速发展,诞生了Midjourney、DALLE 3、Stable Difusion等一大批出色的文生图模型。但在文生视频领域却进步缓慢,因为文生视频多数采用逐帧生成的方式,这类自回归方法运算效率低下、成本高。 即便使用先生成关键帧,再生成中间帧新方法。如…

Windows下使用AndroidStudio及CMake编译Android可执行程序或静态库动态库

Windows下使用AndroidStudio及CMake编译Android可执行程序或静态库动态库 文章目录 Windows下使用AndroidStudio及CMake编译Android可执行程序或静态库动态库一、前言二、编译环境三、示例C/CPP程序1、总体工程结构2、示例代码3、CMakeLists.txt(重要)4、…

Python语言基础学习大纲(由某大模型生成)

自从上次经丙察察游了一次滇藏线,已有3个没写一篇了。今天利用由某大模型生成的上面这张思维导图,配合这个大模型生成的6000多字拼凑出一篇博文聊以交差。 Python语言概述 一、语言特点 1.语法简单明了 Python的语法简洁易懂,使得编写代码…

12.5作业

1. #include <iostream>using namespace std;class Animal { private:string name; public:Animal(){}Animal(string name):name(name){cout << "animal" << endl;}virtual void perfrom(){cout << "实现不同表演行为" << …