设计模式-创建型模式之原型、建造者设计模式

news2024/9/24 22:17:05

文章目录

    • 七、原型模式
    • 八、建造者模式

七、原型模式

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。它提供了一种创建对象的最佳方式
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。
例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

例如:

创建一个可复制的支付类:

public class WxPay implements Cloneable{
    public WxPay(){
        System.out.println("创建支付对象");
    }
    public WxPay clone() throws CloneNotSupportedException {
        System.out.println("复制对象!");
        return (WxPay) super.clone();
    }
}

使用:

public class demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        WxPay pay = new WxPay();
        WxPay pay1 = pay.clone();
        System.out.println(pay);
        System.out.println(pay1);
    }
}

在这里插入图片描述

可以看到,创建了两个不同的对象,只进行了一次构件函数的执行,当直接创建对象的代价比较大时,就可以采用这种模式。

另外,原型的拷贝又有浅拷贝深拷贝两个层次,上面的方式就是浅拷贝,只把当前对象做了拷贝,如果对象中有其他对象的引用,就不会进行拷贝,修改任意一个对象中的引用,对其他都会有影响

比如上面的WxPay类做如下修改:

  1. 先定义其他操作类
public class OtherOperation {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  1. 再修改WxPay类
public class WxPay implements Cloneable {

    private OtherOperation otherOperation = new OtherOperation();

    public WxPay() {
        System.out.println("创建支付对象");
    }

    public WxPay clone() throws CloneNotSupportedException {
        System.out.println("复制对象!");
        return (WxPay) super.clone();
    }

    public OtherOperation getOperation() {
        return otherOperation;
    }

    public String getName() {
        return otherOperation.getName();
    }

}
  1. 演示
public class demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        WxPay pay = new WxPay();
        WxPay pay1 = pay.clone();
        System.out.println(pay);
        System.out.println(pay1);
        System.out.println(pay.getOperation());
        System.out.println(pay1.getOperation());
        pay.getOperation().setName("abc");
        System.out.println(pay1.getOperation().getName());
    }
}

在这里插入图片描述

上面可以看出,WxPay确实是复制出了一个实例,但是WxPay里面的OtherOperation实例没有复制,还只向同一个地址,导致只要修改任意一个对象中的OtherOperation对其他实例都会有影响。

上面已经看出默认是浅拷贝,但有的时候,我们又需要其中引用的对象也要为新实例,那怎么做呢,下面就来看下深拷贝的实现方式:

深拷贝实现方式 1:重写 clone 方法来实现深拷贝
深拷贝实现方式 2:通过对象序列化实现深拷贝(推荐)

实现方式 1,重写 clone 方法来实现深拷贝

  1. 修改 OtherOperation类
public class OtherOperation implements Cloneable{
    private String name;

    public OtherOperation clone() throws CloneNotSupportedException {
        System.out.println("复制OtherOperation对象!");
        return (OtherOperation) super.clone();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}


  1. 修改WxPay,在clone中再复制OtherOperation ,以达到深拷贝的效果
public class WxPay implements Cloneable {

    private OtherOperation otherOperation = new OtherOperation();

    public WxPay() {
        System.out.println("创建支付对象");
    }

    public WxPay clone() throws CloneNotSupportedException {
        System.out.println("复制对象!");
        WxPay wxPay = (WxPay) super.clone();
        wxPay.otherOperation = otherOperation.clone();
        return wxPay;
    }

    public OtherOperation getOperation() {
        return otherOperation;
    }

    public String getName() {
        return otherOperation.getName();
    }

}
  1. 演示
public class demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        WxPay pay = new WxPay();
        WxPay pay1 = pay.clone();
        System.out.println(pay);
        System.out.println(pay1);
        System.out.println(pay.getOperation());
        System.out.println(pay1.getOperation());
        pay.getOperation().setName("abc");
        System.out.println(pay1.getOperation().getName());
    }
}

在这里插入图片描述

可以看到,WxPay 和 OtherOperation 都是新实例。

深拷贝实现方式 2:通过对象序列化实现深拷贝

  1. OtherOperation 实现 Serializable
public class OtherOperation implements  Serializable {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  1. WxPay 实现Serializable,并提供方法对当前对象进行序列化操作
public class WxPay implements Serializable {

    private OtherOperation otherOperation = new OtherOperation();

    public WxPay() {
        System.out.println("创建支付对象");
    }

    public OtherOperation getOperation() {
        return otherOperation;
    }

    public String getName() {
        return otherOperation.getName();
    }


    public WxPay deepClone() {
        //创建流对象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this); //当前这个对象以对象流的方式输出
            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            return (WxPay) ois.readObject();
        }
        catch (Exception e) {
            return null;
        }
        finally {
            //关闭流
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            }
            catch (Exception e2) {
                System.out.println(e2.getMessage());
            }
        }
    }
}
  1. 效果
public class demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        WxPay pay = new WxPay();
        WxPay pay1 = pay.deepClone();
        System.out.println(pay);
        System.out.println(pay1);
        System.out.println(pay.getOperation());
        System.out.println(pay1.getOperation());
        pay.getOperation().setName("abc");
        System.out.println(pay1.getOperation().getName());
    }
}

在这里插入图片描述

和上面我们手动的方式是一样的效果。

八、建造者模式

建造者模式(Builder Pattern)使用多个简单的对象一步一步构建成一个复杂的对象。将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

例如,在游戏场景中,需要构建人物模型,可能要先构建头部、再构建身体、然后四肢部分,最后才是一个完整的人物,如果都写在一起,肯定会导致代码复杂不易其他开发人员理解,对后期维护扩展难度都大,如果使用构建者模式,便可以将头部、身体、四肢,写在不同的人物实现里面,最后由一个构建类去按照一定的顺序加载它们,然后组成了一个更大的复杂的对象,这样便有利于维护扩展。

下面我们借助上面的例子简单用构建者模式实现下

  1. 定义人物对象,这里直接将头、身体、四肢简化为属性的形式表达。
@Data
public class Person {
    private String head;
    private String body;
    private String foot;
}
  1. 定义人物构建接口,并定义具体的抽象方法。
public interface PersonBuilder {
	//构建入口
	Person Builder();
	//构建头部
	void builderHead();
	//构建身体
	void builderBody();
	//构建四肢
	void builderFoot();
}
  1. 定义一个男孩人物的具体构建实现
public class BoyBuilder implements PersonBuilder {
    private Person person;

    public BoyBuilder() {
        person = new Person();
    }

    @Override
    public Person Builder() {
        builderHead();
        builderBody();
        builderFoot();
        System.out.println("构建完成!");
        return person;
    }

    @Override
    public void builderHead() {
        System.out.println("开始构建男孩头部...");
        person.setHead("男孩头部信息");
    }

    @Override
    public void builderBody() {
        System.out.println("开始构建男孩身体...");
        person.setBody("男孩身体信息");
    }

    @Override
    public void builderFoot() {
        System.out.println("开始构建男孩四肢...");
        person.setFoot("男孩四肢部分信息");
    }
    
}
  1. 演示
public class demo {

    public static void main(String[] args) {
        PersonBuilder personBuilder = new BoyBuilder();
        Person person = personBuilder.Builder();
        System.out.println(StringFormatter.concat("构建对象:", person.toString()).getValue());
    }
	
}

在这里插入图片描述

上面就是将一个人物的不同部分分别构建(实际中每个小的构建都应该在具体的实现中去表达,这里简化为了一个属性),一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C题目12:请写一个函数,判断一个数是否为质数,并在main函数中调用

一.每日小语 人的一切痛苦,本质上都是对自己的无能的愤怒。——王小波 自己思考 判断一个函数是否为质数,这个我在之前练过,我想至少两次,而这一次则是问我如何在main函数中调用,这个概念我不理解,所以我…

软件测试面试最全八股文

请你说一说测试用例的边界 参考回答: 边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充,这种情况下,其测试用例来自等价类的边界。 常见的边界值 1)对16-bit 的整数而言 32…

在gitlab上使用server_hooks

文章目录 1. 前置条件2. Git Hook2.1 Git Hook 分为两部分:本地和远程2.1.1 本地 Git Hook,由提交和合并等操作触发:2.1.2 远程 Git Hook,运行在网络操作上,例如接收推送的提交: 3. 操作步骤3.1 对所有的仓…

Linux 命令pwd

命令作用 pwd是Linux中一个非常有用而又十分简单的命令,pwd是词组print working directory的首字母缩写,即打印工作目录;工作目录就是你当前所处于的那个目录。 pwd始终以绝对路径的方式打印工作目录,即从根目录(/&am…

半同步复制与MHA高可用架构设计

各位道友好,鼠鼠我呀校招刚通过了移动的面试 ,但是安排的岗位是偏远县城里面的岗位,各位能给给建议吗?鼠鼠我啊真不想有时候变成销售员去卖产品!!! 半同步复制与MHA高可用架构设计 一、半同步复…

力扣202题 快乐数 双指针算法

快乐数 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为: 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果这个过程 结果为 1&#…

LeetCode(44)存在重复元素 II【哈希表】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 存在重复元素 II 1.题目 给你一个整数数组 nums 和一个整数 k &#xff0c;判断数组中是否存在两个 不同的索引 i 和 j &#xff0c;满足 nums[i] nums[j] 且 abs(i - j) < k 。如果存在&#xff0c;返回 true &#xf…

.net-去重的几种情况

文章目录 前言1. int 类型的list 去重2. string类型的 list 去重3. T泛型 List去重4. 使用HashSet List去重5. 创建静态扩展方法 总结 前言 .net 去重的几种情况 1. int 类型的list 去重 // List<int> List<int> myList new List<int>(){ 100 , 200 ,100…

波奇学C++:C++11的可变参数模板和emplace

可变参数模板 // args是参数包 template<class T,class ...Args> void _ShowList(T value, Args... args) {cout << sizeof...(args) << endl; // 2cout << value << " ";/*_ShowList(args...);*/} int main() {_ShowList(1,2,3); re…

CSS 在性能优化方面的实践

前言 CSS&#xff08;层叠样式表&#xff09;是一种用于描述网页外观和格式的语言。随着网页变得越来越复杂&#xff0c;CSS文件的大小也随之增加&#xff0c;这可能会对网页性能产生负面 .box {width: 100px;height: 100px;transition: transform 0.3s; }.box:hover {transf…

算法通关村第一关—链表高频面试题(白银)

链表高频面试题 一、五种方法解决两个链表的第一个公共子节点的问题 面试 02.07.链表相交1.首先想到的是暴力解&#xff0c;将第一个链表中的每一个结点依次与第二个链表的进行比较&#xff0c;当出现相等的结点指针时&#xff0c;即为相交结点。虽然简单&#xff0c;但是时间…

SS6810R40V/1A 步进电机驱动芯片 替代ROHM BD68610EFV

SS6810R 是一款由 PWM 电流驱动的双极低功 耗电机驱动集成芯片。 SS6810R 有两路 H 桥驱 动&#xff0c;最大输出 40V /1A。输入接口采用 Pala-IN 的驱 动方式&#xff0c;电流衰减模式可选择为快衰减、慢衰减和 混合衰减&#xff0c;且可以任意设置快衰减与慢衰减的比 例…

【Linux】firewall防火墙配置-解决Zookeeper未授权访问漏洞

背景&#xff1a; zookeeper未授权访问漏洞&#xff0c;进行限制访问&#xff0c;采用防火墙访问策略 配置步骤&#xff1a; ##查看firewall配置清单 firewall-cmd --list-all ##查到为关闭态&#xff0c;启动防火墙 systemctl start firewalld ## 添加端口&#xff0c;这里…

自动驾驶DCLC 功能规范

目录 1 概述Summary....................................................................................................... 4 1.1 目的Purpose....................................................................................................... 4 1.2 范围Ran…

主流数据库类型总结

前言&#xff1a;随着互联网的高速发展&#xff0c;为了满足不同的应用场景&#xff0c;数据库的种类越来越多容易混淆&#xff0c;所以有必要在此总结一下。数据库根据数据结构可分为关系型数据库和非关系型数据库。非关系型数据库中根据应用场景又可分为键值&#xff08;Key-…

跨境在线客服系统:打破国界的沟通壁垒

跨境在线客服系统在如今全球化的时代中扮演着重要的角色。随着电子商务的兴起&#xff0c;越来越多的企业将目光投向了国际市场。然而&#xff0c;跨境交流带来了语言、文化、时区等各种难题&#xff0c;给客服工作带来了巨大的挑战&#xff0c;而跨境在线客服系统成为了解决这…

Python编程新标准:十项好习惯提升编码质量

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 1. 编写易读易维护的代码 编写清晰易读的代码是Python编程的核心。使用描述性变量名、规范的注释和文档字符串&#xff0c;让代码易于理解和维护。 # 示例代码&#xff1a;使用描述性变量名和规范注释 total_s…

AutoCAD 2024 中文

AutoCAD 2024是一款全球知名的计算机辅助设计软件&#xff0c;由Autodesk公司开发。它提供了丰富的绘图功能和工具&#xff0c;可以满足不同领域的需求&#xff0c;支持2D和3D绘图设计&#xff0c;包括平面图、立体图、剖面图等等。此外&#xff0c;AutoCAD 2024具备强大的数据…

Sourcepawn 脚本入门(一)准备

&#x1f34e;Sourcepawn 脚本入门(一)准备 1.Sourcepawn是什么? Sourcepawn是SourceMod团队开发的基于source-sdk的服务器插件开发的一种脚本语言。 SourceMod: Half-Life 2 Scripting 它适用于大部分起源引擎的游戏&#xff0c;多见于L4D&#xff0c;CSS,CSGO&#xff0c; …

哪吒汽车拔头筹,造车新势力首家泰国工厂投产

中国造车新势力首家泰国工厂投产&#xff01;11月30日&#xff0c;哪吒汽车位于泰国的首家海外工厂——泰国生态智慧工厂正式投产下线新车&#xff0c;哪吒汽车联合创始人兼CEO张勇、哪吒汽车泰国合作伙伴BGAC公司首席执行官万查曾颂翁蓬素等出席仪式。首辆“泰国制造”的哪吒汽…