python怎么做网站,上海品划网络做网站,简述电子商务网站建设方案,a市最牛的网站目录 1.概述2.结构3.实现3.1.抽象享元3.2.具体享元3.3.享元工厂3.4.测试 4.优缺点5.使用场景6.JDK 源码解析——Integer 类 1.概述
#xff08;1#xff09;享元模式 (Flyweight Pattern) 是一种结构型设计模式#xff0c;主要通过共享对象来减少系统中的对象数量#xff… 目录 1.概述2.结构3.实现3.1.抽象享元3.2.具体享元3.3.享元工厂3.4.测试 4.优缺点5.使用场景6.JDK 源码解析——Integer 类 1.概述
1享元模式 (Flyweight Pattern) 是一种结构型设计模式主要通过共享对象来减少系统中的对象数量从而提高系统的性能。具体来说享元模式是通过将对象分成内部状态和外部状态两种形式来实现共享
内部状态即不会随着环境的改变而改变的可共享部分。外部状态指随环境改变而改变的不可以共享的部分。
通过将内部状态拆分出来并且在一个对象池中创建对象时判断是否已经存在需要创建的对象并返回已有对象从而避免重复创建。
2这种模式适用于具有大量相近对象的场景通过对象共享的方式可以大幅度减少系统的内存开销。在实际应用中享元模式经常与其他设计模式相结合使用以达到更好的效果。
2.结构
享元模式的主要有以下角色
抽象享元 (Flyweight) 角色通常是一个接口或抽象类在抽象享元类中声明了具体享元类公共的方法这些方法可以向外界提供享元对象的内部数据内部状态同时也可以通过这些方法来设置外部数据外部状态。具体享元 (Concrete Flyweight) 角色它实现了抽象享元类称为享元对象在具体享元类中为内部状态提供了存储空间。通常我们可以结合单例模式来设计具体享元类为每一个具体享元类提供唯一的享元对象。非享元 (Unsharable Flyweight) 角色并不是所有的抽象享元类的子类都需要被共享不能被共享的子类可设计为非共享具体享元类当需要一个非共享具体享元类的对象时可以直接通过实例化创建。享元工厂 (Flyweight Factory) 角色负责创建和管理享元角色。当客户对象请求一个享元对象时享元工厂检査系统中是否存在符合要求的享元对象如果存在则提供给客户如果不存在的话则创建一个新的享元对象。
3.实现
【例】俄罗斯方块下面的图片是众所周知的俄罗斯方块中的一个个方块如果在俄罗斯方块这个游戏中每个不同的方块都是一个实例对象这些对象就要占用很多的内存空间下面利用享元模式进行实现。 类图如下 具体实现代码如下
3.1.抽象享元
AbstractBox.java
//抽象享元角色
public abstract class AbstractBox {//获取图形的方法public abstract String getShape();//显示图形以及颜色public void display(String color) {System.out.println(方块形状: getShape() : color);}
}3.2.具体享元
IBox.java
public class IBox extends AbstractBox{Overridepublic String getShape() {return I;}
}LBox.java
public class LBox extends AbstractBox{Overridepublic String getShape() {return L;}
}OBox.java
public class OBox extends AbstractBox{Overridepublic String getShape() {return O;}
}3.3.享元工厂
BoxFactory.java
//工厂类将该类设计为单例
public class BoxFactory {private HashMapString,AbstractBox map;//在构造方法中进行初始化操作private BoxFactory(){map new HashMapString,AbstractBox();map.put(I, new IBox());map.put(L, new LBox());map.put(O, new OBox());}private static BoxFactory factory new BoxFactory();//提供一个方法获取该工厂类对象public static BoxFactory getInstance(){return factory;}//根据名称获取图形对象public AbstractBox getShape(String name){return map.get(name);}
}3.4.测试
Client.java
public class Client {public static void main(String[] args) {//获取 I 图形对象AbstractBox box1 BoxFactory.getInstance().getShape(I);box1.display(灰色);//获取 L 图形对象AbstractBox box2 BoxFactory.getInstance().getShape(L);box2.display(红色);//获取 O 图形对象AbstractBox box3 BoxFactory.getInstance().getShape(O);box3.display(黑色);//获取 O 图形对象AbstractBox box4 BoxFactory.getInstance().getShape(O);box4.display(蓝色);System.out.println(两次获取到的 O 图形对象是否为同一个对象 (box3 box4));}
}输出结果如下
方块形状: I: 灰色
方块形状: L: 红色
方块形状: O: 黑色
方块形状: O: 蓝色
两次获取到的 O 图形对象是否为同一个对象true4.优缺点
1享元模式的优点
减少内存使用通过共享对象减少了系统中的对象数量从而节省了内存空间。提升性能由于减少了对象的数量可以提高系统的性能。共享的对象可以在多个上下文中共享使用避免了重复创建对象的开销。简化操作对于具有相同或相似内部状态的对象可以共享一个享元对象简化了对对象的操作。
2享元模式的缺点
共享对象状态的限制由于享元模式需要将对象的内部状态和外部状态分离因此可能会引入一定的限制。对于外部状态的改变需要在外部进行设置可能会带来一些额外的复杂性。对象共享的线程安全问题如果多个线程同时使用享元对象需要保证线程安全避免对共享对象进行修改导致其他线程的错误结果。可能引入过多的复杂性在使用享元模式时需要权衡对象的共享和不共享状态可能会增加代码的复杂性和维护成本。
5.使用场景
1享元模式通常适用于以下场景
需要大量创建相似的对象例如用于图形编辑器中的大量相似图形元素如矩形、圆形等可以创建一个共享的图形元素对象池避免每次创建图形元素时都进行对象的初始化从而提高性能和减少内存占用。对象可以被共享复用当一个对象需要在多个地方进行共享使用时使用享元模式可以避免重复创建对象的开销并且提高系统性能。对象的大部分状态可以外部化如果一个对象的大部分状态可以被外部计算或者设置可以使用享元模式来将内部状态与外部状态分离避免重复创建对象的开销。系统需要缓存对象的场景当系统需要缓存一些对象并根据需要重复使用这些对象时使用享元模式可以减少内存的使用提高系统的性能。
2总之享元模式适用于需要大量创建相似对象的场景并且这些对象可以被共享复用可以提高系统的性能和减少内存占用。
6.JDK 源码解析——Integer 类 相关面试题可以参考下面的文章 Java 基础面试题——基本数据类型与包装类 Integer 类使用了享元模式。先看下面的例子
class IntegerDemo {public static void main(String[] args) {Integer i1 127;Integer i2 127;System.out.println(i1 和 i2 是否为同一个对象 (i1 i2));Integer i3 128;Integer i4 128;System.out.println(i3 和 i4 是否为同一个对象 (i3 i4));}
}上述程序的运行结果如下
i1 和 i2 是否为同一个对象true
i3 和 i4 是否为同一个对象false为什么第一个输出语句输出的是 true第二个输出语句输出的是 false通过反编译软件进行反编译代码如下
public class Demo {public static void main(String[] args) {Integer i1 Integer.valueOf((int)127);Integer i2 Integer.valueOf((int)127);System.out.println((String)new StringBuilder().append((String)i1\u548ci2\u5bf9\u8c61\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1f).append((boolean)(i1 i2)).toString());Integer i3 Integer.valueOf((int)128);Integer i4 Integer.valueOf((int)128);System.out.println((String)new StringBuilder().append((String)i3\u548ci4\u5bf9\u8c61\u662f\u5426\u662f\u540c\u4e00\u4e2a\u5bf9\u8c61\uff1f).append((boolean)(i3 i4)).toString());}
}从上面代码可以看出直接给 Integer 类型的变量赋值的底层操作使用方法的是 valueOf()所以只需看该方法的代码即可
public final class Integer extends Number implements ComparableInteger {//...public static Integer valueOf(int i) {if (i IntegerCache.low i IntegerCache.high)return IntegerCache.cache[i (-IntegerCache.low)];return new Integer(i);}private static class IntegerCache {static final int low -128;static final int high;static final Integer cache[];static {int h 127;String integerCacheHighPropValue sun.misc.VM.getSavedProperty(java.lang.Integer.IntegerCache.high);if (integerCacheHighPropValue ! null) {try {int i parseInt(integerCacheHighPropValue);i Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {}}high h;cache new Integer[(high - low) 1];int j low;for(int k 0; k cache.length; k)cache[k] new Integer(j);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high 127;}private IntegerCache() {}}
}可以看到 Integer 默认先创建并缓存 -128 ~ 127 之间数的 Integer 对象当调用 valueOf() 方法时
如果参数在 -128 ~ 127 之间则计算下标并从缓存中返回否则创建一个新的 Integer 对象。