天天看点

设计模式(10)之享元模式

1. 什么是享元模式

Flyweight模式也叫享元模式,是构造型模式之一,它通过与其他类似对象共享数据来减小内存占用。

2.享元模式的结构

设计模式(10)之享元模式

3.享元模式的角色和职责

抽象享元角色:

所有具体享元类的父类,规定一些需要实现的公共接口。

具体享元角色:

抽象享元角色的具体实现类,并实现了抽象享元角色规定的方法。

享元工厂角色: 负责创建和管理享元角色。

先来个简单的例子。大体是这样的:现在要存储”a”,”b”,”c”,”d”四个字符,如果一个字符用一个对象存储,当然要4个对象,因为每个字符都不相同嘛。但是如果存储”a”,”b”,”a”,”d”四个字符,应该要几个对象就能存储,当然要3个对象就够了。现在,我们看看是如何实现的。

首先定义存储字符的类:

//MyCharacter.java

public class MyCharacter {

    private char mychar;

    public MyCharacter(char mychar){
        this.mychar = mychar;
    }

    public void display(){
        System.out.println(this.mychar);
    }
}
           

如果一个字符存储在一个对象中,不区分相同的字符,那么大概是下面这样子的。

//MainClass.java


public class MainClass {

    public static void main(String[] args) {
        MyCharacter mychar1 = new MyCharacter('a');
        MyCharacter mychar2 = new MyCharacter('b');
        MyCharacter mychar3 = new MyCharacter('a');
        MyCharacter mychar4 = new MyCharacter('d');

        mychar1.display();
        mychar2.display();
        mychar3.display();
        mychar4.display();


        if(mychar1 == mychar3)
            System.out.println("true");
        else
            System.out.println("false");
           

那么打印结果是:

a
b
a
d
false
           

这个,应该很好理解吧。mychar1 和 mychar2 两个都是new出来的,显示在堆上不是同一个对象。但是,他们的内容完全一样,按照我们的想法,他们应该是一样的,这样只需一份内存就可以了。

so,下面,我们创建一个工厂,专门生成MyCharacter对象,但是在生成的时候做些手脚,看代码:

//MyCharacterFactory.java
import java.util.HashMap;
import java.util.Map;

/**
 * 管理 MyCharacter
 */
public class MyCharacterFactory {

    private Map<Character,MyCharacter> pool;

    public MyCharacterFactory(){
        pool = new HashMap<Character, MyCharacter>();
    }

    public MyCharacter getMyCharacter(Character character){
        MyCharacter mychar = pool.get(character);

        if(mychar == null){
            mychar = new MyCharacter(character);
            pool.put(character, mychar);
        }

        return mychar;
    }
}
           

应该很好理解吧,MyCharacterFactory中维护了一个容器pool,该容器对MyCharacter对象进行管理,这样,在请求MyCharacter对象的时候,如果该对象不在pool中则new一个返回,再将该新对象加到pool容器中,如果请求的对象恰好在容器中,则直接取出返回就可以了。这样的好处就是,不会有数据冗余。

现在,客户端的代码就变成这样子了:

//MainClass.java

public class MainClass {

    public static void main(String[] args) {    
        MyCharacterFactory myfact = new MyCharacterFactory();

        MyCharacter mychar1 = myfact.getMyCharacter('a');
        MyCharacter mychar2 = myfact.getMyCharacter('b');
        MyCharacter mychar3 = myfact.getMyCharacter('a');
        MyCharacter mychar4 = myfact.getMyCharacter('d');

        mychar1.display();
        mychar2.display();
        mychar3.display();
        mychar4.display();

        if(mychar1 == mychar3)
            System.out.println("true");
        else
            System.out.println("false");
    }
}
           

打印结果是:

a
b
a
d
true
           

还觉得不过瘾,我们再来个例子。上面的例子和前面的享元模式结构图相比,省略了Flyweight基类的创建,而是直接给了个具体的子类MyCharacter,下面的例子,我们完全按照上面的结构图来:

首先定义基类Person:

//Person.java

package com.zemo.wj;

public class Person {
    private String name;
    private int age;
    private String sex;

    public Person(String name, int age, String sex) {
        super();
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public Person() {

    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
}
           

定义实现子类Teacher:

//Teacher.java

package com.zemo.wj;

public class Teacher extends Person {
    private String number;

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public Teacher(String name, int age, String sex,String number) {
        super(name, age, sex);
        this.number = number;
    }

    public Teacher() {
        super();
    }

}
           

定义创建子类的工厂,和前面例子的套路是一样一样的,都是维护一个容器对Teacher进行管理:

//TeacherFactory.java

package com.zemo.wj;

import java.util.HashMap;
import java.util.Map;

public class TeacherFactory {
    private Map<String,Teacher> pool;

    public TeacherFactory() {
        pool = new HashMap<String,Teacher>();
    }

    public Teacher getTeacher(String number) {
        Teacher teacher = pool.get(number);
        if(teacher == null) {
            teacher = new Teacher();
            teacher.setNumber(number);
            pool.put(number, teacher);
        }
        return teacher;
    }
}

           

再看客户端的实现:

//MainClass.java

package com.zemo.wj;

public class MainClass {
    public static void main(String[] args) {
        TeacherFactory factory = new TeacherFactory();
        Teacher teacher1 = factory.getTeacher("0102034");
        Teacher teacher2 = factory.getTeacher("0102035");
        Teacher teacher3 = factory.getTeacher("0102034");
        Teacher teacher4 = factory.getTeacher("0102037");

        System.out.println(teacher1.getNumber());
        System.out.println(teacher2.getNumber());
        System.out.println(teacher3.getNumber());
        System.out.println(teacher4.getNumber());

        if(teacher1 == teacher3) {
            System.out.println("true");
        } else {
            System.out.println("false");
        }
    }
}
           

最后打印结果:

true
           

继续阅读