问题引人:给系统加入权限控制,如普通人员可以查看本部门人员列表时,但是每个人员的工资信息,普通人员看不到。而部门经理可以看到
所有的权限系统都分为两个部分,一个是授权部分,一个是验证部分,为了理解它们,引人两个基本名词:安全实体和权限
安全实体:就是被权限系统检测的对象,比如工资数据
权限:就是需要被校验的权限对象,比如查看、修改等。
两者要一起描述才有意义。
授权:是指将对某些安全实体的某些权限分配给某些人员的过程。
验证:值判断某个人员对某个安全实体是否拥有某个或某些权限
多数采用数据库来存储授权过程产生的数据,也就是说:授权是向数据库添加数据,验证是从数据库中获取相应数据进行匹配。
假设授权过程已经完成:
张三 人员列表 查看的权限
李四 人员列表 查看的权限
李四 工资数据 查看的权限
李四 工资数据 修改的权限
试想,每次登陆都要到数据库中查询,是多么的耗时。
为了加快速度,采用一定的缓存。当人员登录的时候,就把该人员能操作的权限获取到,存储在内存中。这样每次操作进行权限验证时,从缓存中获取验证信息,典型的空间换时间。
如不使用设计模式的解决示例,其问题,1,缓存时间长度的问题,即这些数据应该被缓存多久。如果是web应用,这种跟登录人员相关的权限数据,大多放在session中缓存,
2,缓存数据与真实数据的同步问题3,缓存的多线程并发控制,有时要从缓存中取值,有时要加值。
不用设计模式的解决方法:
权限表
package notusingmode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* 在内存中模拟数据库,准备点测试数据
*/
public class TempDB {
private TempDB() { //不允许外部创建该对象
}
/**
* 记录每个人的权限
*/
public static Collection<String> colDB = new ArrayList<String>();
static {
// 填充测试数据
colDB.add("张三,人员列表,查看");
colDB.add("李四,人员列表,查看");
colDB.add("李四,工资数据,查看");
colDB.add("李四,工资数据,修改");
// 增加更多的权限
for(int i = 0;i<3;i++){
colDB.add("张三"+i+",人员列表,查看");
}
}
}
授权模型
package notusingmode;
//授权模型
public class AuthorizationModel {
private String user; //用户
private String securityEntity; //安全实体
private String permit; //权限
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getSecurityEntity() {
return securityEntity;
}
public void setSecurityEntity(String securityEntity) {
this.securityEntity = securityEntity;
}
public String getPermit() {
return permit;
}
public void setPermit(String permit) {
this.permit = permit;
}
// public String toString(){
// return user+"对"+this.securityEntity+"拥有"+permit+"的权限";
// }
//
}
安全管理的业务逻辑
package notusingmode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
//安全管理,实现成单例
public class SecurityMgr {
// 缓存权限
private Map<String, Collection<AuthorizationModel>> map = new HashMap<String, Collection<AuthorizationModel>>();
private static SecurityMgr sm = new SecurityMgr();
private SecurityMgr() {
}
public static SecurityMgr getInstance() {
return sm;
}
// 模拟登录的功能
public void login(String user) {
// 登录时,就需要把该用户拥有的权限,从数据库中取出来,放入缓存
Collection<AuthorizationModel> col = queryByUser(user);
map.put(user, col);
}
private Collection<AuthorizationModel> queryByUser(String user) {
Collection<AuthorizationModel> col = new ArrayList<AuthorizationModel>();
for (String s : TempDB.colDB) {
String ss[] = s.split(",");
if (ss[0].equals(user)) {
AuthorizationModel am = new AuthorizationModel();
am.setUser(user);
am.setPermit(ss[2]);
am.setSecurityEntity(ss[1]);
col.add(am);
}
}
return col;
}
// 判断某个用户对某个安全实体是否拥有对应的权限
public boolean hasPermit(String user, String securityEntity, String permit) {
Collection<AuthorizationModel> col = map.get(user);
if (col == null || col.size() == 0) {
System.out.println(user + "没有登录或是没有被分配任何权限");
return false;
}
for (AuthorizationModel am : col) {
System.out.println("am==" + am);
if (am.getSecurityEntity().equals(securityEntity)
&& am.getPermit().equals(permit)) {
return true;
}
}
return false;
}
}
package notusingmode;
public class Client {
public static void main(String[] args) {
SecurityMgr mgr = SecurityMgr.getInstance();
mgr.login("张三");
mgr.login("李四");
boolean f1 = mgr.hasPermit("张三","工资数据","查看");
boolean f2 = mgr.hasPermit("李四","工资数据","查看");
System.out.println("f1=" + f1);
System.out.println("f1=" + f2);
for(int i = 0;i<3;i++){
mgr.login("张三"+i);
mgr.hasPermit("张三"+i,"工资数据","查看");
}
}
}
在java中,默认的equals方法比较的是内存地址,而equals和hashCode方法的关系是,如果equals返回为true,两个实例的hashCode必须相同,反之则不成立
上面的实例,存在大量的细粒度对象,而且存在大量的重复数据,严重耗费内存,如何解决?————》享元模式
定义:运用共享技术有效地支持大量细粒度的对象。
需要分离出被换成对象实例中,哪些数据是不变且重复出现的,哪些数据是经常变化的,真正应该被缓存的数据就是那些不变的,把
它们称为对象的内部状态,而变化的数据就不缓存了,称为对象的外部状态。
在实现时,把内部状态分离出来共享,叫享元,享元工厂用来管理享元。
结构:
FlyWeight:享元接口,通过这个接口传入外部的状态,在享元对象的方法处理中可能会使用这些外部的数据。
ConcreteFlyWeight:具体的享元实现对象,必须是可共享的,需要封装FlyWeight的内部状态。
UnsharedConcreteFlyWeight:非共享的享元实现对象,并不是所有的FlyWeight实现对象都需要共享,非共享的享元实现对象通常是对共享享元对象的组合对象
FlyWeightFactory:享元工厂,主要用来创建并管理共享的享元对象。
Client:客户端,主要工作时维持一个对FlyWeight的引用,计算或存储享元对象的外部状态,可以访问共享和不共享的FlyWeight对象
package flyweight;
//享元接口
public interface FlyWeight {
//示意操作,传入外部状态
public void operation(String extrinsicState);
}
package flyweight;
import java.util.HashMap;
import java.util.Map;
//享元工厂
public class FlyWeightFactory {
// 示意一下,缓存多个享元对象
Map<String,FlyWeight> map = new HashMap<String,FlyWeight>();
public FlyWeight getFlyWeight(String key){
// 先从缓存中查找,是否存在key对应的FlyWeight对象
FlyWeight f = map.get(key);
if(f==null){ //如果不存在,创建一个新的FlyWeight对象
f= new ConcreteFlyWeight(key);
map.put(key, f);
}
return f;
}
}
package flyweight;
//享元对象
public class ConcreteFlyWeight implements FlyWeight {
private String intrinsicState; // 内部状态
public ConcreteFlyWeight(String intrinsicState) {
this.intrinsicState = intrinsicState;
}
@Override
public void operation(String extrinsicState) {
// 具体的功能处理,可能用到享元的内部、外部状态
}
}
package flyweight;
//不需要共享的享元对象,通常是将共享的数据进行组合而成的对象
public class UnsharedConcreteFlyWeight implements FlyWeight {
private String allState;
@Override
public void operation(String extrinsicState) {
// TODO Auto-generated method stub
}
}
使用享元模式解决权限问题;
分析:实际上重复出现的数据主要是对安全实体和权限的描述,又二者是不分开的,而且是可以重用的。
所以安全实体和权限描述定义成享元,而和它们结合的人员数据,就可以作为享元的外部数据。
在享元模式中,享元对象分为共享与不共享对象,通常共享的是叶子对象,不共享的部分是由共享部分组合而成的,由于所有细粒度的叶子对象都已经缓存了,缓存组合对象就没有必要了
工业级的实例池有两个难点:1,动态控制实例数量,2,动态分配实例给外部使用
在flyweightSolve包中的实例中,添加上不需共享的享元对象实现如包unsharedFlyweight
对享元对象的管理,所谓垃圾,就是在缓存中存在,但是不再需要被使用的缓存中的对象。
引用计数,就是要记录享元对象被引用的次数
包manageFlyweight中实现引用计数和垃圾清除
分享到:
相关推荐
享元模式(Flyweight Pattern)是一种结构型设计模式,用于减少创建大量小对象所带来的内存开销。通过共享对象,享元模式能够有效地支持大量细粒度的对象,减少内存使用并提高性能。它常用于需要大量重复对象的场景...
享元模式是设计模式中的一种结构型模式,它主要通过共享已有对象来减少内存中对象的数量,从而提高系统性能。在C#编程中,享元模式尤其适用于那些创建大量相似对象且内存消耗较大的场景。本篇文章将深入探讨享元模式...
享元模式(Flyweight Pattern)是软件设计中的一种结构型设计模式,它通过共享技术来支持大量细粒度的对象,以此来降低内存中对象的数量。在PHP中实现享元模式,可以帮助我们优化程序性能,特别是在对象数目过多时,...
在“Flyweight”这个文件中,我们可以预期找到的是一个关于享元模式的代码实现。这个文件可能包含了一个享元接口,若干个实现了该接口的具体享元类,以及一个享元工厂类。享元接口定义了对外暴露的方法,这些方法...
享元模式是软件设计模式中的一种结构型模式,它的主要目的是通过共享大量细粒度对象来减少内存的使用,提高系统性能。在许多场景下,尤其是处理大量相似对象时,享元模式能显著减少内存开销。这个压缩包文件...
享元模式的核心是Flyweight类,它是需要被共享的对象,通常包含两个部分:内在状态(Intrinsic State)和外在状态(Extrinsic State)。内在状态是指对象内部不变的部分,可以在多个对象之间共享;外在状态是随环境...
享元模式是面向对象设计中的一种结构型模式,它的主要目的是通过共享大量相似对象来减少内存的使用,提高系统的性能。在C#编程语言中,我们可以利用享元模式来优化那些具有大量实例但大部分状态可以共享的对象。在这...
复合享元模式则引入了享元工厂(Flyweight Factory)来管理和创建享元对象。享元工厂负责管理享元对象池,并根据需要向客户端提供享元对象。当请求的对象不在池中时,工厂会创建新的享元对象;如果存在相同的内蕴...
C++设计模式之享元模式(Flyweight) C++设计模式之享元模式(Flyweight)是一种结构型设计模式,主要用于解决大量相似对象的创建和操作所带来的内存负载问题。该模式的主要设计目标是通过共享对象来减少内存负载,...
享元模式是软件工程中一种用于优化性能的设计模式,它通过共享相似对象的实例来减少内存使用或者计算的开销。在JavaScript编程中,尤其是处理DOM操作和大量相似对象时,享元模式的使用尤为关键。 享元模式的主要...
"Flyweight"(享元)设计模式是一种结构型模式,其核心目的是为了有效地支持大量细粒度对象的创建和使用,通过共享已经存在的对象来减少内存消耗,提高系统性能。在C#中,Flyweight模式尤其适用于那些内部状态可共享...
享元模式的核心是享元对象(Flyweight),它是一个可以被共享的类,通常包含一些共享状态(Static State)和不共享状态(External State)。共享状态是在所有享元对象之间共享的数据,它们不会因对象的不同而改变;...
在Java中实现享元模式时,通常会结合使用`Flyweight`接口和`Concrete Flyweight`类,以及一个`FlyweightFactory`类或方法。`FlyweightFactory`通常维护一个享元对象池,当客户端请求一个享元对象时,工厂首先检查...
享元模式是一种经典的设计模式,属于结构型模式,它的核心思想是通过共享已经存在的对象来减少内存中的对象数量,从而提高系统性能。在许多场景下,特别是计算机编程中,我们可能会遇到大量的相似对象,比如在图形...
享元模式(Flyweight Pattern)是设计模式中的一种优化模式,主要用于减少创建大量相似对象所需的内存消耗。在C++程序设计中,当系统中存在大量的相同或相似的对象时,使用享元模式可以有效地降低内存占用,提高系统...
在享元模式中可以共享的相同内容称为内部状态(Intrinsic State),而那些需要外部...在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(Flyweight Pool)用于存储具有相同内部状态的享元对象。
1. **抽象享元(Flyweight)**:这是享元模式的接口,定义了所有享元对象公共的行为。 2. **具体享元(Concrete Flyweight)**:实现了抽象享元接口,提供了具体的业务逻辑。这些对象是可以共享的,并且通常存储在一...