工厂模式相关简单论述
作者:互联网
工厂模式相关简单论述
1.工厂模式简介
工厂模式用于对象的创建,使得客户从具体的产品对象中被解耦。
2.工厂模式的定义
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。 这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
3.工厂模式使用实例
我们现在先假设一个简单的需求:计算器
我们的第一版代码如下
import java.util.Scanner;
public class jisuanqi {
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(System.in);
System.out.println("the value of a");
double a = scanner.nextInt();
System.out.println("the value of b");
double b = scanner.nextInt();
System.out.println("+,-,*,/");
String value = scanner.next();
if ("+".equalsIgnoreCase(value)) {
System.out.println(a + b);
} else if ("-".equalsIgnoreCase(value)) {
System.out.println(a - b);
} else if ("*".equalsIgnoreCase(value)) {
System.out.println(a * b);
} else if ("/".equalsIgnoreCase(value) && b != 0 && a != 0) {
System.out.println(a / b);
} else {
System.out.println("error");
}
} catch (Exception e) {
System.out.println("error value");
}
}
}
我们上述代码中有两个初学者常见的代码习惯:
-
命名规范问题
-
大量的if代码
ok,那么我们对上述代码进行修改
我们的第二版代码如下
import java.util.Scanner;
public class jisuanqi {
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(System.in);
System.out.println("the OperateVlaue of a");
double FirstOperateVlaue = scanner.nextInt();
System.out.println("the OperateVlaue of b");
double SecondOperateVlaue = scanner.nextInt();
System.out.println("+,-,*,/");
String operateValue = scanner.next();
switch (operateValue){
case "+":{
System.out.println(FirstOperateVlaue+SecondOperateVlaue);
break;
}
case "-":{
System.out.println(FirstOperateVlaue - SecondOperateVlaue);
break;
}
case "*":{
System.out.println(FirstOperateVlaue * SecondOperateVlaue);
break;
}
case "/":{
if (FirstOperateVlaue != 0 && SecondOperateVlaue!=0) {
System.out.println(FirstOperateVlaue / SecondOperateVlaue);
break;
}
}
default:{
System.out.println("error");
break;
}
}
} catch (Exception e) {
System.out.println("error OperateVlaue");
e.printStackTrace();
}
}
}
但是现在又有一个问题:
- 这么多代码是不是显得很臃肿呢,我们维护和读代码时候也不好,我们应该怎么做呢
面向对象的方法解决问题便可以解决这个问题
我们的第三版的代码如下
public class ExampleMine {
public static final String Exception_FirstFailure = "error value";
}
public class OperateValue {
public static final String ADD_VALUE="+";
public static final String REDUCE_VALUE="-";
public static final String MULTIPLICATION_VALUE="*";
public static final String DIVISION_VALUE="/";
}
import java.util.Scanimport java.util.Scanner;
public class JiServlet {
private double FirstOperateVlaue;
private double SecondOperateVlaue;
public double getFirstOperateVlaue() {
return FirstOperateVlaue;
}
public void setFirstOperateVlaue(double firstOperateValue){
FirstOperateVlaue = firstOperateValue;
}
public double getSecondOperateVlaue() {
return SecondOperateVlaue;
}
public void setSecondOperateVlaue(double secondOperateValue){
SecondOperateVlaue = secondOperateValue;
}
public void GetNumbers() throws Exception {
switch (operateValue){
case OperateValue.ADD_VALUE:{
System.out.println(getFirstOperateVlaue()+getSecondOperateVlaue());
break;
}
case OperateValue.REDUCE_VALUE:{
System.out.println(getFirstOperateVlaue() - getSecondOperateVlaue());
break;
}
case OperateValue.MULTIPLICATION_VALUE:{
System.out.println(getFirstOperateVlaue() * getSecondOperateVlaue());
break;
}
case OperateValue.DIVISION_VALUE:{
if (this.getFirstOperateVlaue() != 0 && this.getSecondOperateVlaue()!=0) {
System.out.println(FirstOperateVlaue / SecondOperateVlaue);
break;
}
}
default:{
System.out.println(ExampleMine.Exception_FirstFailure);
break;
}
}
}
}
import java.util.Scanner;
public class jisuanqi {
public static void main(String[] args) {
JiServlet jiServlet = new JiServlet();
Scanner scanner= new Scanner(System.in);
try {
System.out.println("the FirstOperateVlaue of a");
jiServlet.setFirstOperateVlaue(scanner.nextInt());
System.out.println("the SecondOperateVlaue of b");
jiServlet.setSecondOperateVlaue(scanner.nextInt());
System.out.println("+,-,*,/");
jiServlet.setOperateValue(scanner.next());
jiServlet.GetNumbers();
} catch (Exception e) {
e.printStackTrace();
}
}
}
我们的第三版代码仍然存在问题:
- 我们是否感觉 switch 语句太臃肿了呢,我们可不可以将他们拆成四个类呢
我们的第四版代码如下:
这里使用的是工厂模式,一个最简单的工厂模式,我们发现这与我们的多态的写法是不尽相同的在这里
public class ExampleMine {
public static final String Exception_FirstFailure = "error value";
}
package Base;
import java.util.Scanner;
public abstract class JiServlet {
private double FirstOperateVlaue;
private double SecondOperateVlaue;
public double getFirstOperateVlaue() {
return FirstOperateVlaue;
}
public void setFirstOperateVlaue(double firstOperateValue){
FirstOperateVlaue = firstOperateValue;
}
public double getSecondOperateVlaue() {
return SecondOperateVlaue;
}
public void setSecondOperateVlaue(double secondOperateValue){
SecondOperateVlaue = secondOperateValue;
}
public double GetNumber() throws Exception{
return 0.00;
}
}
package Base;
import tools.GETSMultiplicationValue;
import tools.GetAddValue;
import tools.GetDivisionValue;
import tools.GetReduceValue;
public class OperateCation {
public JiServlet GetOperateCation(String operation) throws Exception {
switch (operation){
case OperateValue.ADD_VALUE:{
return new GetAddValue();
}
case OperateValue.REDUCE_VALUE:{
return new GetReduceValue();
}
case OperateValue.MULTIPLICATION_VALUE:{
return new GETSMultiplicationValue();
}
case OperateValue.DIVISION_VALUE:{
return new GetDivisionValue();
}
default:{
throw new Exception(ExampleMine.Exception_FirstFailure);
}
}
}
}
package Base;
public class OperateValue {
public static final String ADD_VALUE="+";
public static final String REDUCE_VALUE="-";
public static final String MULTIPLICATION_VALUE="*";
public static final String DIVISION_VALUE="/";
}
package tools;
import Base.JiServlet;
public class GetAddValue extends JiServlet {
@Override
public double GetNumber() {
return this.getFirstOperateVlaue()+this.getSecondOperateVlaue();
}
}
package tools;
import Base.ExampleMine;
import Base.JiServlet;
public class GetDivisionValue extends JiServlet {
@Override
public double GetNumber() throws Exception {
if (this.getFirstOperateVlaue()!= 0 && this.getSecondOperateVlaue()!=0) {
return this.getFirstOperateVlaue()/this.getSecondOperateVlaue();
}else{
throw new Exception(ExampleMine.Exception_FirstFailure);
}
}
}
package tools;
import Base.JiServlet;
public class GetReduceValue extends JiServlet {
@Override
public double GetNumber() {
return this.getFirstOperateVlaue()-this.getSecondOperateVlaue();
}
}
package tools;
import Base.JiServlet;
public class GETSMultiplicationValue extends JiServlet {
@Override
public double GetNumber() {
return this.getFirstOperateVlaue()*this.getSecondOperateVlaue();
}
}
import Base.JiServlet;
import Base.OperateCation;
public class issuance {
public static void main(String[] args) throws Exception {
OperateCation operateCation = new OperateCation();
JiServlet jiServlet = operateCation.GetOperateCation("+");
jiServlet.setFirstOperateVlaue(12.0);
jiServlet.setSecondOperateVlaue(19.0);
System.out.println(jiServlet.GetNumber());
}
}
UML图如下
注意
简单工厂实际不能算作一种设计模式,它引入了创建者的概念,将实例化的代码从应用代码中抽离,在创建者类的静态方法中只处理创建对象的细节,后续创建的实例如需改变,只需改造创建者类即可,
但由于使用静态方法来获取对象,使其不能在运行期间通过不同方式去动态改变创建行为,因此存在一定局限性。
4.工厂方法模式
定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到了子类。
场景延伸:不同地区咖啡工厂受制于环境、原料等因素的影响,制造出的咖啡种类有限。中国咖啡工厂仅能制造卡布奇诺、拿铁,而美国咖啡工厂仅能制造美式咖啡、拿铁。
/** * 定义一个抽象的咖啡工厂 * @author Lsj
*/
public abstract class CoffeeFactory {
/** * 生产可制造的咖啡 * @return
*/
public abstract Coffee[] createCoffee();
}
/** * 中国咖啡工厂 * @author Lsj
* */
public class ChinaCoffeeFactory extends CoffeeFactory {
@Override
public Coffee[] createCoffee() {
// TODO Auto-generated method stub
return new Coffee[]{new Cappuccino(), new Latte()};
}
}
/** * 美国咖啡工厂 * @author Lsj
* */
public class AmericaCoffeeFactory extends CoffeeFactory {
@Override
public Coffee[] createCoffee() {
// TODO Auto-generated method stub
return new Coffee[]{new Americano(), new Latte()};
}
}
/** * 工厂方法测试 * @author Lsj
* */
public class FactoryMethodTest {
static void print(Coffee[] c){
for (Coffee coffee : c) {
System.out.println(coffee.getName());
}
}
public static void main(String[] args) {
CoffeeFactory chinaCoffeeFactory = new ChinaCoffeeFactory();
Coffee[] chinaCoffees = chinaCoffeeFactory.createCoffee();
System.out.println("中国咖啡工厂可以生产的咖啡有:");
print(chinaCoffees);
CoffeeFactory americaCoffeeFactory = new AmericaCoffeeFactory();
Coffee[] americaCoffees = americaCoffeeFactory.createCoffee();
System.out.println("美国咖啡工厂可以生产的咖啡有:");
print(americaCoffees);
}
}
5. 抽象工厂
提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。
在上述的场景上继续延伸:咖啡工厂做大做强,引入了新的饮品种类:茶、 碳酸饮料。中国工厂只能制造咖啡和茶,美国工厂只能制造咖啡和碳酸饮料。
如果用上述工厂方法方式,除去对应的产品实体类还需要新增2个抽象工厂(茶制造工厂、碳酸饮料制造工厂),4个具体工厂实现。随着产品的增多,会导致类爆炸。
所以这里引出一个概念产品家族,在此例子中,不同的饮品就组成我们的饮品家族, 饮品家族开始承担创建者的责任,负责制造不同的产品。
/**
* 抽象的饮料产品家族制造工厂
* @author Lsj
*
*/
public interface AbstractDrinksFactory {
/**
* 制造咖啡
* @return
*/
Coffee createCoffee();
/**
* 制造茶
* @return
*/
Tea createTea();
/**
* 制造碳酸饮料
* @return
*/
Sodas createSodas();
}
/**
* 中国饮品工厂
* 制造咖啡与茶
* @author Lsj
*
*/
public class ChinaDrinksFactory implements AbstractDrinksFactory {
@Override
public Coffee createCoffee() {
// TODO Auto-generated method stub
return new Latte();
}
@Override
public Tea createTea() {
// TODO Auto-generated method stub
return new MilkTea();
}
@Override
public Sodas createSodas() {
// TODO Auto-generated method stub
return null;
}
}
/**
* 美国饮品制造工厂
* 制造咖啡和碳酸饮料
* @author Lsj
*
*/
public class AmericaDrinksFactory implements AbstractDrinksFactory {
@Override
public Coffee createCoffee() {
// TODO Auto-generated method stub
return new Latte();
}
@Override
public Tea createTea() {
// TODO Auto-generated method stub
return null;
}
@Override
public Sodas createSodas() {
// TODO Auto-generated method stub
return new CocaCola();
}
}
/**
* 抽象工厂测试类
* @author Lsj
*
*/
public class AbstractFactoryTest {
static void print(Drink drink){
if(drink == null){
System.out.println("产品:--" );
}else{
System.out.println("产品:" + drink.getName());
}
}
public static void main(String[] args) {
AbstractDrinksFactory chinaDrinksFactory = new ChinaDrinksFactory();
Coffee coffee = chinaDrinksFactory.createCoffee();
Tea tea = chinaDrinksFactory.createTea();
Sodas sodas = chinaDrinksFactory.createSodas();
System.out.println("中国饮品工厂有如下产品:");
print(coffee);
print(tea);
print(sodas);
AbstractDrinksFactory americaDrinksFactory = new AmericaDrinksFactory();
coffee = americaDrinksFactory.createCoffee();
tea = americaDrinksFactory.createTea();
sodas = americaDrinksFactory.createSodas();
System.out.println("美国饮品工厂有如下产品:");
print(coffee);
print(tea);
print(sodas);
}
}
6.总结
-
简单工厂:不能算是真正意义上的设计模式,但可以将客户程序从具体类解耦。
-
工厂方法:使用继承,把对象的创建委托给子类,由子类来实现创建方法,可以看作是抽象工厂模式中只有单一产品的情况。
-
抽象工厂:使对象的创建被实现在工厂接口所暴露出来的方法中。
-
工厂模式可以帮助我们针对抽象/接口编程,而不是针对具体类编程,在不同的场景下按具体情况来使用。
7.扩展问题
如果我们的
if
语句有很多呢,我们应该怎么去做呢
我们会在下篇文档中进行论述我们的策略模式
8.相关链接
对于继承和封装基础内容有不解内容的同学请参考以下文档
参考书籍
-
《HeadFirst 设计模式》
-
《大话设计模式》
序从具体类解耦。 -
工厂方法:使用继承,把对象的创建委托给子类,由子类来实现创建方法,可以看作是抽象工厂模式中只有单一产品的情况。
-
抽象工厂:使对象的创建被实现在工厂接口所暴露出来的方法中。
-
工厂模式可以帮助我们针对抽象/接口编程,而不是针对具体类编程,在不同的场景下按具体情况来使用。
7.扩展问题
如果我们的
if
语句有很多呢,我们应该怎么去做呢
我们会在下篇文档中进行论述我们的策略模式
8.相关链接
对于继承和封装基础内容有不解内容的同学请参考以下文档
参考书籍
-
《HeadFirst 设计模式》
-
《大话设计模式》
标签:System,模式,工厂,println,new,论述,public,out 来源: https://blog.csdn.net/qq_45205390/article/details/122847875