七大结构型模式之六:享元模式。

  结构型模式:享元模式
  
  热气球
  
  七大结构型模式之六:享元模式。
  
  简介
  
  姓名 :享元模式
  
  英文名 :Flyweight Pattern
  
  价值观 :共享富贵
  
  个人介绍 :
  
  Use sharing to support large numbers of fine-grained objects efficiently.
  
  使用共享对象可有效地支持大量的细粒度的对象。
  
  (来自《设计模式之禅》)
  
  你要的故事
  
  还记得笔袋么?可能有人已经忘记了,在写这篇文章之前其实我也忘了,从初中开始就再也没用过笔袋。拿笔袋来讲享元模式再适合不过了。笔袋放各种各样的笔,今天我们不讲别的,就讲蜡笔。前段时间在逛公园的时候,看到一位老师在画画,画的就是蜡笔画,第一次看到真正的蜡笔画,真的很震撼,原来蜡笔也可以把景色画得那么美。当时偷偷拍了一张,看下图。
  
  我们就拿这幅画来说,里面画了草、树、路、山、天空等等。如果没有用享元模式,我们可能这样子实现。
  
  蜡笔接口。
  
  interface ICrayon {
  
  void draw(String place);
  
  }
  
  蜡笔。
  
  /**
  
  * 蜡笔
  
  */
  
  class Crayon implements ICrayon {
  
  private String color;
  
  public Crayon(String color) {
  
  System.out.println("---新建【" + color + "】蜡笔" );
  
  this.color = color;
  
  }
  
  @Override
  
  public void draw(String place) {
  
  System.out.println("用" + this.color + "蜡笔画" + place);
  
  }
  
  }
  
  测试代码。这幅画是小明和小红一起画,小明画了草和路,小红画了树和蓝天。
  
  public class NoFlyweightTest {
  
  public static void main(String[] args) {
  
  drawByXiaoMing();
  
  drawByXiaoHong();
  
  }
  
  public static void drawByXiaoMing() {
  
  ICrayon greenCrayon = new Crayon("绿色");
  
  greenCrayon.draw("草");
  
  ICrayon grayCrayon = new Crayon("灰色");
  
  grayCrayon.draw("路");
  
  }
  
  public static void drawByXiaoHong() {
  
  ICrayon blueCrayon = new Crayon("蓝色");
  
  blueCrayon.draw("蓝天");
  
  ICrayon greenCrayon = new Crayon("绿色");
  
  greenCrayon.draw("树");
  
  }
  
  }
  
  打印结果:
  
  ---新建【绿色】蜡笔
  
  用绿色蜡笔画草
  
  ---新建【灰色】蜡笔
  
  用灰色蜡笔画路
  
  ---新建【蓝色】蜡笔
  
  用蓝色蜡笔画蓝天
  
  ---新建【绿色】蜡笔
  
  用绿色蜡笔画树
  
  我们发现小明和小红都用了绿色蜡笔,而这里新建了 2 次绿色蜡笔,也就是在整个作画过程中,小明和小红并不是共用一套蜡笔,而是各自用一套蜡笔,在现实中是没什么问题的,但是在软件开发中,如果这种情况出现,其实相当于资源浪费,因为每个蜡笔都会占用内存,可以共用的我们尽量共用,节省一些内存空间,特别是出现很多这种可以共享却没有共享的对象时候。下面我们引入享元模式。享元模式实现方法相当于我们蜡笔都放在了笔袋,小明和小红用完就放到笔袋里面,每一种颜色的蜡笔只有一根,也就是他们共用一套蜡笔。代码如下所示。
  
  笔袋代码。我们用了 Map 作为容器,如果容器里面没有想要颜色的蜡笔,则创建新的蜡笔,并存到容器里。
  
  /**
  
  * 笔袋
  
  */
  
  class CrayonFactory {
  
  private static Map<String, ICrayon> data = new HashMap<>();
  
  public static ICrayon getCrayon(String color) {
  
  if (data.containsKey(color)) {
  
  return data.get(color);
  
  }
  
  ICrayon crayon = new Crayon(color);
  
  data.put(color, crayon);
  
  return crayon;
  
  <dependencies>
  
  <dependency>
  
  <groupId>org.springframework.boot</groupId>
  
  <artifactId>spring-boot-dependencies</artifactId>
  
  <version>2.0.8.RELEASE</version>
  
  <type>pom</type>
  
  <scope>import</scope>
  
  </dependency>
  
  <dependency>
  
  <groupId>io.spring.platform</groupId>
  
  <artifactId>platform-bom</artifactId>
  
  <version>Cairo-RELEASE</version>
  
  <type>pom</type>
  
  <scope>import</scope>
  
  </dependency>
  
  <dependency>
  
  <groupId>org.springframework.cloud</groupId>
  
  <artifactId>spring-cloud-dependencies</artifactId>
  
  <version>Finchley.SR2</version>
  
  <type>pom</type>
  
  <scope>import</scope>
  
  </dependency>
  
  </dependencies>
  
  项目结构如下:
  
  项目结构
  
  授权认证中心搭建
  
  授权认证中心本质就是一个 Spring Boot应用,因此需要完成几个大步骤:
  
  pom中添加依赖
  
  <dependencies>
  
  <dependency>
  
  <groupId>org.springframework.cloud<www.365soke.com /groupId>
  
  <artifactId>spring-cloud-starter-oauth2</artifactId>
  
  </dependency>
  
  </dependencies>
  
  项目 yml配置文件:
  
  server:
  
  port: 8085
  
  servlet:
  
  context-path: /uac
  
  即让授权中心服务启动在本地的 8085端口之上
  
  创建一个带指定权限的模拟用户
  
  @Component
  
  public class SheepUserDetailsService implements UserDetailsService {
  
  @Autowired
  
  private PasswordEncoder passwordEncoder;
  
  @Override
  
  public UserDetails loadUserByUsername(String www.yunyougj.cn) throws UsernameNotFoundException {
  
  if( !"codesheep".equals(s) )
  
  throw new UsernameNotFoundException("用户" + s + "不存在" );
  
  return new User( s, passwordEncoder.encode("123456"), AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_NORMAL,ROLE_MEDIUM"));
  
  }
  
  }
  
  这里创建了一个用户名为codesheep,密码 123456的模拟用户,并且赋予了 普通权限(ROLE_NORMAL)和 中等权限(ROLE_MEDIUM)
  
  认证服务器配置 AuthorizationServerConfig
  
  @Configuration
  
  @EnableAuthorizationServer
  
  public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
  
  @Override
  
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  
  // 定义了两个客户端应用的通行证
  
  clients.inMemory()
  
  .withClient("sheep1")
  
  .secret(new BCryptPasswordEncoder(www.yunyouuyL.com ).encode("123456"))
  
  .authorizedGrantTypes("authorization_code", "refresh_token")
  
  .scopes("all")
  
  .autoApprove(false)
  
  .and()
  
  .withClient("sheep2")
  
  .secret(new BCryptPasswordEncoder().encode(www.hnxinhe.cn"123456"))
  
  .authorizedGrantTypes("authorization_code", "refresh_token")
  
  .scopes("all")
  
  .autoApprove(false);
  
  }
  
  @Override
  
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
  
  endpoints.tokenStore(jwtTokenStore(www.tianscpt.com)).accessTokenConverter(jwtAccessTokenConverter());
  
  DefaultTokenServices tokenServices = (DefaultTokenServices) endpoints.getDefaultAuthorizationServerTokenServices();
  
  tokenServices.setTokenStore(endpoints.getTokenStore(baihuiyulegw.com  ));
  
  tokenServices.setSupportRefreshToken(true);
  
  tokenServices.setClientDetailsService(endpoints.getClientDetailsService());
  
  tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
  
  tokenServices.setAccessTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(1)); // 一天有效期
  
  endpoints.tokenServices(tokenServices);
  
  }
  
  @Override
  
  public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
  
  security.tokenKeyAccess("isAuthenticated()");
  
  }
  
  @Bean
  
  public TokenStore jwtTokenStore() {
  
  return new JwtTokenStore(jwtAccessTokenConverter());
  
  测试代码。
  
  public class FlyweightTest {
  
  public static void main(String[] args) {
  
  drawByXiaoMing();
  
  drawByXiaoHong();
  
  }
  
  public static void drawByXiaoMing(www.chenhaiyulp.cn/ ) {
  
  ICrayon greenCrayon = CrayonFactory.getCrayon("绿色");
  
  greenCrayon.draw("草");
  
  ICrayon grayCrayon = CrayonFactory.getCrayon("灰色");
  
  grayCrayon.draw("路");
  
  }
  
  public static void drawByXiaoHong() {
  
  ICrayon blueCrayon = CrayonFactory.getCrayon("蓝色");
  
  blueCrayon.draw("蓝天");
  
  ICrayon greenCrayon = CrayonFactory.getCrayon("绿色");
  
  greenCrayon.draw("树");
  
  }
  
  }
  
  打印结果:
  
  ---新建【绿色】蜡笔
  
  用绿色蜡笔画草
  
  ---新建【灰色】蜡笔
  
  用灰色蜡笔画路
  
  ---新建【蓝色】蜡笔
  
  用蓝色蜡笔画蓝天
  
  用绿色蜡笔画树
  
  利用享元模式实现的结果,小红画树所用到的绿色蜡笔跟小明画草的绿色蜡笔一样,小红用到时并没有新建绿色蜡笔。
  
  总结
  
  是不是有一种,原来这就是享元模式的感觉?平时开发过程中经常见到这种因为很多重复的对象,所以利用享元模式来实现的场景。享元模式合理提高了对象的复用性,减少了程序的内存占用,还有一个提高性能的地方就是减少了对象创建的过程。好了,收下这个简单的设计模式。欢迎关注公众号,一起学习进步。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值