秒懂设计模式之原型模式(Prototype Pattern)

[版权申明] 非商业目的注明出处可自由转载
博文地址:https://blog.csdn.net/ShuSheng0007/article/details/116463979
出自:shusheng007

设计模式汇总篇,一定要点赞收藏:

永不磨灭的设计模式(有这一篇真够了,拒绝标题党)

概述

原型模式属于创建型模式,所以它是描述如何创建对象的模式。顾名思义,先搞一个原型对象出来,然后在这个原型对象的基础上修修补补再弄出一个新对象来。

我们一定要牢记设计模式是前人总结的一套可以有效解决问题的经验,不要一写代码就在考虑该使用什么设计模式,这是极其不可取的。正确的做法应该是在实现业务需求的同时,尽量遵守面向对象设计的六大设计原则即可。后期随着业务的扩展,你的代码会不断的演化和重构,在此过程中设计模式绝逼会大放异彩的。

类型

创建型(creational)

难度

2颗星

定义

使用原型实例指定待创建对象的类型,并且通过复制这个原型来创建新的对象。

你看看这定义,就是不说人话!不管它,一会通过实例意会一下,再通过使用场景知道解决什么问题就可以了

使用场景

  • 当一个对象的构建代价过高时。例如某个对象里面的数据需要访问数据库才能拿到,而我们却要多次构建这样的对象。
  • 当构建的多个对象,均需要处于某种原始状态时,就可以先构建一个拥有此状态的原型对象,其他对象基于原型对象来修改。

UML类图

照例上一张手撕UML类图
在这里插入图片描述
UML 类图也比较简单,只有两个部分

  • Prototype

这个是一个接口,里面必须含有一个可以克隆自己的方法。在Java中,我们可以使用JDK自带的java.lang.Cloneable接口来替代此接口

  • ConcretePrototype

实现了Prototype接口的原型对象,这个对象有个能力就是可以克隆自己。

实例

上回我们说到王二狗公司的大老板要看商城项目的周报表,二狗他们在开发中发现,批量导出报表时特别慢。经过调查发现是报表的主体部分特别耗时,那些头部,作者什么的都不怎么耗时。那二狗他们就在想,能不能将那些耗时的操作作为原型对象,然后在这个原型对象上添加上其他部分,对头,用原型模式可解。

假设一篇报表由报表头与报表体组成,报表体获取特别耗时,报表头不耗时,我们如何大量导出报表呢?

第一步,原型接口

原型接口必须有一个可以克隆自己的方法,反回类型为Prototype

public interface Prototype {
    Prototype copy();
}

第二步,原型类

这个类就是我们的原型类,准备被其他人克隆使用的,所以其实现Prototype接口,具备克隆的能力。根据业务需求,克隆可以是浅克隆,也可以是深克隆。

我们假设此类含有一个存放内容的List,这些数据都是从数据库读取的相对比较耗时。假设我们要生成多篇不同报表,内容基本不变(这是要点,只有你需要的对象是可以基于原型对象的才有意义),头部要不同。

public class Report implements Prototype {
    private List<String> parts;

    public Report() {
        this.parts = new ArrayList<>();
    }

    public Report(List<String> parts) {
        this.parts = parts;
    }
	//耗时的数据加载操作
    public void loadData() {
        pats.clear();
        parts.add("老夫聊发少年狂,左牵黄,右擎苍,锦帽貂裘,千骑卷平冈。");
        parts.add("为报倾城随太守,亲射虎,看孙郎。");
        parts.add("酒酣胸胆尚开张,鬓微霜,又何妨!持节云中,何日遣冯唐?");
        parts.add("会挽雕弓如满月,西北望,射天狼。");
    }

    public List<String> getContents() {
        return parts;
    }

    @Override
    public Prototype copy() {
        List<String> cloneList = new ArrayList<>(parts);
        return new Report(cloneList);
    }
}

第三,客户端使用

public class PrototypeClient {
    public void getReport(){
        //创建原型
        Report reportPrototype = new Report();
        //耗费资源的操作
        reportPrototype.loadData();

        //使用原型对象构建新的对象
        Report reportWithTitle = (Report) reportPrototype.copy();
        List<String> reportContent= reportWithTitle.getContents();
        reportContent.add(0,"《江城子·密州出猎》");
        reportContent.add(1,"----------------------------------------------------------");

        for (String s : reportContent) {
            System.out.println(s);
        }
    }
}

输出

《江城子·密州出猎》
--------------------------------------------------------------------------------
老夫聊发少年狂,左牵黄,右擎苍,锦帽貂裘,千骑卷平冈。
为报倾城随太守,亲射虎,看孙郎。
酒酣胸胆尚开张,鬓微霜,又何妨!持节云中,何日遣冯唐?
会挽雕弓如满月,西北望,射天狼。

技术要点总结

  • 首先要有一个可以克隆自己的接口,例如此处的Prototype
  • 其他对象都是可以基于已经构建出来的原型对象扩展的。

优缺点

优点

有时会极大的提升程序的性能。

缺点

相对增加了系统的复杂性。

总结

设计模式值得你可以练习!

最后,如果你从本文中有所收获,可否点赞转发支持一下博主,你小小的鼓励,是激发博主持续写作的动力…

GitHub源码地址design-patterns

  • 20
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShuSheng007

亲爱的猿猿,难道你又要白嫖?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值