原型模式与建造者模式

原型模式与建造者模式

参考教程:https://www.bilibili.com/video/BV1G4411c7N4
代码实现 Github:https://github.com/yaokuku123/pattern


原型模式

  1. 案例

现在有一只羊tom,姓名为: tom, 年龄为:1,颜色为:白色,请编写程序创建和tom羊属性完全相同的10只羊。

  1. 传统方法
4.png
  • Sheep类
package com.yqj.pattern.prototype.traditional;

public class Sheep {
    private String name;
    private int age;
    private String color;

    public Sheep(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';
    }
}
  • Client类
package com.yqj.pattern.prototype.traditional;

public class Client {
    public static void main(String[] args) {
        Sheep sheep = new Sheep("tom", 1, "白色");
        Sheep sheep2 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep3 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep4 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        Sheep sheep5 = new Sheep(sheep.getName(), sheep.getAge(), sheep.getColor());
        System.out.println(sheep);
        System.out.println(sheep2);
        System.out.println(sheep3);
        System.out.println(sheep4);
        System.out.println(sheep5);
    }
}
  • 分析

传统方法虽然可以实现相应的功能,但存在问题:不能动态的获取对象运行时的状态,而只是从初始化的对象中获取参数;若原对象增减属性的话,所有依此创建的新对象均需要修改;在创建新对象的时候,总是需要获取原始对象的属性,若对象的属性复杂时,效率低。

  1. 原型模式

解释:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象。,允许一个对象再创建另外一个可定制的对象, 无需知道如何创建的细节。

原理:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即:对象.clone()

  1. 改进代码
  • Sheep类
package com.yqj.pattern.prototype.improve;

public class Sheep implements Cloneable {
    private String name;
    private int age;
    private String color;

    public Sheep(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Sheep{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';
    }

    @Override
    protected Object clone() {
        Object sheep = null;
        try {
            sheep = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return sheep;
    }
}
  • Client类
package com.yqj.pattern.prototype.improve;

public class Client {
    public static void main(String[] args) {
        Sheep sheep = new Sheep("tom", 1, "白色");
        Sheep sheep2 = (Sheep) sheep.clone();
        Sheep sheep3 = (Sheep) sheep.clone();
        System.out.println(sheep+" hashcode:"+sheep.hashCode());
        System.out.println(sheep2+" hashcode:"+sheep2.hashCode());
        System.out.println(sheep3+" hashcode:"+sheep3.hashCode());

    }
}
  1. 深拷贝和浅拷贝
  • 浅拷贝

对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。

对于数据类型是引用数据类型的成员变量,比如说成员变量是某个数组、某个类 的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(内 存地址)复制一份给新的对象。因为实际上两个对象的该成员变量都指向同一个 实例。在这种情况下,在一个对象中修改该成员变量会影响到另一个对象的该成 员变量值

浅拷贝是使用默认的 clone()方法来实现 sheep = (Sheep) super.clone();

  • 深拷贝

复制对象的所有基本数据类型的成员变量值

为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变 量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对 整个对象进行拷贝

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

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

建造者模式

  1. 案例

盖房子项目:

  • 需要建房子:这一过程为打桩、砌墙、封顶 。
  • 房子有各种各样的,比如普通房,高楼,别墅,各种房子的过程虽然一样,但是要求不要相同的。
  1. 传统方法
1-1592357505036.png
package com.yqj.pattern.builder.traditional;
//抽象房子类
abstract class AbstractHouse {
    public abstract void buildBasic();
    public abstract void buildWalls();
    public abstract void roofed();
    public void build(){
        buildBasic();
        buildWalls();
        roofed();
    }
}
//普通房子
class CommonHouse extends AbstractHouse{

    @Override
    public void buildBasic() {
        System.out.println("普通房子打地基");
    }

    @Override
    public void buildWalls() {
        System.out.println("普通房子刷墙");
    }

    @Override
    public void roofed() {
        System.out.println("普通房子封顶");
    }
}
//别墅
class HighBuilding extends AbstractHouse{

    @Override
    public void buildBasic() {
        System.out.println("别墅打地基");
    }

    @Override
    public void buildWalls() {
        System.out.println("别墅刷墙");
    }

    @Override
    public void roofed() {
        System.out.println("别墅封顶");
    }
}
//用户
public class Client{
    public static void main(String[] args) {
        CommonHouse commonHouse = new CommonHouse();
        commonHouse.build();

        HighBuilding highBuilding = new HighBuilding();
        highBuilding.build();
    }
}
  • 分析

设计的程序结构,过于简单,没有设计缓存层对象,程序的扩展和维护不好. 也就 是说,这种设计方案,把产品(即:房子) 和 创建产品的过程(即:建房子流程) 封装在一起,耦合性增强了。应该想办法将产品和过程分离,达到解耦的目的。

  1. 建造者模式

解释:它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。

建造者模式的四个角色:

  • Product(产品角色): 一个具体的产品对象。
  • Builder(抽象建造者): 创建一个Product对象的各个部件指定的 接口/抽象类。
  • ConcreteBuilder(具体建造者): 实现接口,构建和装配各个部件。
  • Director(指挥者): 构建一个使用Builder接口的对象。它主要是用于创建一个 复杂的对象。它主要有两个作用,一是:隔离了客户与对象的生产过程,二是: 负责控制产品对象的生产过程。
  1. 改进方法
1-1592362117625.png
package com.yqj.pattern.builder.improve;

//产品
class House{
    private String basic;
    private String wall;
    private String roofed;

    public String getBasic() {
        return basic;
    }

    public void setBasic(String basic) {
        this.basic = basic;
    }

    public String getWall() {
        return wall;
    }

    public void setWall(String wall) {
        this.wall = wall;
    }

    public String getRoofed() {
        return roofed;
    }

    public void setRoofed(String roofed) {
        this.roofed = roofed;
    }

    @Override
    public String toString() {
        return "House{" +
                "basic='" + basic + '\'' +
                ", wall='" + wall + '\'' +
                ", roofed='" + roofed + '\'' +
                '}';
    }
}

//抽象建造者
abstract class HouseBuilder{
    protected House house = new House();
    //建造流程,定义有关的抽象方法
    public abstract void buildBasic();
    public abstract void buildWalls();
    public abstract void roofed();
    //建造好房子,返回产品
    public House buildHouse(){
        return house;
    }
}

//具体建造者1
class CommonHouseBuilder extends HouseBuilder{
    //实现具体的构建方法
    @Override
    public void buildBasic() {
        house.setBasic("普通房子打地基");
    }

    @Override
    public void buildWalls() {
        house.setWall("普通房子刷墙");
    }

    @Override
    public void roofed() {
        house.setRoofed("普通房子封顶");
    }
}

//具体建造者2
class HighBuilding extends HouseBuilder{

    @Override
    public void buildBasic() {
        house.setBasic("别墅打地基");
    }

    @Override
    public void buildWalls() {
        house.setWall("别墅刷墙");
    }

    @Override
    public void roofed() {
        house.setRoofed("别墅封顶");
    }
}



//指挥者
class HouseDirector{
    HouseBuilder houseBuilder;

    public HouseDirector(HouseBuilder houseBuilder) {
        this.houseBuilder = houseBuilder;
    }

    public void setHouseBuilder(HouseBuilder houseBuilder) {
        this.houseBuilder = houseBuilder;
    }

    //制定产品的构建流程
    public House build(){
        houseBuilder.buildBasic();
        houseBuilder.buildWalls();
        houseBuilder.roofed();
        //返回产品
        return houseBuilder.buildHouse();
    }
}

//用户
public class Client{
    public static void main(String[] args) {
        HouseDirector director = new HouseDirector(new CommonHouseBuilder());
        System.out.println(director.build());
        //更改指挥者的构建产品
        director.setHouseBuilder(new HighBuilding());
        System.out.println(director.build());
    }
}
  1. 小结
  • 客户端(使用程序)不必知道产品内部组成的细节,将产品本身与产品的创建过程解 耦,使得相同的创建过程可以创建不同的产品对象。
  • 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替 换具体建造者或增加新的具体建造者, 用户使用不同的具体建造者即可得到不同 的产品对象。
  • 可以更加精细地控制产品的创建过程 。将复杂产品的创建步骤分解在不同的方法 中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
  • 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程, 系统扩展方便,符合 “开闭原则”
  • 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
  • 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,因此在这种情况下,要考虑是否选择建造者模式。
  • 抽象工厂模式VS建造者模式 抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产即可。而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

攻城老湿

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值