Поиск по сайту:

Шаблон проектирования легковеса в Java


Сегодня мы рассмотрим шаблон проектирования Flyweight.

Шаблон проектирования легковеса

Согласно GoF, целью шаблона проектирования легковеса является:

Используйте совместный доступ для эффективной поддержки большого количества мелких объектов.

Шаблон проектирования Flyweight — это структурный шаблон проектирования, подобный шаблону Decorator. Шаблон проектирования Flyweight используется, когда нам нужно создать много объектов класса. Поскольку каждый объект занимает место в памяти, которое может иметь решающее значение для устройств с малым объемом памяти, таких как мобильные устройства или встроенные системы, можно применить шаблон проектирования легковеса, чтобы уменьшить нагрузку на память за счет совместного использования объектов. Прежде чем мы применим шаблон проектирования легковеса, нам необходимо рассмотреть следующие факторы:

  • Количество объектов, создаваемых приложением, должно быть огромным.
  • Создание объекта занимает много памяти и может занимать много времени.
  • Свойства объекта можно разделить на внутренние и внешние свойства, внешние свойства объекта должны определяться программой-клиентом.

Чтобы применить шаблон легковеса, нам нужно разделить свойство объекта на внутренние и внешние свойства. Внутренние свойства делают объект уникальным, тогда как внешние свойства задаются клиентским кодом и используются для выполнения различных операций. Например, Object Circle может иметь внешние свойства, такие как цвет и ширина. Для применения шаблона легковеса нам нужно создать фабрику легковеса, которая возвращает общие объекты. Допустим, для нашего примера нам нужно создать рисунок с линиями и овалами. Итак, у нас будет интерфейс Shape и его конкретные реализации в виде Line и Oval. Класс Oval будет иметь внутреннее свойство, чтобы определить, заливать ли овал заданным цветом или нет, тогда как Line не будет иметь никакого внутреннего свойства.

Интерфейс шаблона проектирования легковеса и конкретные классы

Shape.java

package com.journaldev.design.flyweight;

import java.awt.Color;
import java.awt.Graphics;

public interface Shape {

	public void draw(Graphics g, int x, int y, int width, int height,
			Color color);
}

Line.java

package com.journaldev.design.flyweight;

import java.awt.Color;
import java.awt.Graphics;

public class Line implements Shape {

	public Line(){
		System.out.println("Creating Line object");
		//adding time delay
		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);
	}

}

Овал.java

package com.journaldev.design.flyweight;

import java.awt.Color;
import java.awt.Graphics;

public 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);
		//adding time delay
		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);
		}
	}

}

Обратите внимание, что я намеренно ввел задержку в создании объекта конкретных классов, чтобы подчеркнуть, что шаблон легковеса можно использовать для объектов, создание экземпляров которых занимает много времени.

Фабрика наилегчайшего веса

Фабрика легковеса будет использоваться клиентскими программами для создания экземпляра объекта, поэтому нам нужно сохранить карту объектов в фабрике, которая не должна быть доступна клиентскому приложению. Всякий раз, когда клиентская программа делает вызов для получения экземпляра объекта, он должен быть возвращен из HashMap, если он не найден, создайте новый объект и поместите его в карту, а затем верните его. Нам нужно убедиться, что все внутренние свойства учитываются при создании объекта. Наш фабричный класс легковеса выглядит так, как показано ниже. ShapeFactory.java

package com.journaldev.design.flyweight;

import java.util.HashMap;

public 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;
	}
}

Обратите внимание на использование шаблона Factory в методе getShape.

Пример клиента легковесного шаблона проектирования

Ниже приведен пример программы, использующей реализацию шаблона легковеса. DrawingClient.java

package com.journaldev.design.flyweight;

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);
	}
}
Creating Line object
Creating Oval object with fill=true
Creating Oval object with fill=false

Это все, что касается шаблона легковеса, мы рассмотрим другие шаблоны проектирования в следующих постах. Если вам понравилось, пожалуйста, поделитесь своими мыслями в разделе комментариев и поделитесь им с другими.

Пример шаблона проектирования легковеса в JDK

Вся реализация пула строк.

Важные моменты шаблона проектирования легковеса

  1. В нашем примере клиентский код не обязан создавать объект с помощью фабрики-приспособленца, но мы можем принудительно сделать это, чтобы убедиться, что клиентский код использует реализацию шаблона-приспособленца, но это законченное дизайнерское решение для конкретного приложения.
  2. Шаблон легковеса усложняет задачу, и если количество общих объектов велико, возникает компромисс между памятью и временем, поэтому нам нужно использовать его разумно, исходя из наших требований.
  3. Реализация шаблона легковеса бесполезна, когда количество внутренних свойств Object огромно, что делает реализацию класса Factory сложной.

Это все, что касается шаблона проектирования Flyweight в Java.