万字解析设计模式之工厂方法模式与简单工厂模式

一、概述

1.1简介

在java中,万物皆对象,这些对象都需要创建,如果创建的时候直接new该对象,就会对该对象耦合严重,假如我们要更换对象,所有new对象的地方都需要修改一遍,这显然违背了软件设计的开闭原则。如果我们使用工厂来生产对象,我们就只和工厂打交道就可以了,彻底和对象解耦,如果要更换对象,直接在工厂里更换该对象即可,达到了与对象解耦的目的;所以说,工厂模式最大的优点就是:解耦

在本教程中会介绍三种工厂的使用

  • 简单工厂模式(不属于GOF的23种经典设计模式)
  • 工厂方法模式
  • 抽象工厂模式

 1.2简单工厂模式

概述

简单工厂不是一种设计模式,反而比较像是一种编程习惯。

简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,它提供了一个工厂类,该类专门用于创建其他对象。简单工厂模式属于静态工厂模式,即在工厂类中提供静态方法,根据传入的参数不同返回不同的对象实例。

结构

简单工厂模式包含三个角色:

  1. 工厂类(Creator):提供了创建产品的方法,调用者通过该方法来获取产品。
  2. 抽象产品类(Product):定义了产品的规范,描述了产品的主要特性和功能。
  3. 具体产品类(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. 数据库连接池的实现。

  2. 日志处理器的实现。

  3. 图形界面控件库的开发。

  4. 任何需要创建对象的场景,特别是对象创建过程复杂或需要隐藏细节的场景。

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”,工厂可以根据传入的不同参数返回不同品牌的电视机。现使用简单工厂模式来模拟,程序将会自动从配置文件中读取参数,请根据以下类图来补全代码。

,

相关知识

为了完成本关任务,你需要掌握:

  1. 简单工厂模式包含的角色;
  2. 简单工厂模式缺点。
简单工厂模式包含的角色
  • Factory:工厂角色
  • Product:抽象产品角色
  • ConcreteProduct:具体产品角色
简单工厂模式缺点
  1. 工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响;
  2. 增加系统中类的个数(引入了新的工厂类),增加了系统的复杂度和理解难度;
  3. 系统扩展困难,一旦添加新产品不得不修改工厂逻辑;
  4. 由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构,工厂类不能得到很好地扩展。

编程要求

根据提示,给“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 工厂或创维工厂即可,原有的工厂无须做任何修改,使得整个系统具有更加的灵活性和可扩展性。 现使用工厂方法模式来模拟,程序将会自动从配置文件中读取参数,请根据以下类图来修补代码。

,

相关知识

为了完成本关任务,你需要掌握:

  1. 工厂方法模式包含的角色;
  2. 实现要点;
  3. 工厂方法模式缺点。
工厂方法模式包含的角色
  • Product:抽象产品
  • ConcreteProduct:具体产品
  • Factory:抽象工厂
  • ConcreteFactory:具体工厂
实现要点
  1. 让所有产品都遵循同一接口。 该接口必须声明对所有产品都有意义的方法。
  2. 在创建类中添加一个空的工厂方法。 该方法的返回类型必须遵循通用的产品接口。
  3. 在创建者代码中找到对于产品构造函数的所有引用。 将它们依次替换为对于工厂方法的调用, 同时将创建产品的代码移入工厂方法。你可能需要在工厂方法中添加临时参数来控制返回的产品类型。工厂方法的代码看上去可能非常糟糕。 其中可能会有复杂的 switch 分支运算符, 用于选择各种需要实例化的产品类。 但是不要担心, 我们很快就会修复这个问题。
  4. 为工厂方法中的每种产品编写一个创建者子类, 然后在子类中重写工厂方法, 并将基本方法中的相关创建代码移动到工厂方法中。
  5. 如果应用中的产品类型太多, 那么为每个产品创建子类并无太大必要, 这时你也可以在子类中复用基类中的控制参数。
  6. 如果代码经过上述移动后, 基础工厂方法中已经没有任何代码, 你可以将其转变为抽象类。 如果基础工厂方法中还有其他语句, 你可以将其设置为该方法的默认行为。
工厂方法模式缺点
  • 系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,会给系统带来一些额外的开销;
  • 增加了系统的抽象性和理解难度。

编程要求

根据提示,给“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 两种之一。相同联网方式的传感器构成一个产品族,而相同类型的传感器构成了一个产品等级结构,现使用抽象工厂模式模拟该场景,程序将会自动从配置文件中读取联网方式,系统能全套生成,不需要考虑兼容性问题,请根据以下类图来修补文件中的代码。

,

相关知识

为了完成本关任务,你需要掌握:

  1. 抽象工厂模式包含的角色;
  2. 实现方法;
  3. 抽象工厂模式缺点。
抽象工厂模式包含的角色
  • AbstractFactory:抽象工厂
  • ConcreteFactory:具体工厂
  • AbstractProduct:抽象产品
  • ConcreteProduct:具体产品
实现方法
  1. 以不同的产品类型与产品变体为维度绘制矩阵。
  2. 为所有产品声明抽象产品接口。 然后让所有具体产品类实现这些接口。
  3. 声明抽象工厂接口, 并且在接口中为所有抽象产品提供一组构建方法。
  4. 为每种产品变体实现一个具体工厂类。
  5. 在应用程序中开发初始化代码。 该代码根据应用程序配置或当前环境, 对特定具体工厂类进行初始化。 然后将该工厂对象传递给所有需要创建产品的类。
  6. 找出代码中所有对产品构造函数的直接调用, 将其替换为对工厂对象中相应构建方法的调用。
抽象工厂模式缺点

增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了开闭原则。

编程要求

除“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());}}
}

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

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

相关文章

同步盘简介及功能解析:了解同步盘是什么及其实用性

数字化时代&#xff0c;办公中用户对于文件协同的需求越来越高。同步盘无疑是近几年最热门的文件协同工具。什么是同步盘&#xff1f;同步盘有什么用&#xff1f; 什么是同步盘&#xff1f; 同步盘是一种可以将文件存储至云端&#xff0c;然后同步至用户的各个设备的文件存储协…

MySQL创建数据库和创建数据表

二、创建数据库 1. 连接 MySQL 输入 mysql -u root -p 命令&#xff0c;回车&#xff0c;然后输入 MySQL 的密码(不要忘记了密码)&#xff0c;再回车&#xff0c;就连接上 MySQL 了。 mysql -u root -p 最初&#xff0c;都是使用 root 用户登录&#xff0c;工作中如果一直用…

【spring boot】

作用 极大地简化了spring的搭建和开发 开发方法 idea开发springboot 必须联网 结构 parent&#xff1a;装多次使用的依赖&#xff0c;还能管理版本 starter&#xff1a;SpringBoot中常见项目名称&#xff0c;定义了当前项目使用的所有依赖坐标&#xff0c;以达到减少依赖…

Azure - 机器学习:使用 Apache Spark 进行交互式数据整理

目录 本文内容先决条件使用 Apache Spark 进行交互式数据整理Azure 机器学习笔记本中的无服务器 Spark 计算从 Azure Data Lake Storage (ADLS) Gen 2 导入和整理数据从 Azure Blob 存储导入和处理数据从 Azure 机器学习数据存储导入和整理数据 关注TechLead&#xff0c;分享AI…

数据结构与算法-(7)---栈的应用拓展-前缀表达式转换+求值

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

带IV的分组加密下密文分散存储且存在混淆密文片段的多项式时间解密方案

在使用带IV的分组加密模式下&#xff0c;考虑这样一个场景&#xff1a;分组加密后&#xff0c;每组密文都被分散保存&#xff0c;且在恢复的时候&#xff0c;每组密文会和n个混淆的密文一起提供&#xff0c;此时&#xff0c;若想完整的恢复明文&#xff0c;需要一个多项式时间的…

UDP 协议

UDP协议特点&#xff1a; 无连接&#xff1a;只需要知道对方的IP和端口就可以向对方发送数据。 不可靠&#xff1a;没有确认应答机制&#xff0c;没有重传机制。 面向数据报&#xff1a;每调用一次sendto() &#xff0c;就直接将这些数据交给网络层了&#xff0c;不能控制数据读…

双十一限时优惠!沃通SSL证书、代码签名证书年度好价

2023年11月01日至11月11日&#xff0c;沃通2023“双十一限时特惠”活动&#xff0c;精选9款SSL证书、国密SSL证书、代码签名证书产品推出年度好价&#xff0c;部分SSL证书产品低至5折&#xff0c;更有EV代码签名证书爆款特惠&#xff01;多种数字证书一站式采购&#xff0c;解决…

改进YOLOv3!IA-YOLO:恶劣天气下的目标检测

恶劣天气条件下从低质量图像中定位目标还是极具挑战性的任务。现有的方法要么难以平衡图像增强和目标检测任务&#xff0c;要么往往忽略有利于检测的潜在信息。本文提出了一种新的图像自适应YOLO (IA-YOLO)框架&#xff0c;可以对每张图像进行自适应增强&#xff0c;以提高检测…

电源控制系统架构(PCSA)之电源管理软件

下图显示了电源管理软件栈的简化表示。该图说明了OS电源管理框架、具有直接从SCP请求操作功能的组件以及它们与SCP固件之间的关系。 一个重要的方面是&#xff0c;所有硬件电源管理操作都是由SCP代表这些请求者执行的。 这种OS电源管理(OSPM)的简化表示可以分为两部分&#xff…

MySQL -- 表的增删查改

MySQL – 表的增删查改 文章目录 MySQL -- 表的增删查改一、Create创建1.插入数据2.插入否则更新3.替换 二、Retrieve查找1.select列1.1.全列查询1.2.指定列查询1.3.查询字段为表达式1.4.为查询结果指定别名1.5.结果去重 2.where条件2.1.英语不及格的同学&#xff08;英语<6…

数字孪生三剑客!云渲染及虚拟仿真服务器产品MapGIS Server for Unreal来了

10月18日&#xff0c;新一代全空间智能GIS平台的升级之作——MapGIS 10.6 Pro在深圳正式发布&#xff0c;整场发布会全空间GIS、智能GIS、信创GIS、全栈开发各维度创新一一揭晓&#xff0c;全空间一体化、深度融合云端的全系产品全面升级&#xff0c;科技盛宴、高潮迭起。其中尤…

STM智能小车——OLED实现测速小车

目录 1. 测速模块 2. 测试原理和单位换算 3. 定时器和中断实现测速开发和调试代码 4. 小车速度显示在OLED屏 1. 测速模块 用途&#xff1a;广泛用于电机转速检测&#xff0c;脉冲计数,位置限位等。有遮挡&#xff0c;输出高电平&#xff1b;无遮挡&#xff0c;输出低电平接线…

Ubuntu20.04操作系统安装及重中之重:系统分区

最近因为学习原因&#xff0c;需要将电脑设置为双系统&#xff0c;在windows10的系统下去安装Ubuntu操作系统。本来看网上相关的安装教程蛮多的&#xff0c;以为比较简单&#xff0c;结果一路过五关斩六将&#xff0c;坑的七零八落的&#xff0c;折腾了好久&#xff0c;才算安装…

知识图谱实战应用30-知识图谱在反欺诈情报分析项目中的应用实践

大家好,我是微学AI,今天给大家介绍一下知识图谱实战应用30-知识图谱在反欺诈情报分析项目中的应用实践,现代商业环境中,各类欺诈行为日益猖獗,严重影响企业的运营和社会秩序。传统的欺诈检测方法难以满足实时性和有效性方面的要求。本文介绍了采用知识图谱技术构建反欺诈情报…

Go学习第十五章——Gin参数绑定bind与验证器

Go web框架——Gin&#xff08;参数绑定bind与验证器&#xff09; 1 bind参数绑定1.1 JSON参数1.2 Query参数1.3 Uri绑定动态参数1.4 ShouldBind自动绑定 2 验证器2.1 常用验证器2.2 gin内置验证器2.3 自定义验证的错误信息2.4 自定义验证器 1 bind参数绑定 在Gin框架中&#…

x3daudio1 7.dll丢失怎么修复?多种x3daudio1 7.dll修复方法对比

x3daudio1_7.dll是Windows操作系统中的一个动态链接库文件&#xff0c;它主要负责处理音频相关的功能。当这个文件缺失或损坏时&#xff0c;可能会导致一些音频播放问题&#xff0c;如无声、杂音等。那么&#xff0c;x3daudio1_7.dll缺失的原因是什么呢&#xff1f;又该如何修复…

chorme安装esay scholar及chrome 无法从该网站添加应用、扩展程序和用户脚本解决方案

问题描述 如题&#xff0c;博主想安装easy scholar用于查询论文的分区&#xff0c;结果安装了半天一直出现chrome 无法从该网站添加应用、扩展程序和用户脚本解决方案的问题。 解决方案 先从这个网址下载&#xff1a;https://www.easyscholar.cc/download 然后对下载好的文…

处理固定资产折旧报错 AFAB “根据记帐循环, 您必须接下来对期间 001记帐”

会计在运用进行固定资产折旧时&#xff0c;发现有个报错“根据记帐循环, 您必须接下来对期间 001记帐”&#xff0c; 根据记帐循环, 您必须接下来对期间 001记帐 消息编号 AA683 诊断 不可以在指定的期间过帐折旧&#xff0c;因为此操作会遗漏过帐期间。 系统响应 该期间不能进…

损坏的视频不能观看,还能修复吗?

3-1 在日常的生活或者工作中&#xff0c;特别是做摄像工作的人&#xff0c;有一定的概率会遇到损坏的视频文件&#xff0c;比如相机突然断电、无人机炸机等&#xff0c;都有可能导致保存的视频文件损坏。 如果遇到这种情况&#xff0c;该如何修复这种损坏的视频文件&#xff…