package com.Mapking;
/**
* JAVA设计模式:原型--复制建立对象实例
* 有了Product 接口 才可能进行复制。
* 这个接口继承java.lang.Cloneable接口。
* 利用clone方法可自动对实现此接口的类进行复制。
* use方法是“使用”的部分,“使用”代表何种意义需看子类的实现。
* createCone方法则负责复制对象实例的部分。
* @author Administrator
*/
public interface Product extends Cloneable
{
public abstract void use(String s);
public abstract Product createClone();
}
============================================
package com.Mapking;
import java.util.Hashtable;
/**
* 本类是利用Product类接口进行对象实例复制的类。
* showcase字段 以java.util.Hashtable表示对象实例“名称”跟“对象实例”两者间的对应关系。
* 当系统以register方法把产品名称和Product接口传递过来之后,其中1组数据会注册到showcase。
* 在此传递给参数的Product类型proto是什么呢?
* 虽然不了解它的实际类,不过它一定是实现了Product接口的类的对象实例
* (也就是可以调用use方法和createClone方法的对象实例)。
* 请注意:在Product接口和Manager类的源代码中完全没有出现 MessageBox类或UnderlinePen类的类名。
* 没有类名代表着 Product跟Manager可以跟这些类分开单独修改,这点非常重要。
* 如果类名被写在源代码内,它就会跟该类发生密切的关系。
* Manager类没有一一写出所有的类名,只用到Product这个接口名称。
* 所以这个接口是Manager类跟其他类沟通的惟一桥梁。
*
* @author Administrator
*/
public class Manager
{
private Hashtable showcase = new Hashtable();
public void register(String name, Product proto)
{
showcase.put(name,proto);
}
public Product create(String protoname)
{
Product p = (Product)showcase.get( protoname );
return p.createClone();
}
}
=============================================
package com.Mapking;
/**
*
* createClone方法是复制本身的方法。
* 这里所调用的clone方法规定在java语言规格内,它会产生另一个分身(本身的复制品)。
* 在产生复制品时,若该字段包含对象实例,则其值也会跟着复制到新的对象实例。
* 能利用clone方法进行复制的只限于实现java.lang.Cloneable接口的类。
* 如果该类没有实现此接口,则会抛出异常CloneNotSupportedException,所以必须try...catch捕捉。
* MessagerBox类只实现Product接口而已,不过因为Product接口本身就是从java.lang.Cloneable接口扩充出来的,
* 所以不会有这个异常产生。
* 另外,java.lang.Cloneable接口只有标识作用,没有声明此接口的方法。
*
* java语言的clone方法只能从本身的类(含子类)调用,所以如果是因其他类的要求进行复制时,
* 则须另以其它方法(如createClone)把clone抓进来。
*
* @author Administrator
*/
public class MessageBox implements Product
{
private char decochar;
public MessageBox(char decochar)
{
this.decochar = decochar;
}
public void use(String s)
{
int length = s.getBytes().length;
for(int i = 0; i < length + 4; i++)
{
System.out.print( decochar );
}
System.out.println( "" );
System.out.println( decochar + "" + s + "" + decochar );
for(int i = 0; i < length +4; i++)
{
System.out.print( decochar );
}
System.out.println( "" );
}
public Product createClone()
{
Product p = null;
try
{
p = (Product)clone();
}
catch(CloneNotSupportedException e)
{
e.printStackTrace();
}
return p;
}
}
============================================
package com.Mapking;
/**
* 本类和MessageBox类相似
* @author Administrator
*/
public class UnderlinePen implements Product
{
private char ulchar;
public UnderlinePen(char ulchar)
{
this.ulchar = ulchar;
}
public void use( String s )
{
int length = s.getBytes().length;
System.out.println( "\"" + s + "\"");
System.out.println( "" );
for(int i = 0; i < length; i++)
{
System.out.print( ulchar );
}
System.out.println( "" );
}
public Product createClone()
{
Product p = null;
try
{
p = (Product)clone();
}
catch(CloneNotSupportedException e)
{
e.printStackTrace();
}
return p;
}
}
=============================================
package com.Mapking;
/**
* JAVA设计模式:原型--复制建立对象实例
*
* 先产生Manager的对象实例,
* 然后再把UnderlinePen的对象实例MessageBox的对象实例(含名称)注册到Manager的对象实例中.
* @author Administrator
*/
public class Main
{
public static void main(String[] args)
{
//预备阶段
Manager manager = new Manager();
UnderlinePen upen = new UnderlinePen('~');
MessageBox mbox = new MessageBox('*');
MessageBox sbox = new MessageBox('/');
manager.register( "strong message", upen);
manager.register( "warning box", mbox);
manager.register( "slash box", sbox);
//实现产生
Product p1 = manager.create( "strong message");
p1.use( "Hello world.");
Product p2 = manager.create( "warning box");
p2.use( "Hello world.");
Product p3 = manager.create( "slash box");
p3.use( "Hello world.");
}
}
==========================================
run:
"Hello world."
~~~~~~~~~~~~
****************
*Hello world.*
****************
/Hello world./
成功生成(总时间:0 秒)
=============================================
适用:
(1)种类过多无法整合成类时
程序示例出现过下面3种雏形:
a.以'~'把字符串加上下划线;
b.以'*'把字符串加上边框;
c.以'/'把字符串加上边框。
这些例子都属于简单型,虽然雏形只列出3种,只要有心的话还可以多做几种。但是如果全部都要做不同的类,类数量会增加,同时增加程序了程序源代码管理的困难度。
(2)不容易利用类产生对象实例时
在本程序中可能不太明显,不过,你可以想象一下作图的操作。如果把这个操作跟几乎全以鼠标辅助操作的绘图软件联想起来,应该会比较容易理解。
假设有一个表示原来以人工操作方式绘制图形的对象实例,而现在要建立一个完全相同的新对象实例。在这种情形下,利用对象实例复制的方式当然会比从头用类来产生对象实例要简单得多。
(3)希望把框架和所产生的对象实例分开时
程序示例把执行对象实例复制(clone)的部分放在com.mapKing.framework程序包内。
产生对象实例时当然要传递类名给Manager类的create方法,不过这里以"strong message"和"slash box"取代。这可以说是加强广泛应用JAVA语言原本就有的对象实例产生的架构 new Something()的格式,而让框架脱离类名称的束缚。
类名是一种束缚!
话说回来,如果硬把类名塞到程序源代码内会发生什么问题呢?把程序中利用到的类名写在里面不是理所当然的吗?
在这里,要请各位回忆一下面向对象程序设计的几个使用目的,"零件化复用"正是其中之一。
事先把源代码用到的类名写来这个操作,也不见得就是一定错。但是当你写下源代码内所用到的类名的那一刻起,它就无法跟该类分享供你复用了。
当然只要动手修改源代码就可以改掉类名称,不过从"零件化复用"的角度来说,根本不考虑修改源代码。
谈到JAVA,"即使手中只有类文件(.class),可否复用该类?"这个概念相当重要。说到重点了,对,就是"即使没有源文件(.java),可否予以复用?"。
必须紧密结合在一起的类名写到源代码内是理所当然的,根本不成问题;
真正问题是应该分享独立成零件的类名却被写到源代码里面了。