「超全超细」Java设计模式图文详解!!!

灯灯灯灯
• 阅读 1762

java设计模式—原型模式

Java原型模式

1、概述

  啥是原型模式?

  原型模式属于设计模式中的创建型中的一员,

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

  说大白话就是自己复制自己,通过原生对象复制出一个新的对象,这两个对象结构相同且相似;

  需要注意的是,原型对象自己不仅是个对象还是个工厂!并且通过克隆方式创建的对象是全新的对象,它们都是有自己的新的地址,通常对克隆模式所产生的新对象进行修改,是不会对原型对象造成任何影  响的,每一个克隆对象都是相对独立的,通过不同的方式对克隆对象进行修改后,可以得到一系列相似但不完全相同的对象。【获取资源】

2、原型UML图

「超全超细」Java设计模式图文详解!!!

3、深克隆与浅克隆

  原型模式中又可细分为浅克隆和深克隆;【获取资源】

  浅克隆:在浅克隆中,如果原型对象的成员变量是值类型(八大基本类型,byte,short,int,long,char,double,float,boolean).那么就直接复制,如果是复杂的类型,(如枚举、对象)就只复制对应的内存地址。

  深克隆:就是什么都是单独的!全部复制,然后各自独立,修改克隆对象对于原型对象没有任何影响,对于深克隆具体克隆多深取决于业务需求和类结构设计。

4、代码案例

  4.1、先来一个简单小案例热热身

  这个浅克隆比较简单,让我们由浅入深的学习原型模,先看下这个有助于理解深克隆,废话不多说直接上代码

package pattern.prototype.demo;
/**
 * 苹果原型类,这就是我们要复制的对象类
 * 要想克隆一个实例必须要实现Cloneable接口,否则会抛出异常(java.lang.CloneNotSupportedException),
 * @author ningbeibei
 */
public class Apple implements Cloneable{
    //苹果品种
    public String variety;
    //数量
    public int no;

    //添加克隆这个对象的方法,
    public Apple cloneApple() {
        Object obj =null;
        try {
            obj = super.clone();
            return (Apple) obj;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }

    public String getVariety() {
        return variety;
    }
    public void setVariety(String variety) {
        this.variety = variety;
    }
    public int getNo() {
        return no;
    }
    public void setNo(int no) {
        this.no = no;
    }
}

  测试下,看结果是不是很简单,只需要实现Cloneable接口调用clone方法就OK【获取资源】

package pattern.prototype.demo;

public class test {
    public static void main(String[] args) {
        Apple a= new Apple();
        a.setVariety("富士苹果");
        System.out.println("原型对象:"+a);
        Apple b = a.cloneApple();
        System.out.println("克隆出来的新对象:"+b);
        System.out.println("两个对象是否相等:"+(a == b));
        b.setVariety("红星苹果");
        System.out.println("两个对象的苹果品种:"+b.getVariety()+"、"+a.getVariety());
    }
}

  结果输出【获取资源】

「超全超细」Java设计模式图文详解!!!

  4.2、深克隆和浅克隆案例

  代码中案例我以组装电动车为例,要组装电动车必须有这几个组件,电车架子、蓄电池、手刹、钢丝,有了这些组件我们来捋一下他们的关系,组装电车需要把蓄电池和手刹装在电车上,组装手刹需要用到钢丝绳,他们是一个包含关系即:电车架子>蓄电池>手刹>钢丝,请看下面代码。

  (1),先定义克隆接口【获取资源】

package pattern.prototype;
/**
 * 定义原型模式接口
 * @author ningbeibei
 *
 */
public interface ProtoType {
    //浅克隆
    ProtoType getShallowCloneInstance()throws CloneNotSupportedException;
    //深克隆
    ProtoType getDeepCloneInstance(ProtoType protoType);
}

  (2),定义深克隆工具类,通过序列化方式复制对象【获取资源】

package pattern.prototype;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * 原型模式工具类
 * @author ningbeibei
 */
public class ProtoTypeUtil {

    /**
     * 通过序列化方式获取一个深克隆对象
     * 其实就是复制一个全新的对象并且这个对象的引用属性也会单独复制出来
     * 与原对象没有任何关联
     * @param prototype
     * @return
     */
    public static ProtoType getSerializInstance(ProtoType prototype) {
        try {
            //创建输出流
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(prototype);
            //创建输入流
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            ProtoType copy = (ProtoType) ois.readObject();
            bos.flush();
            //关闭输出流
            bos.close();
            //关闭输入流
            ois.close();
            return copy;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

  (3),定义电动车骨架类(属性中有手刹蓄电池组件)【获取资源】

package pattern.prototype;

import java.io.Serializable;

/**
 * 定义电动车类
 * 组装一个电动车需要手刹蓄电池等部件
 * 要实现深克隆需要允许序列化反序列化操作
 * Cloneable :要想使用clone方法必须实现这个接口,否则会抛出异常(java.lang.CloneNotSupportedException)
 * Serializable:允许序列化反序列化对象,通过序列化复制一个新的对象(深克隆会用到)
 * ProtoType:自定义接口,接口中提供浅克隆方法和深克隆方法
 * @author ningbeibei
 */
public class Bicycle implements Cloneable,Serializable,ProtoType{
    //电动车品牌
    public String brand;
    //电动车生产编号
    public int no;
    //手刹组件
    public ParkingBrake parking;
    //蓄电池
    public Accumulator accumulator;

    /**
     * 浅克隆方法
     */
    @Override
    public ProtoType getShallowCloneInstance() {
        Object obj=null;
        try {
            obj = super.clone();
            return (Bicycle)obj;
        } catch (CloneNotSupportedException e) {
            System.out.println("不支持克隆");
            return null;
        }
    }

    /**
     * 深克隆方法
     * 调用工具类ProtoTypeUtil.getSerializInstance方法复制一个新的对象
     */
    @Override
    public ProtoType getDeepCloneInstance(ProtoType protoType) {
        //调用工具类中的序列化对象方法复制对象
        return ProtoTypeUtil.getSerializInstance(protoType);
    }

    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public int getNo() {
        return no;
    }
    public void setNo(int no) {
        this.no = no;
    }
    public ParkingBrake getParking() {
        return parking;
    }
    public void setParking(ParkingBrake parking) {
        this.parking = parking;
    }
    public Accumulator getAccumulator() {
        return accumulator;
    }
    public void setAccumulator(Accumulator accumulator) {
        this.accumulator = accumulator;
    }
}

  (4),定义蓄电池类【获取资源】

package pattern.prototype;

import java.io.Serializable;

/**
 * 电车组件:蓄电池
 * @author ningbeibei
 */
public class Accumulator implements Serializable,ProtoType,Cloneable{
    //蓄电池品牌
    public String brand;
    //出厂编号
    public int no;

    /**
     * 浅克隆方法
     */
    @Override
    public ProtoType getShallowCloneInstance() {
        Object obj=null;
        try {
            obj = super.clone();
            return (Bicycle)obj;
        } catch (CloneNotSupportedException e) {
            System.out.println("不支持克隆");
            return null;
        }
    }

    /**
     * 深克隆方法
     * 调用工具类ProtoTypeUtil.getSerializInstance方法复制一个新的对象
     */
    @Override
    public ProtoType getDeepCloneInstance(ProtoType protoType) {
        //调用工具类中的序列化对象方法复制对象
        return ProtoTypeUtil.getSerializInstance(protoType);
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }
}

  (5),定义手刹类(手刹类属性中有钢丝组件)【获取资源】

package pattern.prototype;

import java.io.Serializable;

/**
 * 电动车组件:手刹
 * @author ningbeibei
 */
public class ParkingBrake implements Serializable, ProtoType,Cloneable {
    //手刹品牌
    public String brand;
    //出厂编号
    public int no;
    //钢丝
    public SteelWire steel;

    /**
     * 浅克隆方法
     */
    @Override
    public ProtoType getShallowCloneInstance() {
        Object obj=null;
        try {
            obj = super.clone();
            return (Bicycle)obj;
        } catch (CloneNotSupportedException e) {
            System.out.println("不支持克隆");
            return null;
        }
    }

    /**
     * 深克隆方法
     * 调用工具类ProtoTypeUtil.getSerializInstance方法复制一个新的对象
     */
    @Override
    public ProtoType getDeepCloneInstance(ProtoType protoType) {
        //调用工具类中的序列化对象方法复制对象
        return ProtoTypeUtil.getSerializInstance(protoType);
    }

    public String getBrand() {
        return brand;
    }
    public void setBrand(String brand) {
        this.brand = brand;
    }
    public int getNo() {
        return no;
    }
    public void setNo(int no) {
        this.no = no;
    }
    public SteelWire getSteel() {
        return steel;
    }
    public void setSteel(SteelWire steel) {
        this.steel = steel;
    }
}

  (6),定义钢丝类

package pattern.prototype;

import java.io.Serializable;

/**
 * 手刹组件;钢丝
 * 电动车手刹需要用到钢丝拉动刹车片才能减速
 * 所以手刹是由钢丝构成
 * @author ningbeibei
 */
public class SteelWire implements Serializable,ProtoType,Cloneable{
    //钢丝品牌
    public String brand;
    //钢丝最大拉力值
    public int no;

    /**
     * 浅克隆方法
     */
    @Override
    public ProtoType getShallowCloneInstance() {
        Object obj=null;
        try {
            obj = super.clone();
            return (Bicycle)obj;
        } catch (CloneNotSupportedException e) {
            System.out.println("不支持克隆");
            return null;
        }
    }

    /**
     * 深克隆方法
     * 调用工具类ProtoTypeUtil.getSerializInstance方法复制一个新的对象
     */
    @Override
    public ProtoType getDeepCloneInstance(ProtoType protoType) {
        //调用工具类中的序列化对象方法复制对象
        return ProtoTypeUtil.getSerializInstance(protoType);
    }
}

  上面代码中都实现三个接口

  Serializable:表明允许这个类被序列化

  ProtoType:自定义接口需要实现浅克隆和深克隆方法

  Cloneable:表明这个类允许被克隆,如果不实现这个接口在克隆时会抛出异常

  在上面的代码中 Bicycle 类中包含了 ParkingBrake 和 Accumulato r类,在 ParkingBrake 类中包含了 SteelWire 类,这样就能充分体现深克隆和浅克隆区别,现在可以直接去测试类中看下区别。

  (6),测试类【获取资源】

package pattern.prototype;

public class test {

    public static void main(String[] args) {

        Bicycle bicycle = new Bicycle(); //创建电动车原型对象                                                               
        ParkingBrake attachment = new ParkingBrake(); //创建手刹对象 
        Accumulator accumulator = new Accumulator(); //创建蓄电池对象
        bicycle.setAccumulator(accumulator); //将蓄电池组装到电动车中
        bicycle.setParking(attachment);    //将手刹添加到电动车中         
        SteelWire steel = new SteelWire();     //钢丝对象
        attachment.setSteel(steel);    //将钢丝对象组装到手刹中
        Bicycle proto = (Bicycle)bicycle.getDeepCloneInstance(bicycle); //深克隆,复制一个新的电动车对象
//        Bicycle proto = (Bicycle)bicycle.getShallowCloneInstance();  //浅克隆,

        System.out.println("电动车"+(proto==bicycle)); 
        System.out.println("电动车手刹"+(proto.getParking()==bicycle.getParking()));
        System.out.println("手刹钢丝"+(proto.getParking().getSteel()==bicycle.getParking().getSteel()));
        System.out.println("电动车蓄电池"+(proto.getAccumulator()==bicycle.getAccumulator()));
    }

}

  深克隆运行结果:都是false说明深克隆出来的对象已经和原对象没有任何联系,修改新的对象也不会影响原来的对象,说明内部手刹钢丝和蓄电池都已经是独立存在的。

「超全超细」Java设计模式图文详解!!!

  浅克隆运行结果:运行结果不难发现手刹、钢丝、蓄电池都是true,这说明复制的出来对象内部组件引用都指向了原对象,也就是说新对象和老对象内部组件引用都是一个对象,当修改新对象或者原对象时新对象也会修改,这就是浅克隆和深克隆的区别,当然深克隆到底克隆几层这个问题还需要深入探讨。

「超全超细」Java设计模式图文详解!!!

5、原型模式优点和缺点【获取资源】

  优点:

  1,当创建的对象实例较为复杂的时候,使用原型模式可以简化对象的创建过程。   2,扩展性好,由于写原型模式的时候使用了抽象原型类,在客户端进行编程的时候可以将具体的原型类通过配置进行读取。   3,可以使用深度克隆来保存对象的状态,使用原型模式进行复制。当你需要恢复到某一时刻就直接跳到。比如我们的idea中就有历史版本。

  缺点:

  1,需要为每一个类配备一个克隆方法,而且该克隆方法位于一个类的里面,当对已有的类进行改造时需要修改源代码,违背了开闭原则。

  2,在实现深克隆的时需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用的时候,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现相对麻烦。

6、原型模式使用场景

  1,创建对象成本比较大,比如初始化要很长时间的,占用太多CPU的,新对象可以通过复制已有的对象获得的,如果是相似的对象,则可以对其成员变量稍作修改。   2,系统要保存对象状态的,而对象的状态改变很小。   3,需要避免使用分层次的工厂类来创建分层次的对象,并且类的对象就只用一个或很少的组合状态。

7、总结

  创建型的设计模式,除开建造者模式基本学习完毕。不过是基础的学习。还没有正式的运用!在写代码的时候需要去考虑使用这种设计模式与否。学而不用存粹浪费时间。其次,创建型的设计模式是基础,需要好好理解这些模式才能够理解其他的结构型以及行为型的设计模式。

本次给大家推荐一个免费的学习君样:894102285里面概括很多干货,包含mysql,netty,spring,线程,spring cloud、jvm、源码、算法等详细讲解及面试资源等。 对Java开发技术感兴趣的同学,欢迎加入Q君样:894102285,不管你是小白还是大牛我都欢迎,还有大牛整理的一套高效率学习路线和教程与您免费分享,同时每天更新视频资料。 最后,祝大家早日学有所成,拿到满意offer,快速升职加薪,走上人生巅峰。【获取资源】

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
菜园前端 菜园前端
1年前
前端学习重点-原型与原型链
原文链接:什么是原型?每一个函数都包含一个prototype属性,这是一个指针指向"原型对象"(prototypeobject),也就是我们平时说的原型。每一个函数都包含不同的原型对象。当将函数用作构造函数的时候,新创建的对象(实例)会从原型对象上继承属性
Stella981 Stella981
3年前
JavaScript面向对象编程的15种设计模式
在程序设计中有很多实用的设计模式,而其中大部分语言的实现都是基于“类”。在JavaScript中并没有类这种概念,面向对象编程不是基于类,而是基于原型去面向对象编程,JS中的函数属于一等对象,而基于JS中闭包与弱类型等特性,在实现一些设计模式的方式上与众不同。ps:本文之讲述面向对象编程的设计模式策略,JavaScript原型的基础请参考阮一峰面向
Wesley13 Wesley13
3年前
Java中23种设计模式详解
Java中23种设计模式1\.设计模式31.1创建型模式41.1.1工厂方法41.1.2抽象工厂61.1.3建造者模式101.1.4单态模式131.1.5原型模式151.2结构型模式171.2.1适配器模式171.2.2桥接模式191.2.3组合
Wesley13 Wesley13
3年前
Java设计模式之原型模式
原型模式简介原型模式实际上不算一种设计模式,应该说是一种技巧吧。当我们需要创建与已有对象一样的对象时,我们通常可以有两种容易想到的方法,一种是将已有对象指向另外一个重新创建的对象,如//将old赋给newObjectnewObjectoldObject;这种做法是相当于newObject还是指向
Wesley13 Wesley13
3年前
Java原型模式
原型模式  原型模式也称克隆模式。原型模式jianmingzhiyi,就是先创造出一个原型,然后通过类似于Java中的clone方法,对对象的拷贝,克隆类似于new,但是不同于new。new创造出来的对象采用的是默认值。克隆出来的对象与原型对象相同,同时不会影响原型对象,然后在修改克隆出来的对象。实现  继承Cloneable接口,重写cl
Wesley13 Wesley13
3年前
00_设计模式之语言选择
设计模式之语言选择设计模式简介背景设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。设计模式(Designpattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的
Stella981 Stella981
3年前
Javascript继承5:如虎添翼
/寄生式继承其实就是对原型继承的第二次封装,在封装过程中对继承的对象进行了扩展。也存在原型继承的缺点!!这种思想的作用也是为了寄生组合式继承模式的实现。///声明基对象varbook{name:'jsbook',al
Wesley13 Wesley13
3年前
23种设计模式(面向对象语言)
一、设计模式的分类总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。创建型模式是用来创建对象的模式,抽象了实例化的过程,帮助一个系统独立于其他关联对象的创建、组合和表示方式。所有的创建型模式都有两个主要功能:  1.将系统所使用的具体类的信息封装起来  2.隐藏