Prototype 原型模式

使用原型模式创建复杂对象
原型模式是一种在运行时创建新对象的设计模式,尤其适用于创建复杂的实例或避免创建工厂类层次。它允许通过克隆原型来创建新对象,减少了子类的构造。然而,它也存在违反开闭原则的缺点。在Java中,实现原型模式通常涉及实现Cloneable接口,覆盖clone()方法,并处理深拷贝与浅拷贝的区别。
一、意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。(Specify the kinds of objects to create using a prototypical instance, and create new objects by coping this prototype.)

通过复制一个原型的实例来创建新的对象,而不是新建新实例,被复制的实例称之谓原型

此时注意:原型模式是通过拷贝自身来创建新的对象,这一点和其他创建型模式不相同。


二、动机:当创建给定类的实例的过程很昂贵或很复杂时,就使用原型模式。
                                                                                                         ——Head First设计模式

场景:
你的交互式角色扮演游戏中,怪兽有着贪得无厌的胃口。当英雄人物在动态创建的场景中闯荡时,遇到了庞大的敌军有待歼灭。你希望怪兽的特征能够随着场景的变幻而演化。毕竟,如果让鸟一般的怪兽跟随你的角色进入海底世界,实在是没有道理。最后,你还希望能够让高级用户创建他们自己的怪兽。



三、适用性

1.适用于创建复杂的实例

2.当要实例化的类是在运行时指定的:如动态装载时

3.或者为了避免创建一个与产品类层次平行的工厂类层次时(只需要克隆原型,而不需要克隆工厂!)

4.或者当一个类的实例只能有几个不同状态组合中的一种时:建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化类更方便一些


四、结构



五、参与者:

prototype
     声明一个克隆自身的接口

concreteprototype
    实现一个克隆自身的操作

client
    让一个原型克隆自身从而创建一个新的对象

六、协作:

客户请求一个原型克隆自身

七、效果:

优点:
           运行时刻增加和删除产品
           灵活创建新的对象
           减少子类的构造
缺点:
           违反开闭原则
           每个类都必须实现clone操作

八、实现:

使用一个原型管理器
实现克隆操作
       浅拷贝
       深拷贝
初始化克隆对象


原型管理器:


public class PrototypeManager {
    /**
     * 用来记录原型的编号和原型实例的对应关系
     */
    private static Map map = new HashMap();
    /**
     * 私有化构造方法,避免外部创建实例
     */
    private PrototypeManager(){}
    /**
     * 向原型管理器里面添加或是修改某个原型注册
     * @param prototypeId 原型编号
     * @param prototype    原型实例
     */
    public synchronized static void setPrototype(String prototypeId , Prototype prototype){
        map.put(prototypeId, prototype);
    }
    /**
     * 从原型管理器里面删除某个原型注册
     * @param prototypeId 原型编号
     */
    public synchronized static void removePrototype(String prototypeId){
        map.remove(prototypeId);
    }
    /**
     * 获取某个原型编号对应的原型实例
     * @param prototypeId    原型编号
     * @return    原型编号对应的原型实例
     * @throws Exception    如果原型编号对应的实例不存在,则抛出异常
     */
    public synchronized static Prototype getPrototype(String prototypeId) throws Exception{
        Prototype prototype = map.get(prototypeId);
        if(prototype == null){
            throw new Exception("您希望获取的原型还没有注册或已被销毁");
        }
        return prototype;
    }
}

深复制vs浅复制


public class Client {
public static void main( String[] args ){
       Report report=new Report();
        Product product=new Product();
        product.setModel(1);
        product.setName("productName");
        report.setName("产品报表");
        report.setProduct(product);
        System.out.println(report.getName()+"|"+report.getProduct().getName());
        Report report1=(Report)report.clone();
        report1.setName("产品报表组1");
        report1.getProduct().setName("产品1");
        System.out.println(report1.getName()+"|"+report1.getProduct().getName());
        System.out.println(report.getName()+"|"+report.getProduct().getName());
    }
    
}
public class Product implements Cloneable{
    private String name;
    private int model;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getModel() {
        return model;
    }
    public void setModel(int model) {
        this.model = model;
    }
    @Override
    protected Object clone()  {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
public class Report implements Cloneable{

    private String name;
    private Product product;
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public Product getProduct() {
        return product;
    }
    public void setProduct(Product product) {
        this.product = product;
    }
    @Override

 protected Object clone()  {
        Report report;
        try {
             return  super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }

}

深复制的实现:

将Report的clone方法重写:

    protected Object clone()  {
        Report report;

        try {
            report=(Report) super.clone();
            report.setProduct((Product)product.clone());
            return report;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }

九、代码示例:

java中对象克隆的实现:


可以利用Object类的clone()方法


1、对象类实现Coneable接口


2、覆盖实现clone()方法


3、调用super.clone(),实现克隆。


public class Prototype {
public interface IUIBox extends Cloneable {
	void showMessage(String msg);
	IUIBox createClone();
}
//信息框
//警告框
//错误框
    public static void main(String[] args) throws Exception {
        //创建阶段
	SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
	System.out.println(sdf.format(new Date()) + ": begin to register ...");
	MessageBox.register("information", new InformationBox());
	MessageBox.register("warning", (IUIBox) new WarningBox());
	MessageBox.register("error", (IUIBox) new ErrorBox());
	System.out.println(sdf.format(new Date()) + ": end");
	//原型拷贝并显示
	System.out.println(sdf.format(new Date()) + ": begin to show ...");
	MessageBox.show("information", "Connected to the network!");
	MessageBox.show("warning", "Confirm to truncate table?");
	MessageBox.show("error", "Access denied!");
	System.out.println(sdf.format(new Date()) + ": end");
    }
}

public class MessageBox {
   // 原型管理器
    	private static Map protoMap = new HashMap();//用来记录原型的编号和原型实例的对应关系

	//原型登录
        private MessageBox(){}//私有化构造方法,避免外部创建实例
        public static void register(String key, IUIBox box) {
		protoMap.put(key, box); //向原型管理器里面添加或是修改某个原型注册
	}
        //产生拷贝并显示消息
	public static void show(String key, String msg) throws Exception {
		IUIBox box = (IUIBox) protoMap.get(key);//获取某个原型编号对应的原型实例
		box.createClone().showMessage(msg);
                if(box == null){
                    throw new Exception("您希望获取的原型还没有注册或已被销毁");
                }
	}
    
}


//信息框

public class InformationBox implements Prototype.IUIBox {
    public InformationBox() {
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	@Override
	public void showMessage(String msg) {
		int len = msg.length();
		System.out.println("Information ");
		for (int i = 0; i < len + 6; i++) {
			System.out.print("/");
		}
		System.out.println();
		System.out.println("// " + msg + " //");
		for (int i = 0; i < len + 6; i++) {
			System.out.print("/");
		}
		System.out.println();
		System.out.println();
	}
	@Override
	public Prototype.IUIBox createClone() {
		try {
			return (Prototype.IUIBox)clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
			return null;
		}
	}
}


//警告框

public class WarningBox implements Prototype.IUIBox{
    	public WarningBox() {
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	@Override
	public void showMessage(String msg) {
		int len = msg.length();
		System.out.println("Warning ");
		for (int i = 0; i < len + 4; i++) {
			System.out.print("*");
		}
		System.out.println();
		System.out.println("* " + msg + " *");
		for (int i = 0; i < len + 4; i++) {
			System.out.print("*");
		}
		System.out.println();
		System.out.println();
	}
	@Override
	public Prototype.IUIBox createClone() {
		try {
			return (Prototype.IUIBox)clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
			return null;
		}
	}
    
}


//错误框

public class ErrorBox  implements Prototype.IUIBox{
    public ErrorBox() {
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	@Override
	public void showMessage(String msg) {
		int len = msg.length();
		System.out.println("Error ");
		for (int i = 0; i < len + 4; i++) {
			System.out.print("X");
		}
		System.out.println();
		System.out.println("X " + msg + " X");
		for (int i = 0; i < len + 4; i++) {
			System.out.print("X");
		}
		System.out.println();
		System.out.println();
	}
	@Override
	public Prototype.IUIBox createClone() {
		try {
			return (Prototype.IUIBox)clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
			return null;
		}
	}
    
}

十、相关模式:
 Prototype 和Abstract Factory模式在某种方面是相互竞争的。
但是它们也可以一起使用。


  Singleton单件模式解决的问题是:实体对象个数问题(这个现在还不太容易混)用于创建必须唯一的实例
       
         FactoryMethod工厂方法模式解决的问题是:某个对象的创建工作 用于创建独立的、相互无关的大量对象


         AbstractFactory抽象工厂模式解决的问题是:“一系列互相依赖的对象”的创建工作  用于成套的对象的创建


         Builder生成器模式解决的问题是:“一些复杂对象”的创建工作,子对象变化较频繁,对算法相对稳定 用于创建步骤稳定,但元素易变的复杂对象


         Prototype原型模式:用于创建大量相同或相似的对象


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值