设计模式——简单工厂模式
  Op9yysgqYUmV 2023年11月12日 25 0


概述


简单工厂模式(Simple Factory Pattern)是通过专门定义一个工厂类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。它可以根据参数的不同返回不同类的实例,而无须知道其创建细节。如果在简单工厂模式中用于创建实例的方法是静态(static)方法,则被称为静态工厂方法(Static Factory Method)模式,它不属于23种设计模式,但在软件开发中应用也较为频繁,通常将它作为学习其他工厂模式的入门。其实工厂模式分为了最弱的简单工厂模式,工厂方法模式,牛逼的抽象工厂模式。


简单工厂模式结构中包括三种角色:


  • 工厂类(Factory):它是简单工厂模式的核心,负责实现创建所有产品实例的内部逻辑;工厂类可以被外界直接调用,创建所需的产品对象;在工厂类中提供了静态的工厂方法,返回类型为抽象产品类型。
  • 抽象产品(Product):工厂类所创建的所有对象的父类,封装了各种产品对象的公有方法,它的引入将提高系统的灵活性,使得在工厂类中只需定义一个通用的工厂方法,因为所有创建的具体产品对象都是其子类对象。
  • 具体产品(ConcreteProduct):简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。每一个具体产品角色都继承了抽象产品角色,需要实现在抽象产品中声明的抽象方法。

实例应用


从我的一次面试经历说起,犹记得当年刚毕业时怀揣着要用代码拯救世界的梦想,结果现实是无情的,一次次求职碰壁,才发现自己图样图森破,唉,“满纸荒唐言,一把辛酸泪”,就把我的经历分享给初出茅庐的学弟们以做警戒吧,面试官给我出了个题目,要求利用一种面向对象的语言实现一个简单的计算器程序,我心想这不很简单吗,马上就把代码写出来,如下:


Scanner scanner=new Scanner(System.in);

System.out.println("请输入第一个数");
double numA=scanner.nextDouble();
System.out.println("请输入第二个数");
double numB=scanner.nextDouble();
System.out.println("请输入运算符");
String operate=scanner.next();

double result=0;
switch (operate){
    case "+":
        result=numA+numB;
        break;
    case "-":
        result=numA-numB;
        break;
    case "*":
        result=numA*numB;
        break;
    case "/":
        result=numA/numB;
        break;
}
System.out.println("最后结果为:"+result);


哈哈,自我感觉良好啊,然后面试官看了看,让我回去等消息,然后就没有然后了。。。多年后我才发现,当时是多么幼稚,看一下代码,先不说具体的异常处理问题,先说题目的要求——用一种面向对象的语言!我这写的完全是面向过程的代码。。。唉,都怨C语言学的太好了,呃~


很多面向对象编程的初学者都会有这样的问题,那就是遇到问题就直觉的用计算机的方式去思考,这样的思维虽然可以解决问题,但却使得我们的程序只满足当前的需求,程序不容易维护,不容易扩展,更不容易复用。既然认识到问题了,那我们就亡羊补牢吧,下面是我的修改版:


public double getResult(double numberA, double numberB, char operate) {
    double result = 0d;
    switch (operate) {
        case '+':
            result = numberA + numberB;
            break;
        case '-':
            result = numberA - numberB;
            break;
        case '*':
            result = numberA * numberB;
            break;
        case '/':
            result = numberA / numberB;
            break;
        default:
            break;
    }
    return result;
}


代码功能都实现了,我将业务逻辑封装到了一个方法里,使用时直接调用即可,乍一看问题不大,仔细分析,发现还是有很多问题的


紧耦合vs松耦合


面向对象的三大特性:继承、多态、封装。我只用到了一个,倘若我现在要添加取余运算,怎么做?直接修改方法吗?如果一不小心把加号改成减号,那就惨了,这样的危险我们应该避免,所以最好的办法是把所有运算都分离出去,让他们之间相互不受影响,分析一下我们的代码,其实每种运算都涉及要运算的数和运算符,我们把他抽象出来,将共有特性进行抽象,这其实是为了更好的封装。


Operation运算类


public abstract class Operation {
    public double numberA;
    public double numberB;
    public abstract double getResult();
}

加减乘除类

public class OperationAdd extends Operation {
    public double getResult() {
        double result = 0d;
        result = numberA + numberB;
        return result;
    }
}
public class OperationSub extends Operation {
    public double getResult() {
        double result = 0d;
        result = numberA - numberB;
        return result;
    }
}


剩下的几个运算类代码类似,就不写了

简单工厂类


public class OperationFactory {

    public static Operation createOperate(char operate) {
        Operation oper = null;
        switch (operate) {
            case '+':
                oper = new OperationAdd();
                break;
            case '-':
                oper = new OperationSub();
                break;
            case '*':
                oper = new OperationMul();
                break;
            case '/':
                oper = new OperationDiv();
                break;

            default:
                break;
        }
        return oper;
    }
}


使用的时候,我们就可以这样使用


public static void main(String[] args) {
    // TODO Auto-generated method stub
    Operation oper;
    oper= OperationFactory.createOperate('+');
    oper.numberA=5;
    oper.numberA=6;
    double result=oper.getResult();
}

看下程序的UML类图:

设计模式——简单工厂模式_工厂类


这样以来,各个运算类直接就没有关系了,我们修改某个类也不影响其他类运行,想要添加新的运算也只是添加运算子类和修改简单工厂类而已。


总结


简单工厂模式的主要优点如下:


  • 客户端可以免除直接创建对象的职责,只关心使用对象,简单工厂模式实现了对象创建和使用的分离。
  • 客户端不用知道创建产品类具体类名,只要知道具体产品类所对应的参数即可。

简单工厂模式的主要缺点如下:


  • 工厂类负责所有对象的创建逻辑,该类出问题整个系统挂掉。
  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑。
  • 简单工厂模式由于使用了静态工厂方法,所以工厂角色无法形成基于继承的等级结构。



【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月12日 0

暂无评论

推荐阅读
  zT6CXotonQAP   2023年12月05日   32   0   0 SystemSystem