网站建设与维护书籍推荐/收录提交入口网址
一、概述
1.1简介
在java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦,如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的;所以说,工厂模式最大的优点就是:解耦。
在本教程中会介绍三种工厂的使用
- 简单工厂模式(不属于GOF的23种经典设计模式)
- 工厂方法模式
- 抽象工厂模式
1.2简单工厂模式
概述
简单工厂不是一种设计模式,反而比较像是一种编程习惯。
简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,它提供了一个工厂类,该类专门用于创建其他对象。简单工厂模式属于静态工厂模式,即在工厂类中提供静态方法,根据传入的参数不同返回不同的对象实例。
结构
简单工厂模式包含三个角色:
- 工厂类(Creator):提供了创建产品的方法,调用者通过该方法来获取产品。
- 抽象产品类(Product):定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品类(Concrete Product):定义具体的产品实现类,实现抽象产品类中的抽象方法。
实现
原先逻辑
SimpleCoffeeFactory.java
package com.yanyu.SimpleFactory;public class SimpleCoffeeFactory {public Coffee createCoffee(String type) {Coffee coffee = null;if("americano".equals(type)) {coffee = new AmericanoCoffee();} else if("latte".equals(type)) {coffee = new LatteCoffee();}return coffee;}
}
Coffeestore.java
package com.yanyu.SimpleFactory;public class Coffeestore {public Coffee orderCoffee(String type) {Coffee coffee = null;if ("american".equals(type)) {coffee = new AmericanoCoffee();} else if ("latte".equals(type)) {coffee = new LatteCoffee();} else {throw new RuntimeException("对不起,您所点的咖啡没有");}// 加配料coffee.addMilk();coffee.addSugar();return coffee;}
}
Coffee.java
package com.yanyu.SimpleFactory;public abstract class Coffee {public abstract String getName();// 加糖public void addSugar() {System.out.println("加糖");}// 加奶public void addMilk() {System.out.println("加奶");}
}
AmericanoCoffee.java
package com.yanyu.SimpleFactory;public class AmericanoCoffee extends Coffee{public String getName(){return"美式咖啡";}
}
LatteCoffee.java
package com.yanyu.SimpleFactory;public class LatteCoffee extends Coffee{public String getName(){return"拿铁咖啡";}
}
test
package com.yanyu.SimpleFactory;public class Client {public static void main(String[] args) {// 创建咖啡店类对象Coffeestore store = new Coffeestore();Coffee coffee = store.orderCoffee("latte");System.out.println(coffee.getName());}
}
SimpleCoffeeFactory是工厂类,负责生产不同类型的咖啡,Coffeestore是客户端,通过调用工厂类的方法来获取咖啡。简单工厂模式属于创建型模式,通过将对象的创建工作交给工厂类来实现客户端与具体产品类的解耦,可以方便地扩展新的产品类型,同时也便于管理和维护。在这个例子中,Coffeestore只需要调用工厂类的createCoffee方法即可获取不同类型的咖啡,而不需要关心具体如何创建。
工厂(factory)处理创建对象的细节,一旦有了SimpleCoffeeFactory,CoffeeStore类中的orderCoffee()就变成此对象的客户,后期如果需要Coffee对象直接从工厂中获取即可。这样也就解除了和Coffee实现类的耦合,同时又产生了新的耦合,CoffeeStore对象和SimpleCoffeeFactory工厂对象的耦合,工厂对象和商品对象的耦合。
后期如果再加新品种的咖啡,我们势必要需求修改SimpleCoffeeFactory的代码,违反了开闭原则。工厂类的客户端可能有很多,比如创建美团外卖等,这样只需要修改工厂类的代码,省去其他的修改操作。
扩展静态工厂
静态工厂是一种创建对象的方式,它通过一个静态方法来获取对象,有时也被称为静态工厂方法。静态工厂方法通常不需要创建对象,所以可以在不创建对象的情况下直接返回对象。
通过扩展静态工厂,我们可以让工厂方法更加灵活,以便能够生产不同类型的对象。它也不是23种设计模式中的
public class SimpleCoffeeFactory {
public static Coffee createCoffee(String type) {Coffee coffee = null;if("americano".equals(type)) {coffee = new AmericanoCoffee();} else if("latte".equals(type)) {coffee = new LatteCoffee();}return coffe;}
}
优缺点
优点:
封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容易扩展。
缺点:
增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。
1.3工厂方法模式
针对上例中的缺点,使用工厂方法模式就可以完美的解决,完全遵循开闭原则。
概述
工厂方法模式(Factory Method Pattern)又称为工厂模式,是一种创建型设计模式。在工厂方法模式中,定义一个用于创建对象的接口,但让子类决定将哪一个类实例化。工厂方法把类的实例化推迟到子类中进行,从而实现了解耦。
结构
工厂方法模式的主要角色:
- 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
- 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。
实现
抽象工厂:
package com.yanyu.FactoryMethod;public interface CoffeeFactory {Coffee createCoffee();
}
具体工厂:
public class LatteCoffeeFactory implements CoffeeFactory {
public Coffee createCoffee() {return new LatteCoffee();}
}
public class AmericanCoffeeFactory implements CoffeeFactory {
public Coffee createCoffee() {return new AmericanoCoffee();}
}
咖啡店类:
package com.yanyu.FactoryMethod;public class CoffeeStore {private CoffeeFactory factory;public void SetFactory(CoffeeFactory factory) {this.factory = factory;}public Coffee orderCoffee() {Coffee coffee = factory.createCoffee();coffee.addMilk();coffee.addSugar();return coffee;}
}
测试
package com.yanyu.FactoryMethod;public class client {public static void main(String[] args) {// 创建咖啡店对象CoffeeStore store = new CoffeeStore();//创建工厂对象CoffeeFactory factory = new AmericanCoffeeFactory();store.SetFactory(factory);// 点咖啡Coffee coffee = store.orderCoffee();System.out.println(coffee.getName());}
}
这就是实现开闭原则的核心:一旦转换成功,我们拓展功能就只需要增加相应类的or接口即可,不需要再动原来的代码
工厂方法模式是简单工厂模式的进一步抽象。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。
优缺点
优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
- 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;
缺点:
- 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
工厂方法模式增加了系统抽象性和理解难度,需要对工厂类和具体产品类进行抽象和设计。
常见应用
常见的使用场景包括:
数据库连接池的实现。
日志处理器的实现。
图形界面控件库的开发。
任何需要创建对象的场景,特别是对象创建过程复杂或需要隐藏细节的场景。
1.4抽象工厂模式
产品族和同一级别产品
产品族是指一组具有相似特征和用途的产品,它们通常共享相同的品牌名称、市场定位和推广策略。比如,苹果公司的iPhone产品族包括iPhone 12、iPhone 11、iPhone SE 等,它们都是苹果公司的智能手机产品,具有相似的功能和设计。
同一级别产品是指在市场上竞争的,具有相似功能和特点的产品。这些产品可能来自不同的品牌,但是它们都是在同一细分市场上竞争的产品。举例来说,苹果公司的iPhone和三星公司的Galaxy手机都是智能手机,它们在市场上是同一级别的产品。
概述
在抽象工厂模式中,我们定义一个抽象工厂接口,该接口具有多个工厂方法,每个工厂方法负责创建一个产品族中的一种产品。然后我们创建一个具体的工厂类来实现抽象工厂接口,并在其中实现工厂方法,以便能够创建具体的产品。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
结构
- 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。
- 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
- 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
- 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它 同具体工厂之间是多对一的关系。
实现
抽象工厂:
package com.yanyu.AbstractFactory;public interface DessertFactory {Coffee createCoffee();Dessert createDessert();
}
抽象类
package com.yanyu.AbstractFactory;public abstract class Dessert {public abstract void show();
}
具体工厂:
//美式甜点工厂
public class AmericanDessertFactory implements DessertFactory {
public Coffee createCoffee() {return new AmericanCoffee();}
public Dessert createDessert() {return new MatchaMousse();}
}
//意大利风味甜点工厂
public class ItalyDessertFactory implements DessertFactory {
public Coffee createCoffee() {return new LatteCoffee();}
public Dessert createDessert() {return new Tiramisu();}
}
具体类:
package com.yanyu.AbstractFactory;public class Trimisu extends Dessert {public void show() {System.out.println("提拉米苏");}
}package com.yanyu.AbstractFactory;public class MatchaMousse extends Dessert {public void show() {System.out.println("抹茶慕斯");}
}
test
package com.yanyu.AbstractFactory;public class Client {public static void main(String[] args) {// 创建的是意大利风味甜品工厂对象// ItalyDessertFactory factory = new ItalyDessertFactory();AmericanDessertFactory factory = new AmericanDessertFactory();// 获取拿铁咖啡和提拉米苏甜品Coffee coffee = factory.createCoffee();Dessert dessert = factory.createDessert();System.out.println(coffee.getName()); dessert.show();
}
}
如果要加同一个产品族的话,只需要再加一个对应的工厂类即可,不需要修改其他的类。
优缺点
优点:
当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:
由于抽象工厂只能创建某个产品族中的全部产品,所以加入新产品时需要修改所有的具体工厂类,增加了维护成本
常见应用
抽象工厂模式常见应用包括以下几个方面:
1. 操作系统的UI界面设计:操作系统常常提供多种不同的UI界面风格,如Windows提供的经典风格、XP风格、Win7风格等,可以使用抽象工厂模式来实现对不同风格的UI界面进行定制和管理。
2. 游戏开发:游戏中的物品、角色、道具等都可以使用抽象工厂模式来进行设计,不同的游戏可以使用不同的抽象工厂来创建不同的游戏元素。
3. 数据库连接:数据库连接器可以使用抽象工厂模式来设计,通过使用不同的工厂来创建不同类型的数据库连接器,从而支持多种不同的数据库类型。
4. 跨平台开发:不同的操作系统和不同的硬件架构需要不同的代码实现,使用抽象工厂模式可以通过实现不同的工厂来创建适配不同平台的代码。
5. GUI开发:GUI框架常常需要支持多种不同的控件和主题,使用抽象工厂模式可以通过不同的工厂来创建不同的控件和主题。
1.5JDK源码解析-Collection.iterator方法
public class Demo {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("令狐冲");list.add("风清扬");list.add("任我行");
//获取迭代器对象Iterator<String> it = list.iterator();//使用迭代器遍历while(it.hasNext()) {String ele = it.next();System.out.println(ele);}}
}
Collection接口是抽象工厂类,ArrayList是具体的工厂类;Iterator接口是抽象商品类,ArrayList类中的Iter内部类是具体的商品类。在具体的工厂类中iterator()方法创建具体的商品类的对象。
二、实验
2.1简单工厂模式
任务描述
本关任务:某电视机厂专为各知名电视机品牌代工生产各类电视机,当需要海尔牌电视机时只需要在调用该工厂的工厂方法时传入参数“Haier”,需要海信电视机时只需要传入参数“Hisense”,工厂可以根据传入的不同参数返回不同品牌的电视机。现使用简单工厂模式来模拟,程序将会自动从配置文件中读取参数,请根据以下类图来补全代码。
相关知识
为了完成本关任务,你需要掌握:
- 简单工厂模式包含的角色;
- 简单工厂模式缺点。
简单工厂模式包含的角色
- Factory:工厂角色
- Product:抽象产品角色
- ConcreteProduct:具体产品角色
简单工厂模式缺点
- 工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响;
- 增加系统中类的个数(引入了新的工厂类),增加了系统的复杂度和理解难度;
- 系统扩展困难,一旦添加新产品不得不修改工厂逻辑;
- 由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构,工厂类不能得到很好地扩展。
编程要求
根据提示,给“HaierTV.java,HisenseTV.java,TVFactory.java”三个代码文件内注释需要填空地方补充代码。
Product:抽象产品角色
package step1;public interface TV {void play();
}
ConcreteProduct:具体产品角色
package step1;public class HaierTV implements TV/**填空——————————**/{@Overridepublic void play() {System.out.println("海尔电视机播放中......");}
}
package step1;public class HisenseTV implements TV/**填空——————————**/{@Overridepublic void play() {System.out.println("海信电视机播放中......");}
}
Factory:工厂角色
package step1;public class TVFactory {public static TV produceTV(String brand) throws Exception{if(brand.equalsIgnoreCase("Haier")){System.out.println("电视机工厂生产海尔电视机!");/******填空******/return new HaierTV();/************/}else if(brand.equalsIgnoreCase("Hisense")){System.out.println("电视机工厂生产海信电视机!");/******填空******/return new HisenseTV();/************/}else{throw new Exception("对不起,暂不能生产该品牌电视机!");}}
}
顾客类
package step1;import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;public class XMLUtilTV {public static String getBrandName(){try{//创建文档对象DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dFactory.newDocumentBuilder();Document doc;doc = builder.parse(new File("/data/workspace/myshixun/src/SimpleFactoryconfigTV.xml"));//获取包含品牌名称的文本节点NodeList nl = doc.getElementsByTagName("brandName");Node classNode=nl.item(0).getFirstChild();String brandName=classNode.getNodeValue().trim();return brandName;}catch(Exception e){e.printStackTrace();return null;}}
}
这段代码实现了从指定的XML配置文件中获取电视品牌名称的方法。具体步骤如下:
1. 导入所需要的Java类库,包括org.w3c.dom、javax.xml.parsers和java.io.File。
2. 创建XMLUtilTV类,并定义静态的getBrandName方法,返回类型为String,用于获取配置文件中的品牌名称。
3. 在getBrandName方法中,使用DocumentBuilderFactory类和DocumentBuilder类来创建文档对象,即读取XML配置文件。
4. 获取文档对象中的品牌名称节点,通过doc.getElementsByTagName("brandName")获取节点列表,然后使用nl.item(0)获取第一个节点,再使用getFirstChild()获取节点的第一个子节点。
5. 最后通过classNode.getNodeValue().trim()获取节点的文本值,并去掉开头结尾的空格。
6. 如果有异常发生,打印堆栈信息,并返回null。
package step1;
public class Client {public static void main(String args[]){try{TV tv;String brandName= XMLUtilTV.getBrandName();tv= TVFactory.produceTV(brandName);tv.play();}catch(Exception e){System.out.println(e.getMessage());}}
}
2.2工厂方法模式
任务描述
本关任务:将原有的电视机工厂进行分割,为每种品牌的电视机提供一个子工厂,海尔工厂专门负责生产海尔电视机,海信工厂专门负责生产海信电视机,如果需要生产 TCL 电视机或创维电视机,只需要对应增加一个新的 TCL 工厂或创维工厂即可,原有的工厂无须做任何修改,使得整个系统具有更加的灵活性和可扩展性。 现使用工厂方法模式来模拟,程序将会自动从配置文件中读取参数,请根据以下类图来修补代码。
相关知识
为了完成本关任务,你需要掌握:
- 工厂方法模式包含的角色;
- 实现要点;
- 工厂方法模式缺点。
工厂方法模式包含的角色
- Product:抽象产品
- ConcreteProduct:具体产品
- Factory:抽象工厂
- ConcreteFactory:具体工厂
实现要点
- 让所有产品都遵循同一接口。 该接口必须声明对所有产品都有意义的方法。
- 在创建类中添加一个空的工厂方法。 该方法的返回类型必须遵循通用的产品接口。
- 在创建者代码中找到对于产品构造函数的所有引用。 将它们依次替换为对于工厂方法的调用, 同时将创建产品的代码移入工厂方法。你可能需要在工厂方法中添加临时参数来控制返回的产品类型。工厂方法的代码看上去可能非常糟糕。 其中可能会有复杂的 switch 分支运算符, 用于选择各种需要实例化的产品类。 但是不要担心, 我们很快就会修复这个问题。
- 为工厂方法中的每种产品编写一个创建者子类, 然后在子类中重写工厂方法, 并将基本方法中的相关创建代码移动到工厂方法中。
- 如果应用中的产品类型太多, 那么为每个产品创建子类并无太大必要, 这时你也可以在子类中复用基类中的控制参数。
- 如果代码经过上述移动后, 基础工厂方法中已经没有任何代码, 你可以将其转变为抽象类。 如果基础工厂方法中还有其他语句, 你可以将其设置为该方法的默认行为。
工厂方法模式缺点
- 系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,会给系统带来一些额外的开销;
- 增加了系统的抽象性和理解难度。
编程要求
根据提示,给“HaierTVFactory.java,HisenseTVFactory.java”两个代码文件内注释需要填空地方补充代码。
Product:抽象产品
package step3;public interface TV {void play();
}
ConcreteProduct:具体产品、
package step3;public class HaierTV implements TV{@Overridepublic void play() {System.out.println("海尔电视机播放中......");}
}
package step3;public class HisenseTV implements TV{@Overridepublic void play() {System.out.println("海信电视机播放中......");}
}
Factory:抽象工厂
package step3;public interface TVFactory {TV produceTV();
}
ConcreteFactory:具体工厂
package step3;public class HaierTVFactory implements TVFactory{@Overridepublic TV produceTV() {/*填空*/return new HaierTV();}
}
package step3;public class HisenseTVFactory implements TVFactory{@Overridepublic TV produceTV() {/*填空*/return new HisenseTV();}
}
顾客
package step3;public class Client {public static void main(String args[]){try{TV tv;TVFactory factory;factory=(TVFactory)XMLUtil.getBean();tv=factory.produceTV();tv.play();}catch(Exception e){System.out.println(e.getMessage());}}
}
package step3;import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;public class XMLUtil {public static Object getBean(){try{//创建文档对象DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = dFactory.newDocumentBuilder();Document doc;doc = builder.parse(new File("./src/FactoryMethodconfig.xml"));//获取包含类名的文本节点NodeList nl = doc.getElementsByTagName("className");Node classNode=nl.item(0).getFirstChild();String cName=classNode.getNodeValue();//通过类名生成实例对象并将其返回Class c=Class.forName(cName);Object obj=c.newInstance();return obj;}catch(Exception e){e.printStackTrace();return null;}}
}
2.3抽象工厂模式
任务描述
本关任务:一个智慧蔬菜大棚需要光照、土壤和空气传感器来搭建物联网,联网方式有 zigbee 或蓝牙 mesh 两种之一。相同联网方式的传感器构成一个产品族,而相同类型的传感器构成了一个产品等级结构,现使用抽象工厂模式模拟该场景,程序将会自动从配置文件中读取联网方式,系统能全套生成,不需要考虑兼容性问题,请根据以下类图来修补文件中的代码。
相关知识
为了完成本关任务,你需要掌握:
- 抽象工厂模式包含的角色;
- 实现方法;
- 抽象工厂模式缺点。
抽象工厂模式包含的角色
- AbstractFactory:抽象工厂
- ConcreteFactory:具体工厂
- AbstractProduct:抽象产品
- ConcreteProduct:具体产品
实现方法
- 以不同的产品类型与产品变体为维度绘制矩阵。
- 为所有产品声明抽象产品接口。 然后让所有具体产品类实现这些接口。
- 声明抽象工厂接口, 并且在接口中为所有抽象产品提供一组构建方法。
- 为每种产品变体实现一个具体工厂类。
- 在应用程序中开发初始化代码。 该代码根据应用程序配置或当前环境, 对特定具体工厂类进行初始化。 然后将该工厂对象传递给所有需要创建产品的类。
- 找出代码中所有对产品构造函数的直接调用, 将其替换为对工厂对象中相应构建方法的调用。
抽象工厂模式缺点
增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了开闭原则。
编程要求
除“Client”文件中代码不需要修改,其它文件请在右侧编辑器 Begin-End 内补充代码来设计实现。
Airsensor.java
package step2;/********** Begin *********/
public interface Airsensor {public abstract void Work();}
/********** End *********/
IOTFactory.java
package step2;/********** Begin *********/public interface IOTFactory {Airsensor produceAirsensor();Lightsensor produceLightsensor();Soilsensor produceSoilsensor();
}/********** End *********/
Lightsensor.java
package step2;/********** Begin *********/public interface Lightsensor {public abstract void Work();}/**** End *********/
MeshAir.java
package step2;/********** Begin *********/public class MeshAir implements Airsensor {public void Work(){System.out.println("mesh空气传感器正常工作中");}
}/********** End *********/
MeshFactory.java
package step2;/********** Begin *********/public class MeshFactory implements IOTFactory {public Airsensor produceAirsensor() {return new MeshAir();}public Lightsensor produceLightsensor() {return new MeshLight();}public Soilsensor produceSoilsensor() {return new MeshSoil();}
}/********** End *********/
MeshLight.java
package step2;/********** Begin *********/public class MeshLight implements Lightsensor {public void Work() {System.out.println("mesh光照传感器正常工作中");}
}/********** End *********/
MeshSoil.java
package step2;/********** Begin *********/public class MeshSoil implements Soilsensor {public void Work() {System.out.println("mesh土壤传感器正常工作中");}
}/********** End *********/
Soilsensor.java
package step2;/********** Begin *********/
public interface Soilsensor {public abstract void Work() ;
}/********** End *********/
ZigbeeAir.java
package step2;/********** Begin *********/public class ZigbeeAir implements Airsensor {public void Work() {System.out.println("zigbee空气传感器正常工作中");}
}/********** End *********/
ZigbeeFactory.java
package step2;/********** Begin *********/public class ZigbeeFactory implements IOTFactory {public Airsensor produceAirsensor() {return new ZigbeeAir();}public Lightsensor produceLightsensor() {return new ZigbeeLight();}public Soilsensor produceSoilsensor (){return new ZigbeeSoil();}
}/********** End *********/
ZigbeeLight.java
package step2;/********** Begin *********/public class ZigbeeLight implements Lightsensor {public void Work() {System.out.println("zigbee光照传感器正常工作中");}
}/********** End *********/
ZigbeeSoil.java
package step2;/********** Begin *********/public class ZigbeeSoil implements Soilsensor {public void Work() {System.out.println("zigbee土壤传感器正常工作中");}
}/********** End *********/
Client.java
package step3;public class Client {public static void main(String args[]){try{TV tv;TVFactory factory;factory=(TVFactory)XMLUtil.getBean();tv=factory.produceTV();tv.play();}catch(Exception e){System.out.println(e.getMessage());}}
}
相关文章:

万字解析设计模式之工厂方法模式与简单工厂模式
一、概述 1.1简介 在java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的…...

One-to-N N-to-One: Two Advanced Backdoor Attacks Against Deep Learning Models
One-to-N & N-to-One: Two Advanced Backdoor Attacks Against Deep Learning Models----《一对N和N对一:针对深度学习模型的两种高级后门攻击》 1对N: 通过控制同一后门的不同强度触发多个后门 N对1: 只有当所有N个后门都满足时才会触发…...

洛谷 B2009 计算 (a+b)/c 的值 C++代码
目录 题目描述 AC Code 切记 题目描述 题目网址:计算 (ab)/c 的值 - 洛谷 AC Code #include<bits/stdc.h> using namespace std; int main() {int a,b,c;cin>>a>>b>>c;cout<<(ab)/c<<endl;return 0; } 切记 不要复制题…...

Arduino驱动ME007-ULA防水测距模组(超声波传感器)
目录 1、传感器特性 2、控制器和传感器连线图 3、驱动程序 3.1、读取串口数据...

Linux 权限管理(二)
文件类型和访问权限(事物属性) linux前都会有一串这个字符,第二字符到第九字符分别表示拥有者,所属组,和other所对应的权限。那么第一个字符表示什么呢? 第一个字符表示文件类型: d:…...
线性代数 第一章 行列式
一、概念 不同行不同列元素乘积的代数和(共n!项) 二、性质 经转置行列式的值不变,即; 某行有公因数k,可把k提到行列式外。特别地,某行元素全为0,则行列式的值为0; 两行互换行列式…...

查询Oracle所有用户相关信息
$sqlplus / as sysdba 1. 查询oracle中所有用户信息 select * from dba_users; select * from all_users; select distinct owner from all_objects; 2. 只查询用户和密码 select username,password from dba_users; 3. 查询当前用户信息 select * from dba_ustats; 4…...

电路的电线的拼接
不积跬步无以至千里,今天小编也是复习今天学习的内容,废话不多说,看博客吧!!! 目录 准备条件 操作 成品 准备条件 操作 将定制的套管插入导线当中,24V或者0V是尖端的端子,后面根…...

前端学习之webpack
概述 webpack是一个流行的前端项目构建工具(打包工具),可以解决当前web开发中所面临的问题。 webpack提供了友好的模块化支持,以及代码压缩混淆、处理js兼容问题、性能优化等强大的功能,从而让程序员把工作重心放到具…...

2023NOIP A层联测20-旅行
小 A 旅行到了远方的一座城市,其内部的道路可以被视为一张包含恰好 n n n 个点以及 n n n 条边的无向连通图。这里的居民可以用一种特质的墨水来改变图中某一条边的颜色。 居民们的狂欢节即将开始了,且节日会持续 m m m 天。每一天,居民们…...

STM32 中断NVIC详解,配置及示例
NVIC全称 Nested Vectored Controller 嵌套向量中断控制器 它是一种硬件设备,用于管理和协调处理器的中断请求。NVIC可以管理多个中断请求,并按优先级处理它们。当一个中断请求到达时,NVIC会确定其优先级并决定是否应该中断当前执行的程序&am…...

10.30英语期中稿
influence of Chinese and Japanese literary culture on the country and the world, and compare the differences between the two 对自己文化影响 中日文学文化比较 表达,餐饮,服装 相似点与不同点 与日本友人交流 draft Chinese and Japanes…...

二维数组如何更快地遍历
二维数组如何更快地遍历 有时候,我们会发现,自己的代码和别人的代码几乎一模一样,但运行时间差了很多,别人是 AC \text{AC} AC,你是 TLE \text{TLE} TLE,这是为什么呢? 一个可能的原因是数组的…...

【网络安全】Seeker内网穿透追踪定位
Seeker追踪定位对方精确位置 前言一、kali安装二、seeker定位1、ngrok平台注册2、获取一次性邮箱地址3、ngrok平台登录4、ngrok下载5、ngrok令牌授权6、seeker下载7、运行seeker定位8、运行隧道开启监听9、伪装链接10、用户点击(获取定位成功)11、利用经…...

Spring Boot 3系列之一(初始化项目)
近期,JDK 21正式发布,而Spring Boot 3也推出已有一段时间。作为这两大技术领域的新一代标杆,它们带来了许多令人振奋的新功能和改进。尽管已有不少博客和文章对此进行了介绍,但对于我们这些身处一线的开发人员来说,有些…...

用python判断一个数是否为素数
判断一个数是否为素数可以使用以下方法: 排除特殊情况:首先判断该数是否小于等于1,因为素数定义中,素数必须大于1。如果小于等于1,则该数不是素数。 除尽法(试除法):从2开始&#x…...

FreeRTOS_信号量之二值信号量
目录 1. 信号量简介 2. 二值信号量 2.1 二值信号量简介 2.1.1 二值信号量无效 2.1.2 中断释放信号量 2.1.3 任务获取信号量成功 2.1.4 任务再次进入阻塞态 2.2 创建二值信号量 2.2.1 vSemaphoreCreateBinary() 2.2.2 xSemaphoreCreateBinary() 2.2.3 xSemaphoreCrea…...

使用Gateway解决跨域问题时配置文件不生效的情况之一
首先html文件只有一个发送ajax请求 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content&q…...

【火影手游】新版押镖护送高分攻略
文章目录 Part.I IntroductionPart.II 迪达拉视角1、打栅栏2、石头边,打石头和栅栏3、石头边,踩封印,撞力士4、大树前,打石头和栅栏5、石头边,给佩恩当路标6、后一前二接大招7、补伤害 Part.III 佩恩视角1、头进洞&…...

【JVM】类的声明周期(加载、连接、初始化)
🐌个人主页: 🐌 叶落闲庭 💨我的专栏:💨 c语言 数据结构 javaEE 操作系统 Redis 石可破也,而不可夺坚;丹可磨也,而不可夺赤。 JVM 一、类的声明周期(加载阶段…...

开源3D激光(视觉)SLAM算法汇总(持续更新)
原文连接 目录 一、Cartographer 二、hdl_graph_slam 三、LOAM 四、LeGO-LOAM 五、LIO-SAM 六、S-LOAM 七、M-LOAM 八、livox-loam 九、Livox-Mapping 十、LIO-Livox 十一、FAST-LIO2 十二、LVI-SAM 十三、FAST-Livo 十四、R3LIVE 十五、ImMesh 十六、Point-LIO 一、Cartograph…...

绕WAF手法总结
云锁 被拦截 http://www.test123.com/article.php?id1%20union%20select%201,2,3 绕过 http://www.test123.com/article.php?id-1/*!36000union*//*!36000distinct*//*!36000select*/1,2,user() 360websec 被拦截 http://www.xxx.com.cn/productshow.php?id79 绕过 http:/…...

Linux mv命令:移动文件或改名
mv 命令(move 的缩写),既可以在不同的目录之间移动文件或目录,也可以对文件和目录进行重命名。该命令的基本格式如下: [rootlocalhost ~]# mv 【选项】 源文件 目标文件 -f:强制覆盖,如果目标文…...

在 Elasticsearch 中丰富你的 Elasticsearch 文档
作者:David Pilato 对于 Elasticsearch,我们知道联接应该在 “索引时” 而不是查询时完成。 本博文是一系列三篇博文的开始,因为我们可以在 Elastic 生态系统中采取多种方法。 我们将介绍如何在 Elasticsearch 中做到这一点。 下一篇博文将介…...

探营云栖大会:蚂蚁集团展出数字人全栈技术,三大AI“机器人”引关注
一年一度的科技盛会云栖大会将于10月31日正式开幕。30日,记者来到云栖大会展区探营,提前打卡今年上新的“黑科技”。 记者在蚂蚁集团展馆看到,超1亿人参与的亚运“数字火炬手”全栈技术首次公开展示,还可体验基于数字人技术的“数…...

hdlbits系列verilog解答(8位宽移位寄存器)-24
文章目录 一、问题描述二、verilog源码三、仿真结果一、问题描述 这项练习是module_shift移位寄存器的延伸。模块端口不是只有单个引脚,我们现在有以向量作为端口的模块,您将在其上附加线向量而不是普通线网数据。与 Verilog 中的其他位置一样,端口的向量长度不必与连接到它…...

LeetCode 275. H 指数 II
原题链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 题目描述 给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数,citations 已经按照 升序排列 。计算并返回该研究者的 h…...

Android 优质的UI组件汇总
1、RuleView :Android自定义标尺控件(选择身高、体重等) 链接:https://github.com/cStor-cDeep/RuleView 2、DashboardView :Android自定义仪表盘View,仿新旧两版芝麻信用分、炫酷汽车速度仪表盘 链接:https://git…...

halcon roberts、 prewitt_amp、 sobel_amp、 edges_image、 laplace_of_gauss 对比
原图 灰度: roberts 算子: prewitt算子 sobel 算子 canny算子 拉普拉斯 代码: read_image (Image, C:/Users/alber/Desktop/opencv_images/canny.png) rgb1_to_gray (Image, GrayImage)* 测试 roberts 算子 roberts (GrayImage, ImageRoberts…...

Vue2 跨域问题报错AxiosError net::ERR_FAILED、 Network Error、ERR_NETWORK
请求场景: 当前页面URL:http://127.0.0.1:8000/testcase 跳转请求页面URL:http://127.0.0.1:5000/testcase_orm 使用axios请求 时 页面提示跨域报错 跨域报错信息 > Access to XMLHttpRequest at http://127.0.0.1:5000/testcase_orm fr…...