《图解设计模式》笔记(三)生成实例

五、Singleton模式:只有一个实例

Singleton 是指只含有一个元素的集合。因为本模式只能生成一个实例,因此以 Singleton命名。

示例程序类图

请添加图片描述

Singleton.java

public class Singleton {private static Singleton singleton = new Singleton();private Singleton() {System.out.println("生成了一个实例。");}public static Singleton getInstance() {return singleton;}
}

Main.java

public class Main {public static void main(String[] args) {System.out.println("Start.");Singleton obj1 = Singleton.getInstance();Singleton obj2 = Singleton.getInstance();if (obj1 == obj2) {System.out.println("obj1与obj2是相同的实例。");} else {System.out.println("obj1与obj2是不同的实例。");}System.out.println("End.");}
}

运行结果

Start.
生成了一个实例。
obj1与obj2是相同的实例。
End.

扩展思路的要点

何时生成这个唯一的实例

注意示例程序的运行结果,在【Start.】之后就显示出了【生成了一个实例。】

程序运行后,在第一次调用 getInstance方法时,Singleton类会被初始化。也就是在这个时候,static字段singleton被初始化,生成了唯一的一个实例。

相关的设计模式

在以下模式中,多数情况下只会生成一个实例。

AbstractFactory 模式(第8章)

Builder 模式(第7章)

Facade 模式(第15章)

Prototype 模式(第6章)

六、Prototype模式:通过复制生成实例

Prototype模式:不根据类来生成实例(不使用 new ClassName() 的形式),而是根据实例来生成新实例

Prototype有“原型”“模型”的意思。在设计模式中,它是指根据实例原型、实例模型来生成新的实例。

Java可以使用clone创建出实例的副本。本章将学习clone方法与Cloneable接口的使用方法。

示例程序类图

在这里插入图片描述

Manager类

package framework;import java.util.*;public class Manager {private HashMap showcase = new HashMap();public void register(String name, Product proto) {showcase.put(name, proto);}public Product create(String protoname) {Product p = (Product) showcase.get(protoname);return p.createClone();}
}

Product接口

package framework;import java.lang.Cloneable;public interface Product extends Cloneable {public abstract void use(String s);public abstract Product createClone();
}

MessageBox类

import framework.*;public class MessageBox implements Product {private char decochar;public MessageBox(char decochar) {this.decochar = decochar;}public void use(String s) {// 业务逻辑:把传入的s用decochar包围打印}public Product createClone() {Product p = null;try {p = (Product) clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return p;}
}

UnderlinePen类

与MessageBox几乎相同,use()方法中对s进行加下划线打印

import framework.*;public class UnderlinePen implements Product {private char ulchar;public UnderlinePen(char ulchar) {this.ulchar = ulchar;}public void use(String s) {// 业务逻辑:把传入的s用decochar加下划线打印}public Product createClone() {Product p = null;try {p = (Product) clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return p;}
}

Main测试类

import framework.*;public class Main {public static void main(String[] args) {// 准备Manager manager = new Manager();UnderlinePen upen = new UnderlinePen('~');MessageBox mbox = new MessageBox('*');MessageBox sbox = new MessageBox('/');manager.register("strong message", upen);manager.register("warning box", mbox);manager.register("slash box", sbox);// 生成Product p1 = manager.create("strong message");p1.use("Hello, world.");Product p2 = manager.create("warning box");p2.use("Hello, world.");Product p3 = manager.create("slash box");p3.use("Hello, world.");}
}

运行结果

在这里插入图片描述

角色

在这里插入图片描述

  • Prototype(原型)

    负责定义用于复制现有实例来生成新实例的方法。在示例程序中,由Product接口扮演此角色。

  • ConcretePrototype(具体的原型)

    负责实现复制现有实例并生成新实例的方法。在示例程序中,由MessageBox类和UnderlinePen类扮演此角色。

  • Client(使用者)

    负责使用复制实例的方法生成新的实例。在示例程序中,由Manager类扮演此角色。

扩展思路的要点

不能根据类来生成实例吗

根据类生成实例:new Something()

不根据类生成实例的场景:

  1. 对象种类繁多,无法将它们整合到一个类中时

示例程序中,一共出现了3种对字符串处理的样式。但只要想做,能支持更多样式。

但若将每种样式都编写为一个类,类的数量将太多,较难管理源程序。

  1. 难以根据类生成实例时

本例中感觉不到这一点。试想若要开发一个用户可以使用鼠标进行操作的、类似于图形编辑器的应用程序,可能更容易理解。

假设我们想生成一个和用户通过一系列鼠标操作所创建出来的实例完全一样的实例,此时,与根据类来生成实例相比,根据实例来生成实例要更简单。

  1. 想解耦框架与生成的实例时

在示例程序中,我们将复制(clone)实例的部分封装在 framework包中了。

在Manager类的create方法中,没使用类名,取而代之使用了strong messageslash box等字符串为生成的实例命名。

与Java自带的生成实例的new Something()方式相比,这种方式具有更好的通用性,而且将框架从类名的束缚中解脱出来了。

类名是束缚吗

在源程序中使用类名到底会有什么问题?在代码中出现要使用的类的名字不是理所当然的吗?

再回忆一下面向对象编程的目标之一:作为组件复用

一旦在代码中出现要使用的类的名字,就无法与该类分离开来,也就无法实现复用。

虽然可以通过替换源代码或改变类名来解决这个问题。但此处说的“作为组件复用”不包含替换源代码。

以Java来说,重要的是当手边只有class文件(.class)时,该类能否被复用。即使没有Java文件(.java)也能复用该类才是关键。

当多个类必须紧密结合时,代码中出现这些类的名字没问题。但若那些需要被独立出来作为组件复用的类的名字出现在代码中,那就有问题了。

相关的设计模式

Flyweight 模式(第20章)

Prototype 模式可以生成一个与当前实例的状态完全相同的实例。

Flyweight 模式可以在不同的地方使用同一个实例。

Memento 模式(第18章)

Prototype 模式可以生成一个与当前实例的状态完全相同的实例。

Memento 模式可以保存当前实例的状态,以实现快照和撤销功能。

Composite 模式(第11章)以及Decorator模式(第12章)

经常使用Composite模式和Decorator模式时,需要能够动态地创建复杂结构的实例。这时可以使用 Prototype模式,以帮助我们方便地生成实例。

Command 模式(第22章)

想要复制Command 模式中出现的命令时,可以使用 Prototype模式。

补充:Clone注意事项

clone方法所进行的复制只是将被复制实例的字段值直接复制到新的实例中,即它没考虑字段中所保存的实例的内容。

例如,当字段中保存的是数组时,如果使用clone方法进行复制,则只会复制该数组的引用,并不会一一复制数组中的元素。

像上面这样的字段对字段的复制(field-to-field-copy)被称为浅复制(shallow copy)。clone方法所进行的复制就是浅复制。

当使用clone方法进行浅复制无法满足需求时,可以重写 clone方法,实现自己需要的复制功能(重写clone方法时,别忘了使用super.clone()来调用父类的clone方法)。

clone方法只进行复制,不会调用被复制实例的构造函数。

对于在生成实例时需要进行特殊的初始化处理的类,需要自己去实现clone方法,在其内部进行这些初始化处理。

七、Builder模式:组装复杂的实例

示例程序类图

在这里插入图片描述

注意:此案例中Builder是抽象类,但也可以用interface来实现这个模式。

Director类

public class Director {private Builder builder;public Director(Builder builder) {// 接收的参数是Builder类的子类,所以可以将其保存在builder字段中this.builder = builder;}// 编写文档public void construct() {// 标题、字符串、条目builder.makeTitle("Greeting");builder.makeString("从早上至下午");builder.makeItems(new String[]{"早上好。", "下午好。"});// 其他字符串、其他条目builder.makeString("晚上");builder.makeItems(new String[]{"晚上好。", "晚安。", "再见。"});// 完成文档builder.close();}
}

TextBuilder类

public class TextBuilder extends Builder {// 文档内容保存在该字段中private StringBuffer buffer = new StringBuffer();// 纯文本的标题public void makeTitle(String title) {// 业务逻辑:buffer.append 装饰线、为标题添加『』、换行}// 纯文本的字符串public void makeString(String str) {// 业务逻辑:buffer.append 为字符串添加■、换行}// 纯文本的条目public void makeItems(String[] items) {// 业务逻辑:buffer.append 为条目添加・、换行}// 完成文档 添加装饰线public void close() {buffer.append("==============================\n");}// 完成的文档public String getResult() {                                 return buffer.toString();}
}

HTMLBuilder类

import java.io.*;public class HTMLBuilder extends Builder {private String filename;                                                        // 文件名private PrintWriter writer;                                                     // 用于编写文件的PrintWriterpublic void makeTitle(String title) {                                           // HTML文件的标题filename = title + ".html";                                                 // 将标题作为文件名try {writer = new PrintWriter(new FileWriter(filename));                     // 生成 PrintWriter} catch (IOException e) {e.printStackTrace();}writer.println("<html><head><title>" + title + "</title></head><body>");    // 输出标题writer.println("<h1>" + title + "</h1>");}public void makeString(String str) {                                            // HTML文件中的字符串writer.println("<p>" + str + "</p>");                                       // 用<p>标签输出}public void makeItems(String[] items) {                                         // HTML文件中的条目writer.println("<ul>");                                                     // 用<ul>和<li>输出for (int i = 0; i < items.length; i++) {writer.println("<li>" + items[i] + "</li>");}writer.println("</ul>");}public void close() {                                                           // 完成文档writer.println("</body></html>");                                           // 关闭标签writer.close();                                                             // 关闭文件}public String getResult() {                                                     // 编写完成的文档return filename;                                                            // 返回文件名}
}

Main测试类

public class Main {public static void main(String[] args) {if (args.length != 1) {usage();System.exit(0);}if (args[0].equals("plain")) {TextBuilder textbuilder = new TextBuilder();Director director = new Director(textbuilder);director.construct();String result = textbuilder.getResult();System.out.println(result);} else if (args[0].equals("html")) {HTMLBuilder htmlbuilder = new HTMLBuilder();Director director = new Director(htmlbuilder);director.construct();String filename = htmlbuilder.getResult();System.out.println(filename + "文件编写完成。");} else {usage();System.exit(0);}}public static void usage() {System.out.println("Usage: java Main plain      编写纯文本文档");System.out.println("Usage: java Main html       编写HTML文档");}
}

角色

在这里插入图片描述

  • Builder(建造者)

    负责定义用于生成实例的接口(API)。Builder角色中准备了用于生成实例的方法。在示例程序中,由Builder类扮演此角色。

  • ConcreteBuilder(具体的建造者)

    是负责实现 Builder角色的接口的类(API),定义了在生成实例时实际被调用的方法、获取最终生成结果的方法。

    在示例程序中,由TextBuilder类和HTMLBuilder类扮演此角色。

  • Director(监工)

    负责使用Builder角色的接口(API)来生成实例。它并不依赖于ConcreteBuilder角色。

    为了确保不论ConcreteBuilder角色是如何被定义的,Director角色都能正常工作,它只调用在Builder角色中被定义的方法。

    在示例程序中,由Director类扮演此角色。

  • Client(使用者)

    该角色使用了Builder模式(Builder模式并不包含Client角色)。

    在示例程序中,由Main类扮演此角色。

相关的设计模式

Template Method模式(第3章)

Builder模式:Director角色控制Builder角色。

Template Method模式:父类控制子类。

Composite 模式(第11章)

有些情况下 Builder模式生成的实例构成了Composite模式。

Abstract Factory模式(第8章)

Builder模式和Abstract Factory模式都用于生成复杂的实例。

Facade模式(第15章)

在 Builder模式中,Director角色通过组合 Builder角色中的复杂方法向外部提供可以简单生成实例的接口(API)(相当于示例程序中的construct方法)。

Facade模式中的 Facade角色则是通过组合内部模块向外部提供可以简单调用的接口(API)。

扩展思路的要点

谁知道什么

Director类不知道自己使用的究竟是Builder类的哪个子类也好。因为“只有不知道子类才能替换”。

正是因为可以替换,组件才具有高价值。作为设计人员,我们必须时刻关注这种“可替换性”。

设计时能够决定的事情和不能决定的事情

在Builder类中,需要声明编辑文档(实现功能)所必需的所有方法,在Builder类中应当定义哪些方法很重要。

而且,Builder类还必须能够应对将来子类可能增加的需求,若将来要新编写一种文档类型的子类实现,是否需要新的方法?

虽然类的设计者无法准确地预测到将来可能发生的变化,但还是有必要让设计出的类能够尽可能灵活地应对近期可能发生的变化。

代码的阅读方法和修改方法

如果没有理解各个类的角色就动手增加和修改代码,在判断到底应该修改哪个类时,就会很容易出错。

八、Abstract Factory模式:将关联零件组装成产品

在 Abstract Factory模式中,不仅有“抽象工厂”,还有“抽象零件”和“抽象产品”。抽象工厂的工作是将“抽象零件”组装为“抽象产品”。

回顾面向对象编程中的“抽象”这个词的具体含义:它指的是“不考虑具体怎样实现,而是仅关注接口(API)"的状态。

例如,抽象方法(Abstract Method)并不定义方法的具体实现,而是仅仅只确定了方法的名字和签名(参数的类型和个数)。

我们不关心零件的具体实现,而只关心接口(API),仅使用该接口(API)将零件组装成为产品。

在 Tempate Method模式和Builder模式中,子类这一层负责方法的具体实现。

在 AbstractFactory模式中也是一样的。在子类这一层中有具体的工厂,它负责将具体的零件组装成为具体的产品。

本章中的示例程序的功能是将带有层次关系的链接的集合制作成HTML文件。

示例程序类图

在这里插入图片描述

factory包 - 抽象

Item
package factory;public abstract class Item {protected String caption;public Item(String caption) {this.caption = caption;}public abstract String makeHTML();
}
Link
package factory;public abstract class Link extends Item {protected String url;public Link(String caption, String url) {super(caption);this.url = url;}
}
Tray
package factory;import java.util.ArrayList;public abstract class Tray extends Item {protected ArrayList tray = new ArrayList();public Tray(String caption) {super(caption);}// 将Link类和Tray类集合在一起。为表示集合的对象是“Link类和Tray类”,我们设置add方法的参数为Link类和Tray类的父类Item类。public void add(Item item) {tray.add(item);}
}
Page
package factory;import java.io.*;
import java.util.ArrayList;public abstract class Page {protected String title;protected String author;protected ArrayList content = new ArrayList();public Page(String title, String author) {this.title = title;this.author = author;}// 向页面中增加Item(即Link或Tray)。增加的Item将会在页面中显示出来。public void add(Item item) {content.add(item);}// output方法是一个简单的 Template Method模式 的方法。public void output() {try {// 首先 根据页面标题确定文件名String filename = title + ".html";Writer writer = new FileWriter(filename);// 然后 调用makeHTML抽象方法将自身保存的HTML内容写入到文件中。writer.write(this.makeHTML());writer.close();System.out.println(filename + " 编写完成。");} catch (IOException e) {e.printStackTrace();}}public abstract String makeHTML();
}
Factory
package factory;public abstract class Factory {// 虽然getFactory方法生成的是具体工厂的实例,但是返回值的类型是抽象工厂类型public static Factory getFactory(String classname) {Factory factory = null;try {// 根据 类名字符串 生成具体工厂的实例。factory = (Factory) Class.forName(classname).newInstance();} catch (ClassNotFoundException e) {System.err.println("没有找到 " + classname + "类。");} catch (Exception e) {e.printStackTrace();}return factory;}// createLink、createTray、createPage等方法 是用于在抽象工厂中生成零件和产品的方法public abstract Link createLink(String caption, String url);public abstract Tray createTray(String caption);public abstract Page createPage(String title, String author);
}

listfactory - 具体

ListFactory
package listfactory;
import factory.*;public class ListFactory extends Factory {// 各个方法内部只是分别简单地new出了对应类的实例(根据实际需求,这里可能需要用 Prototype模式来进行clone)public Link createLink(String caption, String url) {return new ListLink(caption, url);}public Tray createTray(String caption) {return new ListTray(caption);}public Page createPage(String title, String author) {return new ListPage(title, author);}
}
ListLink
package listfactory;
import factory.*;public class ListLink extends Link {public ListLink(String caption, String url) {super(caption, url);}public String makeHTML() {return "  <li><a href=\"" + url + "\">" + caption + "</a></li>\n";}
}
ListTray
package listfactory;import factory.*;import java.util.Iterator;public class ListTray extends Tray {public ListTray(String caption) {super(caption);}public String makeHTML() {StringBuffer buffer = new StringBuffer().append("<li>\n").append(caption + "\n").append("<ul>\n");Iterator it = tray.iterator();while (it.hasNext()) {Item item = (Item) it.next();// 这里并不关心变量item中保存的实例究竟是ListLink的实例还是ListTray的实例,只是简单地调用了item.makeHTML()语句而已。// 同时这里不能使用 switch语句或if语句去判断变量item中保存的实例的类型,否则就不是面向对象编程了。buffer.append(item.makeHTML());}buffer.append("</ul>\n").append("</li>\n");return buffer.toString();}
}
ListPage
package listfactory;import factory.*;import java.util.Iterator;public class ListPage extends Page {public ListPage(String title, String author) {super(title, author);}public String makeHTML() {StringBuffer buffer = new StringBuffer().append("<html><head><title>" + title + "</title></head>\n").append("<body>\n").append("<h1>" + title + "</h1>\n").append("<ul>\n");// content继承自Page类的字段。Iterator it = content.iterator();while (it.hasNext()) {Item item = (Item) it.next();buffer.append(item.makeHTML());}buffer.append("</ul>\n").append("<hr><address>" + author + "</address>").append("</body></html>\n");return buffer.toString();}
}

Main

import factory.*;public class Main {public static void main(String[] args) {if (args.length != 1) {System.out.println("Usage: java Main class.name.of.ConcreteFactory");System.out.println("Example 1: java Main listfactory.ListFactory");System.out.println("Example 2: java Main tablefactory.TableFactory");System.exit(0);}Factory factory = Factory.getFactory(args[0]);Link people = factory.createLink("人民日报", "http://www.people.com.cn/");Link gmw = factory.createLink("光明日报", "http://www.gmw.cn/");Link us_yahoo = factory.createLink("Yahoo!", "http://www.yahoo.com/");Link jp_yahoo = factory.createLink("Yahoo!Japan", "http://www.yahoo.co.jp/");Link excite = factory.createLink("Excite", "http://www.excite.com/");Link google = factory.createLink("Google", "http://www.google.com/");Tray traynews = factory.createTray("日报");traynews.add(people);traynews.add(gmw);Tray trayyahoo = factory.createTray("Yahoo!");trayyahoo.add(us_yahoo);trayyahoo.add(jp_yahoo);Tray traysearch = factory.createTray("检索引擎");traysearch.add(trayyahoo);traysearch.add(excite);traysearch.add(google);Page page = factory.createPage("LinkPage", "杨文轩");page.add(traynews);page.add(traysearch);page.output();}
}

为示例程序增加其他工厂

当只有一个具体工厂的时候,没有必要划分“抽象类”与“具体类”。

可以为示例程序增加其他的具体工厂,比如编写含有表格的HTML格式的文件。

之前的listfactory包的功能是将超链接以条目形式展示出来,

现在可以新建tablefactory包,在其下编写其他工厂将链接以表格形式展示出来:

新增TableFactory、TableLink、TableTray、TablePage,内容与listfactory包下对应的类相似,只是在编写html具体内容时有些要改为table标签之类的。

角色

在这里插入图片描述

  • AbstractProduct(抽象产品)

    定义 AbstractFactory 角色所生成的抽象零件和产品的接口(API)。

    示例中是 Link类、Tray类、Page类

  • AbstractFactory(抽象工厂)

    定义用于生成抽象产品的接口(API)。

    示例中是 Factory类

  • Client(委托者)

    仅会调用 AbstractFactory角色和AbstractProduct 角色的接口(API)来进行工作,不知道具体的零件、产品、工厂。

    示例中是 Main类,上图省略了这一角色。

  • ConcreteProduct(具体产品)

    实现AbstractProduct 角色的接口(API)。

    示例中是以下

    listfactory包:ListLink类、ListTray类、ListPage类

    tablefactory包:TableLink类、TableTray类、TablePage类

  • ConcreteFactory(具体工厂)

    实现AbstractFactory角色的接口(API)。

    示例中是以下

    listfactory包:Listfactory类

    tablefactory包:Tablefactory类

拓展思路的要点

易于增加具体的工厂

在本模式中很容易增加具体的工厂,因为需要编写哪些类和需要实现哪些方法都非常清楚。

无论要增加多少个具体工厂(或是要修改具体工厂的 Bug),都无需修改抽象工厂和 Main部分。

难以增加新的零件

怎么在 Abstract Factory模式中增加新的零件?

例如,我们要在factory包中增加一个表示图像的Picture零件,必须对所有的具体工厂进行相应的修改才行。

具体来说,在listfactory包中,需做修改:在ListFactory 中加入createPicture方法,新增ListPicture类。

已编写完成的具体工厂越多,修改的工作量就会越大。

相关的设计模式

Builder 模式(第7章)

Abstract Factory 模式:通过调用抽象产品的接口(API)来组装抽象产品,生成具有复杂结构的实例。

Builder 模式:分阶段地制作复杂实例。

Factory Method模式(第4章)

有时Abstract Factory 模式中零件和产品的生成会使用到 Factory Method模式。

Composite模式(第11章)

有时Abstract Factory模式在制作产品时会使用Composite模式。

Singleton 模式(第5章)

有时Abstract Factory 模式中的具体工厂会使用 Singleton模式。

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

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

相关文章

[Meachines] [Easy] bounty web.config 文件上传代码注入+内核MS10-092权限提升

信息收集 IP AddressOpening Ports10.10.10.93TCP:80 $ nmap -p- 10.10.10.93 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION │ 80/tcp open http Microsoft IIS httpd 7.5 …

使用Element UI组件时,icon图标不显示

问题描述&#xff1a; 我在使用Element UI组件的日期选择器时&#xff0c;发现图标不显示(左边是原图&#xff0c;右边的问题图)。 经过检查我发现&#xff0c;我的JS&#xff0c;CSS文件都没有问题&#xff0c;只是缺少了element-icons.tff和element-icons.woff这两个文件。 …

Qt 0814作业

一、思维导图 二、登录窗口界面 自由发挥登录窗口的应用场景&#xff0c;实现一个登录窗口界面 要求&#xff1a;每行代码都有注释 【需要用到的图片或者动图&#xff0c;自己去网上找】 #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(par…

【OCR 学习笔记】二值化——全局阈值方法

二值化——全局阈值方法 固定阈值方法Otsu算法在OpenCV中的实现固定阈值Otsu算法 图像二值化&#xff08;Image Binarization&#xff09;是指将像素点的灰度值设为0或255&#xff0c;使图像呈现明显的黑白效果。二值化一方面减少了数据维度&#xff0c;另一方面通过排除原图中…

微服务架构的介绍

系统架构的演变 随着互联⽹的发展&#xff0c;⽹站应⽤的规模不断扩⼤&#xff0c;常规的应⽤架构已⽆法应对&#xff0c;分布式服务架构以及微服务架构势在必⾏&#xff0c;必需⼀个治理系统确保架构有条不紊的演进。 单体应用架构 Web应⽤程序发展的早期&#xff0c;⼤部分…

C++入门——“继承”

一、引入 面相对象的计算机语言有三大特性&#xff1a;“封装”、“继承”、“多态”。今天来讲解一下C的一大重要特性——继承。 通俗理解来讲&#xff0c;继承就和现实生活一样&#xff0c;子辈继承父辈的一些特性&#xff0c;C中的继承也可以这样理解。它允许我们在保持原有…

计算机毕业设计选什么题目好?springboot 基于Java的学院教学工作量统计系统

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

vue使用高德获取当前地区天气

1、收件箱 | 高德控制台 (amap.com) 首先打开高德开放平台注册一下 2、创建一个应用获取到key后面获取天气的时候 请求接口的时候会用到key 2.1.1 创建应用的时候注意类型选成天气 2.1.2 创建完成之后就点添加key 然后选择web服务就行 3、可以调取天气接口 天气查询-基础 API…

【鸿蒙学习】HarmonyOS应用开发者基础 - 构建更加丰富的页面(一)

学完时间&#xff1a;2024年8月14日 一、前言叨叨 学习HarmonyOS的第六课&#xff0c;人数又成功的降了500名左右&#xff0c;到了3575人了。 二、ArkWeb 1、概念介绍 ArkWeb是用于应用程序中显示Web页面内容的Web组件&#xff0c;为开发者提供页面加载、页面交互、页面调…

文献检索中JCR与SCIE的区别

一、SCIE Science Citation Index-Expanded&#xff08;SCI-E&#xff0c;科学引文索引&#xff09;,属于Web of Science中一个子库&#xff0c;是全球著名的科学引文索引数据库&#xff0c;收录了全球自然科学、工程技术、临床医学等领域内170多个学科的9500多种国际性、高影响…

volta引发的血案

什么是volta volta用于做项目级别的node版本控制&#xff0c;当手头上的项目有多个时&#xff0c;且node版本可能还不一样&#xff0c;我们需要不断切换node版本。使用volta可以很好的解决这个问题。只需要安装volta&#xff0c;然后在下面的package.json中配置好node版本即可…

Oracle 用户-表空间-表之间关系常用SQL

问题&#xff1a; 当某一个表数据量特别大&#xff0c;突然插入数据一直失败&#xff0c;可能是表空间不足&#xff0c;需要查看表的使用率 用户-表空间-表之间关系&#xff1a;用户可以有多个表空间&#xff0c;表空间可以有多个表&#xff0c;表只能拥有一个表空间和用户 1.…

跨国企业是否适合使用专线连接国际互联网?

在跨国企业开展国际通信时&#xff0c;需要稳定高效的网络连接来保障业务运作。虽然传统的互联网连接方式较为普遍&#xff0c;但由于带宽有限、网络延迟等问题&#xff0c;跨国企业往往会遇到网速缓慢、连接不稳定等挑战。因此&#xff0c;专线连接逐渐成为跨国企业的一个可行…

如何将MySQL迁移到TiDB,完成无缝业务切换?

当 MySQL 数据库的单表数据量达到了亿级&#xff0c;会发生什么&#xff1f; 这个现象表示公司的业务上了一个台阶&#xff0c;随着数据量的增加&#xff0c;公司规模也进一步扩大了&#xff0c;是非常喜人的一个改变 &#xff0c;然而随之而来的其他变化&#xff0c;就没那么…

C#实现国产Linux视频录制生成mp4

一. 技术方案 要完成这些功能&#xff0c;具体来说&#xff0c;需要解决如下几个技术问题&#xff1a; &#xff08;1&#xff09;麦克风数据采集。 &#xff08;2&#xff09;摄像头数据采集。 &#xff08;3&#xff09;音频数据编码。 &#xff08;4&#xff09;视频数…

低代码与AI:赋能企业数字化转型

引言 随着全球经济的快速发展和科技的飞速进步&#xff0c;数字化转型已成为各个行业和企业发展的重要趋势。数字化转型的背景不仅是提升效率和竞争力的手段&#xff0c;更是适应市场变化、满足客户需求的必由之路。 在当今信息化时代&#xff0c;技术的变革推动了企业运营方式…

嵌入式系统:全面解读与关键要点

嵌入式系统&#xff0c;这个看似专业而遥远的技术词汇&#xff0c;其实早已渗透进了我们日常生活的方方面面。从智能手机到家用电器&#xff0c;再到汽车中的电子控制系统&#xff0c;嵌入式系统无处不在。你是否好奇它们是如何工作的&#xff0c;又有哪些关键点值得我们关注&a…

强大的接口测试可视化工具:Postman Flows

Postman Flows是一种接口测试可视化工具&#xff0c;可以使用流的形式在Postman工作台将请求接口、数据处理和创建实际流程整合到一起。如下图所示 Postman Flows是以API为中心的可视化应用程序开发界面。它提供了一个无限的画布用于编排和串连API&#xff0c;数据可视化来显示…

配置oss cdn加速静态资源访问 阿里云

效果对比 配置cdn下载速度对比 步骤 1: 登录阿里云控制台控制台主页&#xff0c;找到并点击“对象存储 OSS” 创建存储空间&#xff08;Bucket&#xff09; 设置权限 步骤 2: 获取外网访问地址 步骤 3 在 CDN 中使用该地址 复制该外网访问地址 打开全站加速 DCDN/域名管理 添…

STM32 PWR电源控制 与 低功耗模式 详解

目录 STM32 PWR电源控制 与 低功耗模式 详解 1. PWR 电源控制 简介 2. PWR 电源控制 框图 3. 上电复位和掉电复位 与 可编程电压检测器&#xff08;PVD&#xff09; 3.1 内嵌复位与电源控制模块特性图 3.2 上电复位和掉电复位 3.3 可编程电压检测器&#xff08;PVD&…