策略模式和工厂模式的区别_工厂模式和策略模式

2023-11-01

学习最好的方法还是得通过笔记和代码。所以今天继续学习工厂模式和策略模式。

简单工厂模式

工厂模式很多人比较熟悉,之前很多地方都能看到工厂模式。之前一直以为工厂模式很简单,所以就没有认真的去学习这个模式,没有去了解这个模式的精髓。今天就好好学习下。

什么是简单工厂模式?

工厂模式就是把创建对象的过程交给工厂类去做,而不是由我们需要用对象的人去创建,我们只管使用,不管这个对象是怎样创建出来的。

为什么使用简单工厂模式?

看个例子,例如现在有个交通工具接口 里面有个移动方法

public interface Vehicle {
    void move();
}

拥有三个实现类,分别是自动车,汽车,公交汽车。

/**
 * @author fanshanchao
 * @date 2019/4/18 13:24
 */
public class Bicycle implements Vehicle {
    @Override
    public void move() {
        System.out.println("使用自定车出行");
    }
}
/**
 * @author fanshanchao
 * @date 2019/4/18 13:27
 */
public class Car implements  Vehicle{
    @Override
    public void move() {
        System.out.println("坐小轿车出行");
    }
}
/**
 * @author fanshanchao
 * @date 2019/4/18 13:28
 */
public class Bus implements Vehicle{
    @Override
    public void move() {
        System.out.println("坐公交车出行");
    }
}

假设现在我们需要骑汽车车出行,最简便的方法应该就是直接创建一个自行车对象然后进行嗲用move方法,例如这样:

public static void main(String[] args) {
    Vehicle bicycle = new Bicycle();
    bicycle.move();
}

这样是能够成功创建自行车对象的,但是现在自行车对象被修改了,创建自行车对象需要额外添加一个brand参数标识这个自行车的品牌。现在如果需要获取自行车对象可能第一时间想到就是修改一下创建Bicycle的代码,传入参数就好了。

public class Bicycle implements Vehicle {
    private String brand;
    public Bicycle(String brand){
        this.brand = brand;
    }
    @Override
    public void move() {
        System.out.println("使用自定车出行");
    }
    public static void main(String[] args) {
        Vehicle bicycle = new Bicycle("凤凰牌");
        bicycle.move();
    }
}

像上面这样很简单就实现了,但是如果一个程序中很多地方用到了Bicycle对象,那岂不是每个地方都要去修改它创建Bicycle对象的代码,那样也太难维护了吧。而且我们使用Bicycle对象根本不关系创建它需要什么东西,你只要能给我一个Bicycle对象就行,所以就出现了工厂模式。

工厂模式的使用:

创建一个工厂类

/**
 * @author fanshanchao
 * @date 2019/4/18 13:42
 */
public class VehicleFactory {
    public static Vehicle getVehicle(String name){
        Vehicle vehicle = null;
        switch (name){
            case "自行车":
                vehicle = new Bicycle();
                break;
            case "汽车":
                vehicle = new Car();
                break;
            case "公共汽车":
                vehicle = new Bus();
                break;
        }
        return vehicle;
    }
}

现在我们获取一个自行车对象可以这样获取

public static void main(String[] args) {
    Vehicle bicycle = VehicleFactory.getVehicle("自行车");
    bicycle.move();
}

而如果现在创建自行车对象时需要添加一个brand参数的时候我们根本不需要在每个使用自行车对象的地方都传入brand参数,我们只需要在VehicleFactory工厂类中修改一下工厂类的代码就可以了。使用工厂模式降低了耦合度,因为使用自行车对象的人根本不管你自行车是怎么创建出来的,你只要能给我一个自行车对象就行,所以创建自行车的过程完全可以交给工厂去做。

工厂模式UML图

策略模式

先看下策略模式的定义:

它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化,不好影响到使用算法的客户。

大概意思就是一个对象由于实例化不同的策略,所以最终在调用这个对象的统一方法的所获得的结果不不同,具体看代码。

还是上面的交通工具接口和三个实现类自行车,汽车,公共汽车。按理来说出行的不应该是交通工具,而应该是人吧,所以现在重新创建一个人的类,在人的类里面有一个交通工具引用,然后使用交通工具去出行。

public class Person {
    private Vehicle vehicle;
    private Person(Vehicle vehicle){
        this.vehicle = vehicle;
    }

    /**
     * 旅行方法
     */
    public void travel(){
        this.vehicle.move();
    }
}

运行代码:

public static void main(String[] args) {
    Person person = new Person(new Bicycle());
    person.travel();

    person = new Person(new Bus());
    person.travel();
}

运行结果:

可以看到由于选择的策略(Vehicle)不同,会导致运行的结果不同。

有人会说我直接调用自行车对象或公交车对象的方法不也可以有同样的运行结果吗?其实这里应该用到面向对象的概念,因为交通工具应该是人可以选择的。策略模式是一种定义一系列算法的方法,从概念上来看,所有的这些方法都是相同的工作,例如各种交通工具的根本作用不就是出行吗,只是实现不同,它可以以相同的方法调用所有的算法,例如上面的this.vehicle.move();.而且使用策略模式扩展性很好,增加一个策略,就多增加一个类就好了。

其实策略模式就是一个算法接口(Vehicle),多个算法实现(Bicycle,Bus,Car),和一个上下文(Person)。

策略模式UML图

其实现在看这个策略模式UML会发现一个问题,如果自行车类修改了怎么办?其实很简单,把策略模式和简单工厂模式结合使用就可以了,改写Person如下

public class Person {
    private Vehicle vehicle;
    private Person(String name){
        switch (name){
            case "自行车":
                vehicle = new Bicycle();
                break;
            case "汽车":
                vehicle = new Car();
                break;
            case "公共汽车":
                vehicle = new Bus();
                break;
        }
    }

    /**
     * 旅行方法
     */
    public void travel(){
        this.vehicle.move();
    }
}
调用代码:
    public static void main(String[] args) {
        Person person = new Person("自行车");
        person.travel();

        person = new Person("公共汽车");
        person.travel();
    }

策略模式和工厂模式结合后还可以避免用户看到实际真正的策略类。具体策略模式和工厂模式需不需要结合还是看个人需求吧。

工厂方法模式

简单工厂模式最大的优点就是工程类中包含了必要的逻辑判断,根据用户的选择条件实例化相关的类,对于用户来说,去除了与具体产品的依赖。但是简单工厂模式有个缺陷。例如上面的例子我们需要增加一个新的交通工具,例如火车,那么我们必须创建一个火车类实现交通工具接口后还要重新去修改工厂类的swtch语句添加一个分支选项。设计模式有个原则就是开放封闭原则。而上面的做法就违背了这个原则。所有工厂模式就来了。

工厂模式的定义

定义一个用户创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。

具体看代码:

创建一个工厂接口

public interface VehicleFactory2 {
    Vehicle getVehicle();
}

然后像我们之前需要获取某种交通工具的方式改成分别写一个工厂类去实现这个接口,然后这个工厂类去创建具体的交通工具。

/**
 * @author fanshanchao
 * @date 2019/4/18 15:05
 * 自行车工厂类
 */
public class BicycleFactory implements VehicleFactory2 {
    @Override
    public Vehicle getVehicle() {
        return new Bicycle();
    }
}
/**
 * @author fanshanchao
 * @date 2019/4/18 15:06
 * 公共汽车工厂类
 */
public class BusFactory implements VehicleFactory2 {
    @Override
    public Vehicle getVehicle() {
        return new Bus();
    }
}
.......汽车类类似

我们现在再创建自行车对象和公共汽车对象就可以使用下面的方法

public static void main(String[] args) {
    //根据自行车工厂创建自行车
    BicycleFactory bicycleFactory = new BicycleFactory();
    Vehicle bicycle = bicycleFactory.getVehicle();
    bicycle.move();
    //根据公共汽车工厂创建公共汽车
    BusFactory busFactory = new BusFactory();
    Vehicle bus = busFactory.getVehicle();
    bus.move();
}

如果需要添加一个交通工具火车只需要创建一个火车类实现交通工具接口,再创建一个火车工厂实现交通工具工厂。这也就不用修改原来的代码就可以增加一个交通工具,符合了开放封闭原则。

工厂方法模式UML图

优缺点

工厂方法模式是简单工厂模式的进一步抽象和推广,由于使用了多态,工厂方法模式保持了简单工厂模式的有点,而且克服了它的缺点。但缺点是每加一个产品就多多加一个产品工厂类,增加了额外的开发量。

总结

简单来说两者工厂模式都是可以让使用对象的人去避免创建对象,工厂把对象给你了,你只管使用就可以了,而不必管这些对象究竟如何创建及如何组织的。工厂模式是可以配合反射来使用,这个以后学到再写吧。

策略模式就是根据用户提供的策略,在不同的场景中,该行为有不同的实现算法。策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码转移到父类里面,从而避免重复的代码。缺点是用户必须知道所有的策略类,可以通过和工厂模式来结合使用,不过也有弊端,并且每个策略都需要一个策略类,策略一多类也就非常多了。以前使用DBUtils时候传入不同的参数然后就可以有不同的封装方式返回object或者list就是就是的策略模式。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

策略模式和工厂模式的区别_工厂模式和策略模式 的相关文章

  • PAM4: A new measurement science

    原文地址 This article is part of EDN and EE Times Hot Technologies Looking ahead to 2016 feature where our editors examine s
  • 各自然带代表植被_各气候带对应植被

    1 各种气候对应的代表植被 动物 土壤 农作物 shide 2 地理各自然带所对应的植被带分别是什么 1 热带雨林带 热带雨林 2 热带草原带 热带稀树草原 3 热带荒漠带 热带荒漠 4 亚热带常绿硬叶林带 亚热带常绿硬叶林 5 亚热带常绿
  • CSS animation动画使用详解

    目录 一 animation动画的使用步骤 第一步 定义动画 第二步 使用动画 二 animation的复合属性 三 animation的拆分属性 四 动画属性 一 animation动画的使用步骤 第一步 定义动画 changes为定义的
  • springboot实现复杂业务下的更新操作

    大家好 我是雄雄 欢迎关注微信公众号 雄雄的小课堂 前言 现在是2022年5月4日19 25 55 今天写了个这样的功能 某用户在一天内有多个训练项目 比如 晨跑 有氧训练 跳绳这三个项目 这三个训练项目都在数据库中有记录 每个项目都有开始
  • moment()获取当前时间的前几个小时、前几天、前几个月、前几年

    注意 项目中如果没有安装moment需要先安装引入或直接引入网页 可以参考moment官网 1 获取从当前时间开始的前一个小时是几时 整时 moment subtract 1 hours hour 2 获取当前日期的前一天日期是几日 日 m
  • Linux应用编程之多次打开同一文件进行读写操作与 O_APPEND 标志

    重复打开同一个文件 进行写操作 譬如一个进程中两次调用 open 函数打开同一个文件 分别得到两 个文件描述符 fd1 和 fd2 使用这两个文件描述符对文件进行写入操作 那么它们是分别写 各从各的位置 偏移量开始写 还是接续写 一个写完
  • 《Linux运维总结:Centos7.6之OpenSSH7.4升级版本至9.3》

    一 环境信息 操作系统 Centos7 6 1810 OpenSSH 7 4p1 OpenSSL 1 0 2k fips 如下图所示 注意 升级后由于加密算法的区别 低版本的SSH工具可能无法连接 建议改用Xshell7或SecureCRT
  • 【高级Java架构师系统学习】最新Java高级面试题汇

    性能调优 影响MySQLServer 性能的相关因素 商业需求对性能的影响 系统架构及实现对性能的影响 Query语句对系统性能的影响 Schema设计对系统的性能影响 硬件环境对系统性能的影响 MySQL 数据库锁定机制 MySQL锁定机
  • 当黑客就入门 ZzCMS8.1前台任意脚本上传漏洞复现

    一 环境选择 1 系统环境 Win server 2003 2 靶机IP 192 168 220 132 3 Web环境 Phpstudy2016 4 源码 ZzCMS8 1 lt 点击下载 gt 二 源码部署 1 将源码放入phpstud
  • 如何将typora照片导到csdn上

    解决typora 图片上传到csdn的问题 问题背景 今晚想把typora的笔记传到csdn 却发现照片一直发不过去 总是出现 外链图片转存失败 源站可能有防盗链机制 建议将图片保存下来直接上传 的问题 后来查了一下怎么解决 需要先将导入到
  • 德勤《全球AI发展白皮书》出炉!八大新趋势,三个关键技术一文扫尽【附下载】...

  • json-lib系列包报错原因

    我的JDK是1 6 json lib换了好几个版本还是不行 jsonArray与list之间的转换始终进行不了 之前也用到jsonArray与String之间的转换报错 不得不改用org json jar那个包 今天再次遇到这个问题 我决心
  • Nessus安装与使用

    目录 前言 一 kali安装Nessus 1 访问Nessus官网 2 安装Nessus程序 3 启动Nessus 4 浏览器访问nessus的web网站 5 选择 Managed Scanner 选项 点击 Continue 6 选择 T
  • SPEC CPU简介和使用

    前言 SPEC CPU是一套行业标准的CPU密集型基准测试套件 SPEC设计了此套件 以使用实际用户应用程序开发的工作负载 在最广泛的实际硬件范围内提供计算密集型性能的比较度量 这些基准作为源代码提供 要求用户习惯使用编译器命令以及通过控制
  • Linux开启查看端口

    1 查看防火墙状态 systemctl status firewalld 下图是防火墙关闭状态 2 开启防火墙 systemctl start firewalld 开启端口 firewall cmd zone public add port
  • 教你如何保存有妖气漫画

    有妖气是中国唯一且最大的纯原创漫画网站 官方这么介绍的 是不是真的我也不知道 但是在有妖气中看到喜欢的漫画想要保存下来的时候就出现问题了 有妖气为了防盗版是禁止图片另存为的 如果想要保存漫画只能靠截图了 但是截图后的漫画就没有原版的那么清晰
  • Windows本机无法访问VMware虚拟机Ubuntu上部署的项目

    问题 本机无法访问虚拟机上部署的项目 原因 8080端口没有开放 本来以为防火墙关闭就不会有这个问题 解决方法 开放端口8080 执行命令如下 永久开放8080端口 root ubuntu sudo firewall cmd permane
  • spring boot学习(十四):整合shiro

    shiro和SpringSecurity一样的安全 主要是涉及到realm Spring Boot 的shiro整合
  • S3使用rest API进行签名文件上传出现403问题

    问题 在使用s3的rest api进行签名请求头文件上传的时候 代理服务器出现了403问题 原因 必须将指定的所有签名请求头 都带给aws的s3服务器才能正常返回200响应 如下为请求头信息 POST 86 1792 19 012 0100

随机推荐