设计模式总结

原型模式


原型模式是浅拷贝,需要注意实体类中洪有对象、List等的拷贝,例如BeanUtils.copyProerties()方法
它可以直接操作内存中的二进制流,所以性能相对new实例化来说,尤其是大对象更佳

//定义学生类
class Student implements Cloneable{  
    private String name; //学生姓名
    private Teacher teacher; //定义老师类
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    } 

    public Teacher getTeacher() {  
        return teacher;  
    }  
  
    public void setTeacher(Teacher teacher) {  
        this.teacher = teacher;  
    } 
   //重写克隆方法
   public Student clone() { 
        Student student = null; 
        try { 
            student = (Student) super.clone(); 
            } catch (CloneNotSupportedException e) { 
            e.printStackTrace(); 
            } 
            return student; 
   } 
      
}  

//定义老师类
class Teacher implements Cloneable{  
    private String name;  //老师姓名
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name= name;  
    } 

   //重写克隆方法,堆老师类进行克隆
   public Teacher clone() { 
        Teacher teacher= null; 
        try { 
            teacher= (Teacher) super.clone(); 
            } catch (CloneNotSupportedException e) { 
            e.printStackTrace(); 
            } 
            return student; 
   } 
      
}
public class Test {  
      
    public static void main(String args[]) {
        Teacher teacher = new Teacher (); //定义老师1
        teacher.setName("刘老师");
        Student stu1 = new Student();  //定义学生1
        stu1.setName("test1");           
        stu1.setTeacher(teacher);
        
        Student stu2 = stu1.clone(); //定义学生2
        stu2.setName("test2");  
        stu2.getTeacher().setName("王老师");//修改老师
        System.out.println("学生" + stu1.getName + "的老师是:" + stu1.getTeacher().getName);  
        System.out.println("学生" + stu1.getName + "的老师是:" + stu2.getTeacher().getName);  
    }  
}
运行结果:

学生test1的老师是:王老师
学生test2的老师是:王老师
观察以上运行结果,我们可以发现:在我们给学生2修改老师的时候,学生1的老师也跟着被修改了。这就是浅拷贝带来的问题。

我们可以通过深拷贝来解决这种问题,其实深拷贝就是基于浅拷贝来递归实现具体的每个对象,代码如下:

   public Student clone() { 
        Student student = null; 
        try { 
            student = (Student) super.clone(); 
            Teacher teacher = this.teacher.clone();//克隆teacher对象
            student.setTeacher(teacher);
            } catch (CloneNotSupportedException e) { 
            e.printStackTrace(); 
            } 
            return student; 
   } 
适用场景

前面我详述了原型模式的实现原理,那到底什么时候我们要用它呢?

在一些重复创建对象的场景下,我们就可以使用原型模式来提高对象的创建性能。例如,我在开头提到的,循环体内创建对象时,我们就可以考虑用clone的方式来实现。

例如:

for(int i=0; i
我们可以优化为:

Student stu = new Student(); 
for(int i=0; i
除此之外,原型模式在开源框架中的应用也非常广泛。例如Spring中,@Service默认都是单例的。用了私有全局变量,若不想影响下次注入或每次上下文获取bean,就需要用到原型模式,我们可以通过以下注解来实现,@Scope(“prototype”)。


享元模式

//抽象享元类
interface Flyweight {
    //对外状态对象
    void operation(String name);
    //对内对象
    String getType();
}
//具体享元类
class ConcreteFlyweight implements Flyweight {
    private String type;

    public ConcreteFlyweight(String type) {
        this.type = type;
    }

    @Override
    public void operation(String name) {
        System.out.printf("[类型(内在状态)] - [%s] - [名字(外在状态)] - [%s]", type, name);
    }

    @Override
    public String getType() {
        return type;
    }
}
//享元工厂类
class FlyweightFactory {
    private static final Map FLYWEIGHT_MAP = new HashMap<>();//享元池,用来存储享元对象

    public static Flyweight getFlyweight(String type) {
        if (FLYWEIGHT_MAP.containsKey(type)) {//如果在享元池中存在对象,则直接获取
            return FLYWEIGHT_MAP.get(type);
        } else {//在响应池不存在,则新创建对象,并放入到享元池
            ConcreteFlyweight flyweight = new ConcreteFlyweight(type);
            FLYWEIGHT_MAP.put(type, flyweight);
            return flyweight;
        }
    }
}
public class Client {

    public static void main(String[] args) {
        Flyweight fw0 = FlyweightFactory.getFlyweight("a");
        Flyweight fw1 = FlyweightFactory.getFlyweight("b");
        Flyweight fw2 = FlyweightFactory.getFlyweight("a");
        Flyweight fw3 = FlyweightFactory.getFlyweight("b");
        fw1.operation("abc");
        System.out.printf("[结果(对象对比)] - [%s]", fw0 == fw2);
        System.out.printf("[结果(内在状态)] - [%s]", fw1.getType());
    }
}
输出结果:

[类型(内在状态)] - [b] - [名字(外在状态)] - [abc]
[结果(对象对比)] - [true]
[结果(内在状态)] - [b]
观察以上代码运行结果,我们可以发现:如果对象已经存在于享元池中,则不会再创建该对象了,而是共用享元池中内部数据一致的对象。这样就减少了对象的创建,同时也节省了同样内部数据的对象所占用的内存空间。

适用场景

享元模式在实际开发中的应用也非常广泛。例如Java的String字符串,在一些字符串常量中,会共享常量池中字符串对象,从而减少重复创建相同值对象,占用内存空间。代码如下:

String s1 = “hello”;
String s2 = “hello”;
System.out.println(s1==s2);//true
还有,在日常开发中的应用。例如,线程池就是享元模式的一种实现;将商品存储在应用服务的缓存中,那么每当用户获取商品信息时,则不需要每次都从redis缓存或者数据库中获取商品信息,并在内存中重复创建商品信息了。

原型模式、享元模式无论是在开源框架,还是在实际开发中,应用都十分广泛。

在不得已需要重复创建大量同一对象时,我们可以使用原型模式,通过clone方法复制对象,这种方式比用new和序列化创建对象的效率要高;在创建对象时,如果我们可以共用对象的内部数据,那么通过享元模式共享相同的内部数据的对象,就可以减少对象的创建,实现系统调优。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值