zoukankan      html  css  js  c++  java
  • 面向对象的设计模式(三),原型模式

    前言

     面向对象中的另外一个设计模式是原型(prototype)模式。这样的模式使用非常easy,使用的场合不是非常多。所以不是非经常常使用。

    定义:将一个对象实例设为原型。通过clone该原型实例得到新的一个实例。而不是通过new得到原型对象实例,这点java和C++的对象拷贝是一样的。

    适用场景:

    1、提升对象创建的效率。假设一个对象的创建比較复杂,须要消耗非常长的时间才干完毕该对象的创建,那么这个时候使用原型模式比較好。即通过一个已有该对象的实例克隆出一个新的实例而不是通过new。

    2、保护原型实例的安全。

    对于一个已经有的原型对象的实例。假设要操作该原型实例(读取数据),又要保证安全性,那么我们能够将该实例复制出一个新的实例给要读取该实例的client使用。而不是直接将该实例返回。

    这样client就无法更改原来那个对象的实例的数据了。

    原型模式的实现

    以java语言为例,原型模式的实现非常easy。以下模拟一个用户登录的过程来实现原型模式。

    1、原型对象,User.java

    public class User implements Cloneable{
    
        private String username;
        private String password;
        private Role role;
    
        public User(String username, String password) {
            this.username = username;
            this.password = password;
        }
    
        //.. -> setter
    
        @Override
        protected User clone(){
            User user = null;
            try {
                user = (User) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return user;
        }
    
        @Override
        public String toString() {
            return "User [username=" + username + ", password=" + password
                    + ", role=" + role + "]";
        }
    }

    须要注意的是clone方法是重写Object对象的。这里重写clone方法没有处理引用类型的复制,为浅复制。

    java对象的复制(须要实现Cloneable接口)

    1. 浅复制:没有对引用类型进行处理,这样会导致复制出来的对象,假设存在引用类型,那么复制出来的对象和原来的对象里面的引用类型对象指向的是同一个内存空间。
    2. 深复制:对引用类型也进行复制。这样能够使得克隆对象和原对象全然脱离关系,即怎么操作克隆对象都不会影响原对象。

    2、登录的Session。LoginSession.java

    public class LoginSession {
    
        private static User currentUser;
    
        public static void login(User user) {
            if (currentUser == null) {
                 currentUser = user;
                System.out.println("登录用户:"+currentUser);
            }
        }
    
        public static User getCurrentUser() {
            return currentUser.clone();
        }
    }

     注意:

    1. login()方法模拟用户实际登录的过程,用户实际登录则会在Session中加入一个登录的用户(原型实例)。

    2. getCurrentUser()不是返回原型实例。而是返回原型实例的克隆实例。这样保证了当前Session中登录的用户信息仅仅能由登录的时候决定,登录后不能改动用户名或者密码了。

      而这个克隆实例则给程序的其他地方使用(即使改变了里面的数据,原型实例中的数据也不变)。

    3、模拟用户从浏览器登录站点和其他地方操作登录的用户信息,Test.java

    public class Test {
    
        public static void main(String[] args) {
            User currentUser = new User("lt","123");
            currentUser.setRole(new Role("程序猿"));
            // 模拟登陆
            LoginSession.Login(currentUser);
            // 模拟其他地方操作当前登录用户的情况
            User clone = LoginSession.getCurrentUser();
            clone.setUsername("ydx");
            Role role = clone.getRole();
            role.setName("老板");
    
            System.out.println("cloneUser:"+clone);
            System.out.println("登录用户:"+currentUser);
        }
    }

    这是一个模拟用户登录和其他地方操作登录的用户的样例。以下我们执行看输出:

    这里写图片描写叙述

    其他地方得到当前登录的用户实例(实际上是一个克隆实例),并改动了克隆实例的用户名和角色信息,发现原型实例用户名没变而角色却变了。这里我们明明改的是克隆实例的信息,为什么原型实例角色信息却变了!

    这里涉及到了浅复制和深复制。

    我们对User的克隆方法改成以下这样并修重写Role的clone(注意须要实现CloneAble方法,否则克隆的时候会报CloneNotSupportedException异常)。

    改动后的User的clone()

    @Override
    protected User clone(){
        User user = null;
        try {
            user = (User) super.clone();
            user.setRole((Role) user.getRole().clone());
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return user;
    }
    

    重写了Role的clone方法。须要实现Cloneable接口(告诉外界这个对象能够被复制),Role无引用类型,浅复制和深复制一样。所以直接给个空的实现就可以。

    public class Role implements Cloneable{
        private String name;
    
        public Role(String name) {
            super();
            this.name = name;
        }
    
        //.. -> setter
    
        @Override
        public String toString() {
            return "Role [name=" + name + "]";
        }
    
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    }

    再次执行Test.java:

    这里写图片描写叙述

    能够看到我们改动了克隆实例的信息后,原型实例什么信息也没有改变。包含引用类型的对象信息也没变,这就是深复制和浅复制的差别。

    到此这个模拟过程结束,这个模拟过程保证了其他地方能够读取到原型实例的信息但无法影响原型实例信息。满足了我们安全性要求和逻辑须要。

    总结:原型模型的实现非常easy,就是对象的拷贝(克隆或复制),但我们要注意对象的克隆有深和浅之分。

  • 相关阅读:
    Spring Batch 之 Sample(XML文件操作)(五)
    Spring Batch 之 Spring Batch 简介(一)
    Spring Batch 之 Sample(固定长格式文件读写)(六)
    Spring Batch 之 Sample(复合格式文件的读、多文件的写)(七)
    bat调用jar包的两个典型问题
    Spring Batch 之 Sample(Hello World)(三)
    开园大吉
    js中createElement方法的兼容性
    Struts2中关于"There is no Action mapped for namespace / and action name"的总结
    Spring Batch 之 框架流程简单介绍(二)
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/7244564.html
Copyright © 2011-2022 走看看