在我上次写过的关于Flyweight设计模式的文章中,通过Flyweight模式的运用,已经达到了共享元类的目的.但进一步深入探讨上一次的实现过程,在对象的安全性方面将会发现一些问题:
由于Student类中,学生的学号与姓名在整个对象的生命周期中都是不可变的,且每一个学号应只能对应一个姓名,所以我们应该除了在工厂类的静态初始代码块中通过初始化创建Student类的信息之外,应该保证在外界不能随便地再去创建或篡改Student的信息.
而我们上次的实现当中Student类是一个public的类,在StuScore类中就可以随意地进行访问与创建Student对象.这与我们的目的相违背.
所以应该对上次的设计模式进行改进.在改进后的设计模式中,我们的实现应该做到,只能在工厂类中通过静态代码块创建Student类的实例,且将它们保存在工厂类的Hashtable中,且外部将不能篡改Student的信息.
因为只有工厂类才能创建Student对象,所以可以考虑把其作为工厂类的私有内部类.这样外部将不可能创建Student的实例.但注意到如果只采用此种方式进行实现,外部即StuScore类将不可能通过两个get方法获得学生的姓名与学号信息.此时为了解决这种矛盾,可以采用在外界定义一个Student接口,在接口中定义分别获得学生学号姓名信息的方法,然后由工厂类里的内部类StudentImpl实现Student接口,这样就可完美地实现即只在工厂内内部创建学生对象,又可在外部访问学生对象信息的功能.
以下是改进后的各个类的代码:
StuScore类代码如下:
package org.xqq.flyweight;
public class StuScore { private Student student; private String course; private int score;
public StuScore(String stuNum,String course,int score) { this.course=course; this.score=score; this.student=StudentFactory.getStudent(stuNum); }
public String getCourse() { return course; } public int getScore() { return score; }
public String getStuName() { return student.getStuName(); } public String getStuNum() { return student.getStuNum(); } } |
Student接口代码如下
package org.xqq.flyweight;
//Student接口定义取得学生各种信息的行为 public interface Student { String getStuName();//获取学生姓名 String getStuNum();//获取学生学号 } |
工厂类StudentFactory的代码如下:
package org.xqq.flyweight;
import java.util.Hashtable;
public class StudentFactory {
private static Hashtable stuTable=new Hashtable();
static { StudentFactory factory=new StudentFactory(); stuTable.put("AP0501", factory.new StudentImpl("AP0501","张三")); stuTable.put("AP0502", factory.new StudentImpl("AP0502","李四")); stuTable.put("AP0503", factory.new StudentImpl("AP0503","王五")); } //内部类StudentImpl包括学生的各属性,实现了Student接口 private class StudentImpl implements Student { private String stuName;//学生姓名 private String stuNum;//学生学号 public StudentImpl(String stuName, String stuNum) { this.stuName = stuName; this.stuNum = stuNum; } public String getStuName() { // TODO Auto-generated method stub return stuName; } public String getStuNum() { // TODO Auto-generated method stub return stuNum; } } //从工厂类中取得特定的学生信息 public static Student getStudent(String stuNum) { Student student=(Student) stuTable.get(stuNum); return student; } } |
然后利用StudentTest的代码进行测试,可得到与上篇文章一样的结果,于是经过改进的FlyWeight设计模式得以实现.