设计模式之享元模式

引入

书接上回,我们来聊聊什么是享元模式?
运用共享技术有效地支持大量细粒度的对象。

讲的明白点创建一堆外部不允许修改的小对象供外部程序使用,如果有很多对象用同一种参数属性,你不能copy出几百个副本让对象使用吧~,第一这会使内存消耗变大第二这本身就显得很蠢,当你要修改时要同时对几百个不同的副本进行操作。

适合享元模式的场景

  • 一个应用程序使用大量的对象,这些对象之间部分属性本质上是一样的(用享元来封装相同的部分,这个很像状态模式的共享做法)
  • 对象的多数状态都可变为外部状态,就可以考虑将这样的对象作为系统中的享元来使用(就是说这个对象是给外部程序调用的,就考虑加上一个享元接口,把这个对象变成一个享元)

享元模式的结构

在这里插入图片描述
是不是很疑惑为什么没有享元对象?
为什么在书上又写了具体享元对象呢?其实具体的享元对象是作为享元工厂的内部类存在的,我这里为了表示这个关系故意没有画出这个实现,具体享元的实现细节全部被享元工厂隐藏起来了·,这样保证了享元对象与所处的环境无关,用户程序不允许直接使用具体享元,创建和管理享元对象全部由享元工厂负责。
这样做的好处就是让具体享元和环境完全解耦,从而使具体享元可以用到任何环境中,不管调用它的是汽车还是火车,只要它还有长宽高的共享数据就可以用这个具体享元。

具体享元对象是享元工厂对象的内部对象,它是享元接口的实例对象,下面就是它的完整画法。
在这里插入图片描述
在这里插入图片描述
这个代表内部类的意思,享元工厂还采用了单例模式,所以这里的享元工厂还有一个自调用的符号!!

享元接口

public interface Flyweight {
    public double getHeight(); //返回内部数据
    public double getWidth();
    public double getlength();
    public void printMess(String mess); // 使用参数mess获取外部数据
}

享元工厂及其内部类具体享元对象

import java.util.HashMap;
//享元工厂,负责创建和管理享元对象
//它将创建享元对象的具体享元类作为自己的内部类
//而它自身则是采用单例模式确保只有它一个实例可以处理享元,进一步确保了享元的唯一性
public class FlyweightFactory {
    private HashMap<String,Flyweight> hashMap;//用hashmap来存放具体享元
    static FlyweightFactory factory  = new FlyweightFactory(); //工厂对象实例是静态的
    private FlyweightFactory(){
        hashMap = new HashMap<String, Flyweight>();
    }
    public static FlyweightFactory getFactory(){
        return factory;
    }

    public synchronized Flyweight getFlyweight(String key){
        if(hashMap.containsKey(key))
            return  hashMap.get(key);
        else {
            double width = 0 ,height = 0,length = 0;
            String[] str =key.split("#");
            width = Double.parseDouble(str[0]);
            height = Double.parseDouble(str[1]);
            length= Double.parseDouble(str[2]);
            Flyweight ft = new ConcreFlyweight(width,height,length);
            hashMap.put(key,ft);
            return ft;
        }
    }
    //享元对象是享元工厂对象的内部类,这样做可以防止外部程序修改这个对象
    private class ConcreFlyweight implements Flyweight {
        private double width;
        private double height;
        private double length;
        public ConcreFlyweight(double width, double height, double length) {
            this.height = height;
            this.width = width;
            this.length = length;
        }

        @Override
        public double getHeight() {
            return height;
        }

        @Override
        public double getWidth() {
            return width;
        }

        @Override
        public double getlength() {
            return length;
        }

        //主动打印从外部来的数据
        @Override
        public void printMess(String mess) {
            System.out.println(mess);
            System.out.println("宽度为"+width);
            System.out.println("高度为"+height);
            System.out.println("长度为"+length);
        }
    }

}

调用享元对象的car对象

//外部程序引用享元对象
public class Car {
    Flyweight flyweight; // 存放享元对象的引用
    String name , color ;
    int power ;
    Car( Flyweight flyweight , String name , String color , int power){
        this.flyweight = flyweight;
        this.color = color;
        this.name = name;
        this.power = power;
    }
    public void printCar(){
        System.out.println("名称"+name);
        System.out.println("颜色"+color);
        System.out.println("功率"+power);
        System.out.println("宽度"+flyweight.getWidth());//这里用的就是享元对象中的数据
        System.out.println("高度"+flyweight.getHeight());
        System.out.println("长度"+flyweight.getlength());
    }
}

应用程序入口

public class Application {
    public static void main(String[] args) {    	
    	//这个享元工厂用的饿汉模式,应用程序中是调用这个getFactory接口获得实例对象的
        FlyweightFactory factory = FlyweightFactory.getFactory();
        double width  = 2,height = 2 ,length = 5 ;
        //key值在工厂那里按照 #号将关键词分离了,这样的好处在于添加新的享元,我们的接口不需要修改
        String key =""+width +"#"+height+"#"+length;
        Flyweight flyweight = factory.getFlyweight(key);// 把享元的数据给到工厂
        //下面两个获取的是享元中的内部数据,是共享的
        Car A6One = new Car(flyweight,"奥迪A6","黑色",128);
        Car A6Two = new Car(flyweight,"奥迪A6","灰色",160);
        A6One.printCar();
        A6Two.printCar();
        //要是你调用printMess方法,外部数据就不是共享的,它不是享元对象的一部分
    }
}

使用享元模式的优点

  • 使用享元可以节省内存的开销,特别适合处理大量细粒度对象,这些对象的许多属性值是相同的,而且一旦创建不允许修改(一个经典的粒子就是这个汽车的例子)
  • 享元模式中的享元可以使用方法的参数接受外部状态中的数据,但外部状态数据不会干扰到享元中的内部数据(这样享元可以在不同的环境中被共享)

总结

享元模式就和我们状态模式将状态抽离出来是一样的道理,既然很多对象都会用到同一个属性,把它抽离出来何乐而不为呢~~!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
享元设计模式(Flyweight Design Pattern)是一种用于优化大量对象创建和使用的设计模式。在Android开发中,使用享元模式可以有效地减少内存消耗和提高性能。 在享元模式中,对象被分为两种状态:内部状态和外部状态。内部状态是不变的,可以被多个对象共享,而外部状态是可变的,每个对象都有自己的外部状态。 在Android中,典型的例子是使用Bitmap对象来显示图片。当需要显示多个相同的图片时,可以使用享元模式来共享已加载的Bitmap对象,而不是每次都创建新的Bitmap对象。 以下是一个简单的示例代码: ```java public class BitmapFactory { private Map<String, Bitmap> bitmapCache = new HashMap<>(); public Bitmap getBitmap(String path) { Bitmap bitmap = bitmapCache.get(path); if (bitmap == null) { // 如果缓存中没有该Bitmap对象,则创建新的Bitmap对象 bitmap = BitmapFactory.decodeFile(path); bitmapCache.put(path, bitmap); } return bitmap; } } ``` 在上面的示例中,`BitmapFactory` 类使用一个 `bitmapCache` Map 来缓存已加载的 Bitmap 对象。当需要获取 Bitmap 对象时,首先从缓存中查找,如果找到则返回缓存的对象,否则创建新的 Bitmap 对象并存入缓存。 通过使用享元模式,可以避免重复创建相同的 Bitmap 对象,从而减少内存消耗。这在需要频繁加载和显示大量图片的应用中非常有用。 需要注意的是,享元模式适用于有大量相似对象的情况,并且需要权衡共享对象和创建对象的开销。在某些情况下,过度使用享元模式可能会导致代码复杂化,降低可读性和可维护性。因此,在使用享元模式时应根据实际情况进行评估和折衷。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AlbertOS

还会有大爷会打钱?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值