享元模式 - 结构型模式

个人理解:    

模式类型:

    Flyweight   享元模式 - 结构型模式

意图:
    The intent of this pattern is to use sharing to support a large number of objects that have part of their internal state in common where the other part of state can vary.
    运用共享技术有效地支持大量细粒度的对象.

    
概述:
    享元模式的作用在于节省内存开销,对于系统内存在的大量相似的对象,通过享元的设计方式,可以提取出可共享的部分,将其只保留一份进而节省大量的内存开销。
    并不是所有的对象都适合进行享元设计,它要求对象具有可共享的特征,这些可共享的特征可以做享元设计,对象的可共享特征比例越大,进行享元设计后节省的内存越多。
    注意,对象的不可共享特征不能计入享元设计,所以需要仔细判断区分对象的可共享特征与不可共享特征。
    
    享元模式的本质是:分离和共享。分离的是对象状态中变与不变的部分,共享的是对象中不变的部分。享元模式的关键之处就是在于分离变与不变,把不变的部分作为享元对象的内部状态,把变化的部分作为外部状态,这样享元对象就可以达到共享的目的,从而减少对象数量,节约内存空间。
    
角色:
    1、抽象享元(Flyweight)角色:享元接口,通过这个接口可以接收并作用于外部状态。通过这个接口传入外部的状态,在享元对象的方法处理中可能会使用这些外部状态数据。
    2、具体享元(ConcreteFlyweight)角色:具体的享元对象,必须是共享的,需要封装Flyweight的内部状态。
    3、非共享的具体享元(UnsharedConcreteFlyweight)角色:非共享的具体享元对象,并不是所有的Flyweight对象都需要共享,非共享的享元对象通常是对共享享元对象的组合对象。
    4、享元工厂(FlyweightFactory)角色:享元工厂,主要用来创建并管理共享的享元对象,并对外提供访问共享享元对象的接口。
    5、客户端(Client)角色:享元客户端,主要的工作是维持一个对享元对象的引用,计算或存储享元对象的外部状态,也可以访问共享和非共享的享元对象。

模式的应用场景:
    1 一个应用程序使用了大量的对象
    2 完全由于使用大量的对象,造成很大的存储开销
    3 对象的大多数状态都可变为外部状态
    4 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象
    5 应用程序不依赖对象标识.由于Flyweight对象可以被共享,对于概念明显有别的想对象,标识测试将返回真值.

结构图:




模式的优缺点:

    
代码:

网上的实例都差不多,这里还有一个外国网站的(和下面的实例差不多):http://www.tutorialspoint.com/design_pattern/flyweight_pattern.htm

    import java.util.HashMap;  
    import java.util.Map;  
      
    class ServiceContext {  
        private int tableIndex;  
        private String customerName;  
        public ServiceContext(int tableIndex, String customerName) {  
            this.tableIndex = tableIndex;  
            this.customerName = customerName;  
        }  
        public int getTableIndex() {  
            return tableIndex;  
        }  
        public String getCustomerName() {  
            return customerName;  
        }  
    }  
    interface Drink {  
        void provideService(ServiceContext serviceContext);  
    }  
    class Coffee implements Drink {  
        public Coffee() {  
            System.out.println("Coffee is created.");  
        }  
        @Override  
        public void provideService(ServiceContext serviceContext) {  
            System.out.println("Coffee is serving for table " + serviceContext.getTableIndex() + " customer " + serviceContext.getCustomerName());  
        }  
    }  
    class Tea implements Drink {  
        public Tea() {  
            System.out.println("Drink is created.");  
        }  
        @Override  
        public void provideService(ServiceContext serviceContext) {  
            System.out.println("Drink is serving for table " + serviceContext.getTableIndex() + " customer " + serviceContext.getCustomerName());  
        }  
    }  
    class Water implements Drink {  
        public Water() {  
            System.out.println("Water is created.");  
        }  
        @Override  
        public void provideService(ServiceContext serviceContext) {  
            System.out.println("Water is serving for table " + serviceContext.getTableIndex() + " customer " + serviceContext.getCustomerName());  
        }  
    }  
    class DrinkFactory {  
        private Map<String, Drink> drinks = new HashMap<>();  
        public Drink createDrink(String type) {  
            Drink drink = drinks.get(type);  
            if (drink == null) {  
                // 以下可以考虑抽象工厂模式实现以符合开闭原则,也可以使用反射  
                if (type.equals("Water")) {  
                    drink = new Water();  
                } else if (type.equals("Tea")) {  
                    drink = new Tea();  
                } else if (type.equals("Coffee")) {  
                    drink = new Coffee();  
                }  
                drinks.put(type, drink);  
            }  
            return drink;  
        }  
    }  
    public class WaiterTest {  
        public static void main(String[] args) {  
            String[] types = {"Water", "Tea", "Coffee"};  
            DrinkFactory drinkFactory = new DrinkFactory();  
            for (int i = 1; i <= 9; i++) {  
                Drink drink = drinkFactory.createDrink(types[i % 3]);// Drink 可共享特征 在 DrinkFactory 内部实现享元  
                ServiceContext serviceContext = new ServiceContext(i, "Sir" + i);// 服务细节为不可共享特征,不能享元  
                drink.provideService(serviceContext);//外部特征,不可共享特征,保证调用过程不会影响下次调用。  
            }  
        }  
    }  

输出:
Drink is created.  
Drink is serving for table 1 customer Sir1  
Coffee is created.  
Coffee is serving for table 2 customer Sir2  
Water is created.  
Water is serving for table 3 customer Sir3  
Drink is serving for table 4 customer Sir4  
Coffee is serving for table 5 customer Sir5  
Water is serving for table 6 customer Sir6  
Drink is serving for table 7 customer Sir7  
Coffee is serving for table 8 customer Sir8  
Water is serving for table 9 customer Sir9 


可以看出:在9次的服务过程中,饮品只创建了三次,一种饮品都仅仅创建了一次,减小了很多内存开销,服务可以很好的进行。
这就是享元模式的精髓,但务必注意区分出可共享与不可共享部分,保证不可共享部分在使用之后不会影响下次使用,即不会改变可共享部分。

相关模式:
    享元模式与单例模式:两者可以组合使用。享元模式中的享元工厂完全可以实现为单例,另外,享元工厂中缓存的享元对象,都是单例实例,可以看成是单例模式的一种变形控制,在享元工厂中来单例享元对象。
    享元模式与组合模式:两者可以组合使用。在享元模式中,存在不需要共享软件的享元实现,这些不需要共享的享元通常是对共享的享元对象的组合对象。换句话来说,就是通过将将两种模式组合使用,可以实现更复杂的对象层次结构。
    享元模式与状态模式:两者可以组合使用。可以使用享元模式来共享状态模式中的状态对象。通常在状态模式中,会存在数量很大的,细粒度的状态对象,而且它们基本上可以重复使用的,都是用来处理某一个固定的状态的,它们需要的数据通常都是由上下文传入,也就是变化部分都被分离出去呢,所以可以用享元模式来实现这些状态对象呢。
    享元模式与策略模式:两者可以组合使用。也可以使用享元来实现策略模式中的策略对象。和状态模式一样,策略模式中也存在大量细粒度的策略对象,它们需要的数据同样也是从上下文传入的,因而可以通过享元模式来实现这些策略对象。



所有模式:
     创建型模式,共五种:工厂方法模式、抽象工厂模式单例模式建造者模式原型模式
结构型模式,共七种:适配器模式装饰器模式代理模式外观模式桥接模式组合模式享元模式
    行为型模式,共十一种:策略模式模板方法模式观察者模式迭代子模式责任链模式命令模式备忘录模式状态模式访问者模式中介者模式解释器模式
    补充模式:空对象模式

参考/转自:
http://m.blog.csdn.net/blog/xlf13872135090/22000191
http://www.cnblogs.com/JackyTecblog/archive/2012/10/13/2722255.html
http://www.oodesign.com/flyweight-pattern.html


转载请注明:http://blog.csdn.net/paincupid/article/details/46896653

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值