菜鸟的架构学习之路-原型模式和建造者模式

原型模式

定义:用已经创建的对象实例,在复制另一个相似的对象
理解:原型模式就是通过一个对象copy出另一个对象,不适用原型模式来实现的话,就是 new 出来一个对象 通过构造方法或get set方法 把原来对象的值逐一赋给新的对象,可是如果对象的属性过多,那么操作起来特别麻烦,于是又通过反射机制新建一个对象并用 for 循环进行赋值代码如下在这里插入图片描述
这样的赋值显得特别麻烦,因此原型模式的出现决解了上述问题,而原型模式分为浅拷贝与深拷贝两个,下面我们一一介绍
浅拷贝:
实现代码:
在这里插入图片描述
我们只需要实现 cloneable 接口即可,然后重写clone 方法,这样我们在进行克隆对象的话只需要调用clone方法,便可得到另一个相同的对象,调用代码如下
在这里插入图片描述
是不是简单了很多,但是继承 cloneable 接口会出现一个问题,但我们成员变量为引用类型的时候,那么我们在改变新对象的对应属性值的时候,原有对象的属性值也会随之改变,问题重现如下:
在这里插入图片描述
执行结果
在这里插入图片描述
因此我们可知,jdk自带的 clone 方法只是将对应的属性值赋值,而不是属性的内容,所以给 这个应用类型赋值的时候值赋予了对应的内存地址,这显然不是我们想用看到的,所以我们进行了以下改变:
在这里插入图片描述
通过ArrayList 拥有的clone方法将原有的对象在克隆出来一个新的对象并赋值,这样可以解决上面出现的问题,通过查看ArrayList源码我们得知在这里插入图片描述
他也继承cloneable这个接口,所以当ArrayList<> 的里面元素的类型也是引用类型的话,改变对应的值是否原来的数据,也会变化呢?
将 premium 改变List类型
在这里插入图片描述
客户端调用
在这里插入图片描述
返回结果
在这里插入图片描述
因此我们得知继承 cloneable的接口都是浅克隆,那么我们怎么去修改呢?

我们可以通过序列化的方式进行深拷贝
在这里插入图片描述
这样我们就可以得到预期的结果了
在这里插入图片描述
除了序列化外,我们还可以通过将对象转成json
在这里插入图片描述
这样对拷贝出的对象改变,并不会影响到原来对象的值

总结:当我们的类的成员变量没有除了string 类型外 没有其他引用类型的时候 我们可以使用 实现 cloneable 接口 实现拷贝对象,如果存在应用对象时,引用对象元素是string或非引用类型,那么我们可以通过修改clone()方法进行拷贝对象,否则 我们可以通过序列化的方式实现对象拷贝实现深拷贝:

建造者模式

定义:指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示
个人理解:将对象的创建交给类似于工厂得一个类(建造类),但与工厂模式不同得是,工厂创建出来的对象属性值是相同的,但建造者模式创建出来得对象属性值是可以变得,建造者模式会创建对象会通过定义好得顺序进行赋值。
我们通过装饰房间这个例子来了解建造者模式
首先建立一个房间得类:
在这里插入图片描述
里面有地板、沙发、窗帘、墙壁字段,然后请工人装修代码如下

public class SpruceUpBulider {
    private Map<String,String> bulideInfo = new HashMap<>();
    public SpruceUpBulider createFloor(String floor) {
        this.bulideInfo.put("floor",floor);
        return this;
    }
    public SpruceUpBulider createSofa(String sofa) {
        this.bulideInfo.put("sofa",sofa);
        return this;
    }
    public SpruceUpBulider createCurtain(String curtain) {
        this.bulideInfo.put("curtain",curtain);
        return this;
    }
    public SpruceUpBulider createWall(String wall) {
        this.bulideInfo.put("wall",wall);
        return this;
    }
    public SpruceUp bulider(){
        SpruceUp res = new SpruceUp();

        if(bulideInfo.containsKey("floor")){res.setFloor(bulideInfo.get("floor")); }
        else { res.setFloor("水泥地板"); }
        System.out.println("地板已经铺好了");

        if(bulideInfo.containsKey("wall")){ res.setWall(bulideInfo.get("wall")); }
        else { res.setWall("白色墙壁"); }
        System.out.println("墙面已经刷完了");

        if(bulideInfo.containsKey("sofa")){
            res.setSofa(bulideInfo.get("sofa"));
            System.out.println("沙发摆放完毕");
        }
        if(bulideInfo.containsKey("curtain")){
            res.setCurtain(bulideInfo.get("curtain"));
            System.out.println("窗帘挂好了");
        }
        System.out.println("装修完成");
        return res;
    }
}

工人开始装修了
在这里插入图片描述
装修结果
在这里插入图片描述
通过上面的案例 可以看出想要的不同的对象属性,直接调用对应方法赋值即可,而工厂方法只能创造出相同属性的对象,那么我们直接创建SpruceUp对象,调用get set方法赋值 不就行了吗?为什么还要新建一个类呢?如果自己之间建立那么就需要我们自己知道,需要先铺地板,其次刷墙、然后摆放沙发,最后挂窗帘,这样操作起来使用者知道的细节够多,所以只需要使用者告诉创建者,要什么样地板的就行了,这样减轻了使用者的负担。
但建造者模式也拥有对应的弊端:一个类对应着一个创建者,这样可能会造成代码过于复杂

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值