zoukankan      html  css  js  c++  java
  • [工作中的设计模式]享元模式模式FlyWeight

    一、模式解析

    Flyweight在拳击比赛中指最轻量级,即“蝇量级”或“雨量级”,这里选择使用“享元模式”的意译,是因为这样更能反映模式的用意。享元模式是对象的结构模式。享元模式以共享的方式高效地支持大量的细粒度对象。

    享元模式:主要为了在创建对象时,对共有对象以缓存的方式进行保存,对外部对象进行单独创建

    模式要点:

    1、享元模式中的对象分为两部分:共性部分和个性化部分,共性部分就是每个对象都一致的或者多个对象可以共享的部分,个性化部分指差异比较大,每个类均不同的部分

    2、共性部分的抽象就是此模式介绍的享元对象

    3、享元对象一般通过一个享元工厂进行创建和保存

    4、享元工厂根据享元对象的多少,实现一个单例或者多例模式,来创建享元对象

    5、享元对象可以预先设定好在享元工厂里,也可以创建一个集合,每次创建对象时,查看享元对象是否存在,不存在则进行添加

    二、模式代码

    1、创建享元接口

    package flyweight.patten;
    //享元接口
    public interface FlyWeight {
    
        public void opertion();
    }

    2、创建具体享元类

    package flyweight.patten;
    
    public class ConcreteFlyWeight implements FlyWeight {
        public String name;
        public ConcreteFlyWeight(String name){
            this.name=name;
        }
        @Override
        public void opertion() {
            System.out.println("执行享元类");
        }
    }

    3、创建享元工厂

    package flyweight.patten;
    
    import java.util.HashMap;
    import java.util.Map;
    
    //享元工厂,为客户端提供享元类
    public class FlyWeightFactory {
        
        //使用内部map,保证享元对象只被创建一次
        private Map<String,FlyWeight> map=new HashMap<String,FlyWeight>();
        
        public FlyWeight getFlyWeight(String name){
            FlyWeight flyWeight=map.get(name);
            if(map.get(name)==null||map.get(name).equals("")){
                flyWeight=new ConcreteFlyWeight(name);
                map.put(name, flyWeight);
            }
            return flyWeight;
        }
    
    }

    5、客户端

    package flyweight.patten;
    
    public class Client {
        public static void main(String[] args) {
            FlyWeightFactory factory=new FlyWeightFactory();
            FlyWeight flyWeight1=factory.getFlyWeight("张三");
            FlyWeight flyWeight2=factory.getFlyWeight("李四");
            FlyWeight flyWeight3=factory.getFlyWeight("张三");
            System.out.println(flyWeight1==flyWeight2);
            System.out.println(flyWeight1==flyWeight3);
        }
    }

    6、执行结果,可以看到,如果姓名相同,每次引用的享元对象都是一样的,符合多例模式

    false
    true

    注:此模式的标准代码为单纯的享元模式,并不完全符合我们上边的模式要点,因为他创建的对象参数全部为享元内容,所以我们在后边的实例中编写一个完全的享元模式代码。

    三、应用场景

    享元模式的应用比较广泛,类似与数据库的外键关联关系,所以我们以工作中最常见的银行卡举例:

      客户账户属性分为:银行卡种类,银行卡名称,银行卡号,余额,客户姓名等因素。在创建卡对象时候,由于卡种类和名称对于每个银行仅有几种,所以创建一个享元对象进行保存。

    四、模式代码

    1、创建银行卡类,也就是享元对象

    package flyweight.example;
    /**
     * 卡类型
     * @author lenovo
     *
     */
    public class Card {
        private String cardType;
        private String cardName;
        public String getCardName() {
            return cardName;
        }
    
        public void setCardName(String cardName) {
            this.cardName = cardName;
        }
    
        public String getCardType() {
            return cardType;
        }
    
        public void setCardType(String cardType) {
            this.cardType = cardType;
        }    
        public Card(String cardType,String cardName){
            this.cardType=cardType;
            this.cardName=cardName;
        }
    
        @Override
        public String toString() {
            return "CardType [cardType=" + cardType + ", cardName=" + cardName + "]";
        }
        
    }

    2、创建账户接口

    package flyweight.example;
    /**
     * 账户接口
     * @author lenovo
     *
     */
    public interface CountInterface {
        /**
         * 显示卡内容
         */
        public void show() ;
    }

    3、创建账户类

    package flyweight.example;
    
    import java.math.BigDecimal;
    
    /**
     * 具体账户属性
     * @author lenovo
     *
     */
    public class ConcreteCount implements CountInterface {
        private String cardNo;
        private BigDecimal balance;
        private Card card;
        /**
         * 根据参数创建用户对象
         * @param cardNo
         * @param balance
         * @param cardType
         */
        public ConcreteCount(String cardNo, BigDecimal balance, Card card) {
            this.cardNo = cardNo;
            this.balance = balance;
            this.card = card;
        }
    
    
    
        @Override
        public String toString() {
            return "ConcreteCount [cardNo=" + cardNo + ", balance=" + balance + ", card=" + card + "]";
        }
    
    
    
        @Override
        public void show() {
            System.out.println(this.toString());
    
        }
    
    }

    5、创建享元工厂,享元工厂返回客户账户实例,在创建客户账户时,首先判断卡属性是否存在,存在就直接从享元对象中获取卡属性,否则创建新的卡

    package flyweight.example;
    
    import java.math.BigDecimal;
    import java.util.HashMap;
    import java.util.Map;
    
    
    /**
     * 享元工厂,主要用于创建对象
     * @author lenovo
     *
     */
    public class CountFactory {
        //保存享元对象的map
        Map<String,Card> cardTypeMap=new HashMap<String, Card>();
        
        public ConcreteCount getConcreteCount(String cardNo, BigDecimal balance,String cardType,String cardName){
            
            Card card=null;
            //判断享元对象是否已经存在,如果存在则使用,不存在则额外创建
            if(cardTypeMap.get(cardType+cardName)!=null){
                card=cardTypeMap.get(cardType+cardName);
            }else {
                card=new Card(cardType, cardName);
                cardTypeMap.put(cardType+cardName, card);
            }
            
            return new ConcreteCount(cardNo, balance, card);
            
        }
    }

    5、客户端

    package flyweight.example;
    
    import java.math.BigDecimal;
    
    public class CardTest {
    
        /**
         * 测试享元模式
         * @param args
         */
        public static void main(String[] args) {
            CountFactory factory=new CountFactory();
            ConcreteCount count=factory.getConcreteCount("001", new BigDecimal(100), "1", "信用卡");
            ConcreteCount count2=factory.getConcreteCount("002", new BigDecimal(200), "2", "借记卡");
            ConcreteCount count3=factory.getConcreteCount("003", new BigDecimal(300), "1", "信用卡");
            ConcreteCount count4=factory.getConcreteCount("004", new BigDecimal(400), "2", "借记卡");
            
            count.show();
            count2.show();
            count3.show();
            count4.show();
            
        }
    
    }

    6、结果

    ConcreteCount [cardNo=001, balance=100, card=CardType [cardType=1, cardName=信用卡]]
    ConcreteCount [cardNo=002, balance=200, card=CardType [cardType=2, cardName=借记卡]]
    ConcreteCount [cardNo=003, balance=300, card=CardType [cardType=1, cardName=信用卡]]
    ConcreteCount [cardNo=004, balance=400, card=CardType [cardType=2, cardName=借记卡]]

    五、解析

    如同第三部分所说,享元模式大都是以数据库外键形式体现在系统中,所以在系统中使用享元思想的很多,但是使用享元对象标准模式写法的还是比较少,所以设计模式还是要注重思想。

  • 相关阅读:
    网络通信socket连接数上限
    图像轮廓的提取
    C# 基础类型的快速转换
    十大编程算法助程序员走上高手之路
    椭圆的曲线模拟
    覆盖父类方法的new和override关键字
    BackgroundWorker异步更新界面
    小程序开发(七)利用SQL实现access_token的自动通知
    漫水填充(泛洪填充、油漆桶)的C#实现(解决堆溢出问题)
    SQL中获取最近的N个半年度
  • 原文地址:https://www.cnblogs.com/jyyzzjl/p/5189721.html
Copyright © 2011-2022 走看看