买了大神关爱民与何红辉所著书籍《设计模式解析与实战》,观后有所感、有所悟。
所谓的原型模式我更喜欢叫它复制拷贝,调用简单,通过类实现Cloneable空接口(该接口是一个标识接口,表示该类可以拷贝,如果不实现该接口,将会抛出异常)调用clone方法拷贝。性能比new 更好,但是开发中需要注意clone方法不会执行类的构造方法。下面看一段代码实例:
public class User implements Cloneable{
private String userName;
private String password;
private String icon;
private ArrayList<Image> mImageList=new ArrayList<Image>();
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public ArrayList<Image> getmImageList() {
return mImageList;
}
public void setmImageList(ArrayList<Image> mImageList) {
this.mImageList = mImageList;
}
public void addImage(Image mImage){
this.mImageList.add(mImage);
}
@Override
protected User clone() throws CloneNotSupportedException {
return (User) super.clone();
}
@Override
public String toString() {
return "User [userName=" + userName + ", password=" + password
+ ", icon=" + icon + ", mImageList=" + mImageList + "]";
}
}
测试代码:
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
User mUser=new User();
mUser.setIcon("xxxxx/icon/xxx.jpg");
mUser.setPassword("password123");
mUser.setUserName("usernameadmin");
Image mImage=new Image();
mImage.setImageUrl("image123434.jpg");
mImage.setName("imageName12334");
mImage.setUploadTime("2015-09-20 12:13:14");
mUser.addImage(mImage);
System.out.println("原型拷贝前:-----"+mUser.toString()+"\n");
User cloneUser=mUser.clone();
System.out.println("原型拷贝前:-----"+mUser.toString());
System.out.println("原型拷贝后:-----"+cloneUser.toString()+"\n");
cloneUser.setPassword("123456");
System.out.println("修改拷贝后原型:-----"+mUser.toString());
System.out.println("修改拷贝后cloneUser:-----"+cloneUser.toString()+"\n");
}
}
测试结果:
原型拷贝前:-----User [userName=usernameadmin, password=password123, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
原型拷贝前:-----User [userName=usernameadmin, password=password123, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
原型拷贝后:-----User [userName=usernameadmin, password=password123, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
修改拷贝后原型:-----User [userName=usernameadmin, password=password123, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
修改拷贝后cloneUser:-----User [userName=usernameadmin, password=123456, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
通过上述测试代码和结果,可以发现,调用clone方法拷贝了一份一模一样的对象,修改原型的值(simple:int)不会影响原型数据,即浅拷贝。再看一段代码测试结果:
Image mImage2=new Image();
mImage2.setImageUrl("image123434.jpg");
mImage2.setName("imageName12334");
mImage2.setUploadTime("2015-09-20 12:13:14");
cloneUser.addImage(mImage2);
原型拷贝前:-----User [userName=usernameadmin, password=password123, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
原型拷贝前:-----User [userName=usernameadmin, password=password123, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
原型拷贝后:-----User [userName=usernameadmin, password=password123, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
修改拷贝后原型:-----User [userName=usernameadmin, password=password123, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg], Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
修改拷贝后cloneUser:-----User [userName=usernameadmin, password=123456, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg], Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
观察上面结果,发现修改mImageList后原型同时被修改了,造成这个问题的解决办法就需要用到深拷贝,即再拷贝对象时,对于引用字段也要采取拷贝形式,不只是单纯的引用的形式,clone方法修改如下:
@Override
protected User clone() throws CloneNotSupportedException {
User mCloneUser=(User) super.clone();
mCloneUser.setmImageList((ArrayList<Image>) this.mImageList.clone());
return mCloneUser;
}
结果如下:
原型拷贝前:-----User [userName=usernameadmin, password=password123, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
原型拷贝前:-----User [userName=usernameadmin, password=password123, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
原型拷贝后:-----User [userName=usernameadmin, password=password123, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
修改拷贝后原型:-----User [userName=usernameadmin, password=password123, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
修改拷贝后cloneUser:-----User [userName=usernameadmin, password=123456, icon=xxxxx/icon/xxx.jpg, mImageList=[Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg], Image [uploadTime=2015-09-20 12:13:14, name=imageName12334, imageUrl=image123434.jpg]]]
在源码中该模式应用的范围也挺广的,Simple ArrayList:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
.............此处略.............
/**
* Returns a shallow copy of this <tt>ArrayList</tt> instance. (The
* elements themselves are not copied.)
*
* @return a clone of this <tt>ArrayList</tt> instance
*/
public Object clone() {
try {
@SuppressWarnings("unchecked")
ArrayList<E> v = (ArrayList<E>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError();
}
}
}
下面是一个简单的登录实战实例:
public class User {
private String userName;
private String password;
/**登录成功后返回的信息*/
private UserSession mUserSession=new UserSession();
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public UserSession getUserSession() {
return mUserSession;
}
public void setUserSession(UserSession mUserSession) {
this.mUserSession = mUserSession;
}
@Override
protected User clone(){
User cloneUser=null;
try {
cloneUser = (User) super.clone();
cloneUser.setUserSession(this.mUserSession);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return cloneUser;
}
}
接口定义(别问我为什么要这么定义接口,想知道就去看高老师视频吧,我不会告诉你的):
/**
* 用户接口
* @author LanYan
*
*/
public interface OnAccountListener {
/**
* 登录结果回调接口
*/
interface OnLoginCallback{
/**
* 登录成功
* @param mUserSession
*/
void onLoginSuccess(UserSession mUserSession);
/**
* 登录失败
* @param e
* @param code
* @param message
*/
void onLoginFail(Exception e,int code,String message);
}
/**
* 登录接口
*/
interface OnLoginListener{
/**
* 登录方法传入参数 用户名 和登录密码
* @param userName
* @param password
* @param onLoginCallback
*/
void onLogin(String userName,String password,OnLoginCallback onLoginCallback);
}
/**
* http请求成功后如果需要数据同步,就调用此方法
*/
interface OnSyncListener{
/**
* 同步方法
* @param mUserSession
*/
void sync(UserSession mUserSession);
}
}
登录实现类:
import clonable.simple.OnAccountListener;
public class UserImpl implements OnAccountListener.OnLoginListener ,OnAccountListener.OnSyncListener{
private static UserImpl instance;
public static UserImpl getInstance() {
if(instance==null){
synchronized (UserImpl.class) {
instance=new UserImpl();
}
}
return instance;
}
@Override
public void onLogin(String userName, String password,
OnAccountListener.OnLoginCallback onLoginCallback) {
............此处略...............
}
@Override
public void sync(UserSession mUserSession) {
............此处略...............
}
}
下面是测试代码:
public class LoginTest{
static User mCloneUser;
public static void main(String[] args) {
User mUser=new User();
mUser.setUserName("admin");
mUser.setPassword("123456");
mCloneUser=mUser.clone();
UserImpl.getInstance().onLogin(mCloneUser.getUserName(),mCloneUser.getPassword(),new OnLoginCallback() {
@Override
public void onLoginSuccess(UserSession mUserSession) {
mCloneUser.setUserSession(mUserSession);
UserImpl.getInstance().sync(mUserSession);
}
@Override
public void onLoginFail(Exception e, int code, String message) {
}
});
}
}
OnAccountListener类还可以扩展注册、注销、修改用户信息等方法,原型模式就到这里了,逗比要去学重构啦啦啦。
本文解析了设计模式中的原型模式,介绍了其基本概念与实现方式,并通过具体示例对比了浅拷贝与深拷贝的区别。

407

被折叠的 条评论
为什么被折叠?



