创建型设计模式之原型模式—02

原型模式

  • 存在大量相同或相似对象的创建问题,如果用传统的构造函数来创建对象,会比较复杂且耗时耗资源,用原型模式生成对象就很高效,就像孙悟空拔下猴毛轻轻一吹就变出很多孙悟空一样简单。
  • 原型模式的克隆分为浅克隆和深克隆,Java 中的 Object 类提供了浅克隆的 clone() 方法,具体原型类只要实现 Cloneable 接口就可实现对象的浅克隆,这里的 Cloneable 接口就是抽象原型类。

定义

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。

结构

原型模式包含以下主要角色

  • 1,抽象原型类:规定了具体原型对象必须实现的接口。
  • 2,具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
  • 3,访问类:使用具体原型类中的 clone() 方法来复制新的对象。
    由于 Java 提供了对象的 clone() 方法,所以用 Java 实现原型模式很简单。
    创建型设计模式之原型模式—02_第1张图片

实现

/**
 * @author yeming.gao
 * @Description: 原型模式
 * @date 2020/5/14 18:44
 */
public class Prototype {
    public static void main(String[] args) throws CloneNotSupportedException {
        Realizetype obj1 = new Realizetype();
        Realizetype obj2 = (Realizetype) obj1.clone();
        System.out.println("obj1 == obj2 ? " + (obj1 == obj2));
    }
}

/**
 * 原型模式的测试类
 */
class Realizetype implements Cloneable {
    Realizetype() {
        System.out.println("具体原型创建成功!");
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        System.out.println("具体原型复制成功!");
        return super.clone();
    }
}

程序的运行结果如下

具体原型创建成功!
具体原型复制成功!
obj1 == obj2 ? false

示例

用原型模式除了可以生成相同的对象,还可以生成相似的对象

【例】用原型模式生成“三好学生”奖状
分析:同一学校的“三好学生”奖状除了获奖人姓名不同,其他都相同,属于相似对象的复制,同样可以用原型模式创建,然后再做简单修改就可以了。UML类图如下:
创建型设计模式之原型模式—02_第2张图片
实现

/**
 * @author yeming.gao
 * @Description: 原型模式示例:同一学校的“三好学生”奖状除了获奖人姓名不同,其他都相同,
 *                             属于相似对象的复制,同样可以用原型模式创建,然后再做简单
 *                             修改就可以了
 * @date 2020/5/15 9:42
 */
public class ProtoTypeCitation {
    public static void main(String[] args) throws CloneNotSupportedException {
        citation obj1 = new citation("张三", "同学:在2016学年第一学期中表现优秀,被评为三好学生。", "韶关学院");
        obj1.display();
        citation obj2 = (citation) obj1.clone();
        obj2.setName("李四");
        obj2.display();
        citation obj3 = (citation) obj1.clone();
        obj3.setName("王五");
        obj3.display();
    }
}

/**
 * 奖状类
 */
class citation implements Cloneable {
    private String name;
    private String info;
    private String college;

    citation(String name, String info, String college) {
        this.name = name;
        this.info = info;
        this.college = college;
        System.out.println("奖状创建成功!");
    }

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

    String getName() {
        return (this.name);
    }

    void display() {
        System.out.println(name + info + college);
    }

    @Override
    public Object clone() throws CloneNotSupportedException {
        System.out.println("奖状拷贝成功!");
        return super.clone();
    }
}

程序运行结果如下:

奖状创建成功!
张三同学:在2016学年第一学期中表现优秀,被评为三好学生。韶关学院
奖状拷贝成功!
李四同学:在2016学年第一学期中表现优秀,被评为三好学生。韶关学院
奖状拷贝成功!
王五同学:在2016学年第一学期中表现优秀,被评为三好学生。韶关学院

应用场景

  • 对象之间相同或相似,即只是个别的几个属性不同的时候。
  • 对象的创建过程比较麻烦,但复制比较简单的时候。

扩展

原型模式可扩展为带原型管理器的原型模式,它在原型模式的基础上增加了一个原型管理器 PrototypeManager 类。该类用 HashMap 保存多个复制的原型,Client 类可以通过管理器的 get(String id) 方法从中获取复制的原型。UML类图如下:
创建型设计模式之原型模式—02_第3张图片
【例】用带原型管理器的原型模式来生成包含“圆”和“正方形”等图形的原型,并计算其面积。分析:本实例中由于存在不同的图形类,例如,“圆”和“正方形”,它们计算面积的方法不一样,所以需要用一个原型管理器来管理它们,UML类图如下:
创建型设计模式之原型模式—02_第4张图片
实现

/**
 * @author yeming.gao
 * @Description: 原型模式扩展:用带原型管理器的原型模式来生成包含“圆”和“正方形”等图形的原型,
 *                             并计算其面积。
 * 分析:本实例中由于存在不同的图形类,例如,“圆”和“正方形”,它们计算面积的方法不一样,
 *       所以需要用一个原型管理器来管理它们
 * @date 2020/5/15 10:15
 */
public class ProtoTypeShape {
    public static void main(String[] args) {
        ProtoTypeManager pm = new ProtoTypeManager();
        IShape obj1 = pm.getShape("Circle");
        obj1.countArea();
        IShape obj2 = pm.getShape("Square");
        obj2.countArea();
    }
}

interface IShape extends Cloneable {
    /**
     * 拷贝
     * @return Object
     */
    Object clone();
    /**
     * 计算面积
     */
    void countArea();
}

class Circle implements IShape {
    @Override
    public Object clone() {
        Circle w = null;
        try {
            w = (Circle) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("拷贝圆失败!");
        }
        return w;
    }

    @Override
    public void countArea() {
        int r = 0;
        System.out.print("这是一个圆,请输入圆的半径:");
        Scanner input = new Scanner(System.in);
        r = input.nextInt();
        System.out.println("该圆的面积=" + 3.1415 * r * r + "\n");
    }
}

class Square implements IShape {
    @Override
    public Object clone() {
        Square b = null;
        try {
            b = (Square) super.clone();
        } catch (CloneNotSupportedException e) {
            System.out.println("拷贝正方形失败!");
        }
        return b;
    }

    @Override
    public void countArea() {
        System.out.print("这是一个正方形,请输入它的边长:");
        Scanner input = new Scanner(System.in);
        int a = input.nextInt();
        System.out.println("该正方形的面积=" + a * a + "\n");
    }
}

class ProtoTypeManager {
    private HashMap ht = new HashMap<>();

    public ProtoTypeManager() {
        ht.put("Circle", new Circle());
        ht.put("Square", new Square());
    }

    public void addshape(String key, IShape obj) {
        ht.put(key, obj);
    }

    public IShape getShape(String key) {
        IShape temp = ht.get(key);
        return (IShape) temp.clone();
    }
}

运行结果如下所示:

这是一个圆,请输入圆的半径:5
该圆的面积=78.53750000000001

这是一个正方形,请输入它的边长:5
该正方形的面积=25

你可能感兴趣的:(设计模式,Java,面试)