اليوم سنتناول نمط تصميم الوزن الخفي.
نمط تصميم الوزن الخفي
وفقًا لـ GoF ، فإن الغرض من نمط تصميم الوزن الخفي هو:
استخدام المشاركة لدعم أعداد كبيرة من الكائنات الدقيقة بكفاءة.
نمط تصميم الوزن الخفي هو نمط تصميم هيكلي مثل نمط الواجهة ونمط المحول ونمط المزين. يُستخدم نمط تصميم الوزن الخفي عندما نحتاج إلى إنشاء الكثير من الكائنات من فئة معينة. نظرًا لأن كل كائن يستهلك مساحة في الذاكرة يمكن أن تكون مهمة لأجهزة الذاكرة المنخفضة مثل الهواتف المحمولة أو أنظمة المضمنة، يمكن تطبيق نمط تصميم الوزن الخفي لتقليل الحمل على الذاكرة من خلال مشاركة الكائنات. قبل تطبيق نمط تصميم الوزن الخفي، يجب أن ننظر في العوامل التالية:
- يجب أن يكون عدد الكائنات التي يتم إنشاؤها بواسطة التطبيق هائلًا.
- إن إنشاء الكائن ثقيل على الذاكرة ويمكن أن يستغرق الوقت أيضًا.
- يمكن تقسيم خصائص الكائن إلى خصائص جوهرية وخارجية ، ويجب تعريف خصائص الكائن الخارجية بواسطة برنامج العميل.
لتطبيق نمط الوزن الخفي ، نحتاج إلى تقسيم خاصية الكائن إلى الخصائص الجوهرية والخارجية. تجعل الخصائص الجوهرية الكائن فريدًا بينما يتم تعيين الخصائص الخارجية بواسطة كود العميل وتستخدم لأداء عمليات مختلفة. على سبيل المثال ، يمكن أن يحتوي كائن الدائرة على خصائص خارجية مثل اللون والعرض. لتطبيق نمط الوزن الخفي ، نحتاج إلى إنشاء مصنع الوزن الخفي الذي يعيد الكائنات المشتركة. في مثالنا ، دعونا نقول أننا بحاجة إلى إنشاء رسم يحتوي على خطوط وأشكال بيضاوية. لذا سنكون لدينا واجهة 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");
//إضافة تأخير زمني
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);
}
}
Oval.java
package com.journaldev.design.flyweight;
import java.awt.Color;
import java.awt.Graphics;
public class Oval implements Shape {
//خاصية جوهرية
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);
}
}
}
لاحظ أنني قمت بعمداً بإدخال تأخير في إنشاء كائن من الفئات الخرسانية لأظهر أن نمط الوزن الخفي يمكن استخدامه للكائنات التي تستغرق وقتًا طويلاً أثناء الت實例化.
مصنع الوزن الخفي
سيتم استخدام مصنع الوزن الخفي من قبل برامج العميل لتحقيق الكائن، لذا نحتاج إلى الاحتفاظ بخريطة الكائنات في المصنع التي يجب أن لا تكون متاحة لتطبيق العميل. كلما قام برنامج العميل بالاتصال للحصول على مثيل من الكائن، يجب أن يتم إرجاعه من 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;
}
}
لاحظ استخدام Java Enum لضمان النوع، Java Composition (خرائط الأشكال) و نمط المصنع في الطريقة 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);
}
}
I have used random number generation to generate different type of Shapes in our frame. If you run above client program, you will notice the delay in creating first Line Object and Oval objects with fill as true and false. After that the program executes quickly since its using the shared objects. After clicking “Draw” button multiple times, the frame looks like below image. And you will see following output in command line confirming that Objects are shared.
Creating Line object
Creating Oval object with fill=true
Creating Oval object with fill=false
هذا كل شيء بالنسبة لنمط الوزن الخفيف، سننظر في مزيد من أنماط التصميم في المشاركات المستقبلية. إذا أعجبك، يرجى مشاركة أفكارك في قسم التعليقات ومشاركتها مع الآخرين أيضًا.
مثال على نمط تصميم الوزن الخفيف في JDK
جميع فئات التغليف valueOf()
تستخدم الكائنات المخبأة التي تظهر استخدام نمط تصميم الوزن الخفيف. أفضل مثال هو فئة سلسلة جافا تنفيذ String Pool.
أهم نقاط نمط التصميم الخفيف
- في مثالنا، لا يُجبر رمز العميل على إنشاء كائن باستخدام مصنع التخفيف، ولكن يمكننا أن نضطر إلى ذلك للتأكد من أن رمز العميل يستخدم تنفيذ نمط التخفيف، ولكن هذا قرار تصميم كامل لتطبيق معين.
- يقدم نمط التخفيف تعقيدًا، وإذا كان عدد الكائنات المشتركة كبيرًا، فإن هناك تضايقًا بين الذاكرة والوقت، لذا يجب علينا استخدامه بحكمة استنادًا إلى متطلباتنا.
- تكوين نمط التخفيف ليس مفيدًا عندما يكون عدد الخصائص الجوهرية للكائن كبيرًا، مما يجعل تنفيذ فئة المصنع معقدًا.
هذا كل شيء بخصوص نمط تصميم التخفيف في جافا.
Source:
https://www.digitalocean.com/community/tutorials/flyweight-design-pattern-java