Design Pattern: Prototype 模式-阿里云开发者社区

开发者社区> rollenholt> 正文

Design Pattern: Prototype 模式

简介:
+关注继续查看

一句话概括:用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。

您从图书馆的期刊从发现了几篇您感兴趣的文章,由于这是图书馆的书,您不可以直接在书中作记号或写字,所以您将当中您所感兴趣的几个主题影印出来,这下子您就可在影印的文章上画记重点。 
Prototype模式的作用有些类似上面的描述,您在父类别中定义一个clone()方法,而在子类别中重新定义它,当客户端对于所产生的物件有兴趣并想加以利用,而您又不想破坏原来的物件,您可以产生一个物件的复本给它。 
Prototype具有展示的意味,就像是展览会上的原型车款,当您对某个车款感兴趣时,您可以购买相同款示的车,而不是车展上的车。 
在软体设计上的例子会更清楚的说明为何要进行物件复制,假设您要设计一个室内设计软体,软体中有一个展示家具的工具列,您只要点选工具列就可以产生一个家 具复本,例如一张椅子或桌子,您可以拖曳这个复制的物件至设计图中,随时改变它的位置、颜色等等,当您改变设计图中的物件时,工具列上的原型工具列是不会 跟着一起改变的,这个道理是无需解释的。 
下面的 UML 类别图表示了上述的简单概念:

Prototype

Prototype模式的重点在于clone(),它负责复制物件本身并传回,但这个clone()本身在实作上存在一些困难,尤其是当物件本身又继承另一个物件时,如何确保复制的物件完整无误,在不同的程式语言中有不同的作法。 
在Java中的作法是透过实作一个Cloneable介面,它只是一个声明的介面,并无规定任何实作的方法,您的目的是改写Object的clone ()方法,使其具备有复制物件的功能,这个方面建议您参考:How to avoid traps and correctly override methods from java.lang.Object。 
用一个简单的例子来实作上图中的结构,这个例子利用了Java语言本身的clone特性:

AbstractFurniture.java

public abstract class AbstractFurniture 
                             implements Cloneable {
    public abstract void draw();
    
    // 在Design Pattern上,以下的clone是抽象未实作的
    // 实际上在Java中class都继承自Object
    // 所以在这边我们直接重新定义clone() 
    // 这是为了符合Java现行的clone机制
    protected Object clone() throws CloneNotSupportedException { 
        return super.clone(); 
    }
}

CircleTable与SquareTable继承了AbstractFurniture,并实作clone方法,用于传回本身的复制品:

  • CircleTable.java

import java.awt.*;

public class CircleTable extends AbstractFurniture {
    protected Point center;    
    
    public void setCenter(Point center) {
        this.center = center;
    }
    
    protected Object clone () 
                     throws CloneNotSupportedException { 
        Object o = super.clone(); 
        if(this.center != null) {
            ((CircleTable) o).center = (Point) center.clone();
        }
        
        return o; 
    } 

    public void draw() { 
        System.out.println("\t圆桌\t中心:(" + center.getX() 
                            + ", " + center.getY()+ ")");
    } 
}

SquareTable.java

import java.awt.*;

public class SquareTable extends AbstractFurniture {
    protected Rectangle rectangle;    
    
    public void setRectangle(Rectangle rectangle) {
        this.rectangle = rectangle;
    }
    
    protected Object clone () 
                      throws CloneNotSupportedException { 
        Object o = super.clone(); 
        if(this.rectangle != null) { 
            ((SquareTable) o).rectangle = (Rectangle) rectangle.clone();
        }
        
        return o; 
    } 

    public void draw() { 
        System.out.print("\t方桌\t位置:(" + rectangle.getX() 
                            + ", " + rectangle.getY()+ ")");
        System.out.println(" / 宽高:(" + 
                         rectangle.getWidth() 
                + ", " + rectangle.getHeight()+ ")");
    }
}

House是个虚拟的房屋物件,从Prototype复制出来的物件加入至House中:

  • House.java

import java.util.*;

public class House { 
    private Vector vector;

    public House() { 
        vector = new Vector(); 
    }

    public void addFurniture(AbstractFurniture furniture) { 
        vector.addElement(furniture); 
        
        System.out.println("现有家具....");
        
        Enumeration enumeration = vector.elements();
        while(enumeration.hasMoreElements()) { 
             AbstractFurniture f = 
                 (AbstractFurniture) enumeration.nextElement(); 
             f.draw(); 
        } 
        System.out.println(); 
    } 
}

再来是应用程式本身:

  • Application.java

import java.awt.*;

public class Application {
    private AbstractFurniture circleTablePrototype;
    
    public void setCircleTablePrototype(
                   AbstractFurniture circleTablePrototype) {
        this.circleTablePrototype = circleTablePrototype;
    }
    
    public void runAppExample() throws Exception {
        House house = new House(); 
        CircleTable circleTable = null;

        // 从工具列选择一个家具加入房子中
        circleTable =
            (CircleTable) circleTablePrototype.clone();
        circleTable.setCenter(new Point(10, 10));
        house.addFurniture(circleTable); 
        
        // 从工具列选择一个家具加入房子中
        circleTable = 
            (CircleTable) circleTablePrototype.clone();
        circleTable.setCenter(new Point(20, 30));
        house.addFurniture(circleTable); 
    }
    
    public static void main(String[] args) throws Exception {
        Application application = new Application();
        application.setCircleTablePrototype(
                            new CircleTable());
        application.runAppExample();
    }
}

Java中的clone()方法是继承自Object,AbstractFurniture的子类别则override这个clone()方法,以复制其本身并传回。 
下图为Prototype模式的类别结构图:


在 Gof 的设计模式书中给出一个原型模式的应用:一个通用的图型编辑器 Framework。在这个 Framework中有一个工具列,您可以在上面选择音乐符号以加入乐谱中,并可以随时调整音乐符号的位置等等。 
图型编辑器Framework是通用的,然而它并不知道这些音乐符号的型态,有人或许会想到继承图型编辑器Framework来为每个音乐符号设计一个框 架子类别,但由于音乐符号的种类很多,这会产生相当多的子类别,为了避免这种情况,可以透过Prototype模式来减少子类别的数目,可以设计出以下的 结构:


依照这个结构,图型编辑器的Framework可以独立于要套用的特定类别之外,虽然不知道被复制传回的对象型态是什么,但总可以按照 Graphics所定义的介面来操作这些物件。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
使用NAT网关轻松为单台云服务器设置多个公网IP
在应用中,有时会遇到用户询问如何使单台云服务器具备多个公网IP的问题。 具体如何操作呢,有了NAT网关这个也不是难题。
26797 0
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
10095 0
阿里云服务器ECS远程登录用户名密码查询方法
阿里云服务器ECS远程连接登录输入用户名和密码,阿里云没有默认密码,如果购买时没设置需要先重置实例密码,Windows用户名是administrator,Linux账号是root,阿小云来详细说下阿里云服务器远程登录连接用户名和密码查询方法
11638 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
10886 0
使用SSH远程登录阿里云ECS服务器
远程连接服务器以及配置环境
2512 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
13893 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
4664 0
+关注
406
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载