设计模式第8篇:享元设计模式

Posted quxiangxiangtiange

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式第8篇:享元设计模式相关的知识,希望对你有一定的参考价值。

一.享元设计模式要解决的问题

  享元设计模式是一种结构设计模式,当我们要创建同一个类的大量对象时,可以考虑享元设计模式。由于每一个对象都会消耗内存空间,享元设计模式通过共享对象达到降低内存消耗。

二.享元设计模式的要点

  1.需要创建的对象数量特别巨大。

  2.对象创建占用内存大且耗时。

  3.对象属性可以分为内部属性和外部属性,对象的外部属性应由客户端程序定义。

  为了使用享元设计模式,我们需要将对象属性分为内部属性和外部属性,内部属性使该对象保持唯一性,外部属性由客户端程序定义并通常用来执行一些不同的操作。为了应用享元设计模式,我们需要创建一个返回共享对象的享元工厂。例如我们需要画直线和椭圆,首先我们有一个形状接口Shape以及它的两个实现Line和Oval,Oval类有一个内部属性,该属性决定是否用给椭圆填充颜色,Line没有内部属性。

三.享元设计模式代码用例

  1.Shape接口及其实现类Line和Oval

import java.awt.Color;
import java.awt.Graphics;
interface Shape {

    public void draw(Graphics g, int x, int y, int width, int height,
            Color color);
}
class Line implements Shape {

    public Line(){
        System.out.println("Creating Line object");
        //添加延时,模拟创建对象需要耗大量时间
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void draw(Graphics line, int x1, int y1, int x2, int y2,
            Color color) {
        line.setColor(color);
        line.drawLine(x1, y1, x2, y2);
    }
}
class Oval implements Shape {
    
    //intrinsic property
    private boolean fill;
    
    public Oval(boolean f){
        this.fill=f;
        System.out.println("Creating Oval object with fill="+f);
        //添加延时,模拟创建对象需要耗大量时间
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void draw(Graphics circle, int x, int y, int width, int height,
            Color color) {
        circle.setColor(color);
        circle.drawOval(x, y, width, height);
        if(fill){
            circle.fillOval(x, y, width, height);
        }
    }
}

  2.享元工厂类ShapeFactory.class

  享元工厂类是给客户端程序使用来实例化对象,所以需要在工厂类中保存一个客户端应用程序不应该访问的对象映射,当客户端调用工厂类来获得实例化的对象时,都应该从这个对象映射集合中取得,当集合中没有需要的对象时便创建一个新的对象并添加到该集合中,然后返回该对象给客户端程序使用,这样当再次需要该对象时可以直接从该集合中取出。

class ShapeFactory {

    private static final HashMap<ShapeType,Shape> shapes = new HashMap<ShapeType,Shape>();

    public static Shape getShape(ShapeType type) {
        Shape shapeImpl = shapes.get(type);

        if (shapeImpl == null) {
            if (type.equals(ShapeType.OVAL_FILL)) {
                shapeImpl = new Oval(true);
            } else if (type.equals(ShapeType.OVAL_NOFILL)) {
                shapeImpl = new Oval(false);
            } else if (type.equals(ShapeType.LINE)) {
                shapeImpl = new Line();
            }
            shapes.put(type, shapeImpl);
        }
        return shapeImpl;
    }
    
    public static enum ShapeType{
        OVAL_FILL,OVAL_NOFILL,LINE;
    }
}

  3.模拟客户端程序使用享元工厂类

  运行下面的程序可以发现,当画第一条直线以及第一个填充颜色或者不填充颜色的椭圆时程序有明显延时,之后再次点击“draw”时画图操作无延时,主要是因为之后都共享了之前创建的对象。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import com.journaldev.design.flyweight.ShapeFactory.ShapeType;

public class DrawingClient extends JFrame{

    private static final long serialVersionUID = -1350200437285282550L;
    private final int WIDTH;
    private final int HEIGHT;

    private static final ShapeType shapes[] = { ShapeType.LINE, ShapeType.OVAL_FILL,ShapeType.OVAL_NOFILL };
    private static final Color colors[] = { Color.RED, Color.GREEN, Color.YELLOW };
    
    public DrawingClient(int width, int height){
        this.WIDTH=width;
        this.HEIGHT=height;
        Container contentPane = getContentPane();

        JButton startButton = new JButton("Draw");
        final JPanel panel = new JPanel();

        contentPane.add(panel, BorderLayout.CENTER);
        contentPane.add(startButton, BorderLayout.SOUTH);
        setSize(WIDTH, HEIGHT);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);

        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent event) {
                Graphics g = panel.getGraphics();
                for (int i = 0; i < 20; ++i) {
                    Shape shape = ShapeFactory.getShape(getRandomShape());
                    shape.draw(g, getRandomX(), getRandomY(), getRandomWidth(),
                            getRandomHeight(), getRandomColor());
                }
            }
        });
    }
    
    private ShapeType getRandomShape() {
        return shapes[(int) (Math.random() * shapes.length)];
    }

    private int getRandomX() {
        return (int) (Math.random() * WIDTH);
    }

    private int getRandomY() {
        return (int) (Math.random() * HEIGHT);
    }

    private int getRandomWidth() {
        return (int) (Math.random() * (WIDTH / 10));
    }

    private int getRandomHeight() {
        return (int) (Math.random() * (HEIGHT / 10));
    }

    private Color getRandomColor() {
        return colors[(int) (Math.random() * colors.length)];
    }

    public static void main(String[] args) {
        DrawingClient drawing = new DrawingClient(500,600);
    }
}

四.享元设计模式的注意点

 当对象的内部属性非常多时最好不要考虑享元设计模式,因为此时设计工厂类会非常复杂。

Java中使用享元设计模式:java包装器类中的valueOf()方法以及String类。

 

以上是关于设计模式第8篇:享元设计模式的主要内容,如果未能解决你的问题,请参考以下文章

从零开始学习Java设计模式 | 结构型模式篇:享元模式

从零开始学习Java设计模式 | 结构型模式篇:享元模式

结构篇-享元模式

Flyweight享元模式(结构型模式)

第8篇-JAVA面向对象-设计模式Ⅳ

大话设计模式Python实现- 享元模式