美文网首页
原型模式与建造者模式

原型模式与建造者模式

作者: 攻城老狮 | 来源:发表于2020-06-27 11:36 被阅读0次

    原型模式与建造者模式

    参考教程: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建造者模式 抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产即可。而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品。

    相关文章

      网友评论

          本文标题:原型模式与建造者模式

          本文链接:https://www.haomeiwen.com/subject/qqmmfktx.html