@@@模式定义:
运用共享技术有效地支持大量细粒度的对象。
@@@练习示例:
给系统加入权限控制
@@@示例代码:
[不使用模式的实现]
\usual\AuthorizationModel.java
\usual\TestDB.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\usual\SecurityMgr.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\user\ClientUsual.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
运行结果
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
am==usual.AuthorizationModel@c21495
am==usual.AuthorizationModel@1d5550d
am==usual.AuthorizationModel@c2ea3f
f1==false
f2==true
am==usual.AuthorizationModel@a0dcd9
am==usual.AuthorizationModel@186d4c1
am==usual.AuthorizationModel@f9f9d8
[存在的问题]
对象实例数目太多。
在系统当中,存在大量的细粒度对象,而且存在大量的重复数据,
严重耗费内存,如何解决?
[使用模式的实现]
\pattern\Flyweight.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\pattern\AuthorizationFlyweight.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\pattern\FlyweightFactory.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\pattern\TestDB.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\pattern\SecurityMgr.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\user\ClientPattern.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
运用共享技术有效地支持大量细粒度的对象。
@@@练习示例:
给系统加入权限控制
@@@示例代码:
[不使用模式的实现]
\usual\AuthorizationModel.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package usual;
/**
* 描述授权数据的数据model
*/
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;
}
}
\usual\TestDB.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package usual;
import java.util.ArrayList;
import java.util.Collection;
/**
* 供测试用,在内存中模拟数据库中的值
*/
public class TestDB {
/**
* 用来存放授权数据的值
*/
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 + ",人员列表,查看");
}
}
}
\usual\SecurityMgr.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package usual;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* 安全管理,实现成单例
*/
public class SecurityMgr {
private static SecurityMgr securityMgr = new SecurityMgr();
private SecurityMgr() {
}
public static SecurityMgr getInstance() {
return securityMgr;
}
/**
* 在运行期间,用来存放登录人员对应的权限
* 在Web应用中,这些数据通常会存放到session中
*/
private Map<String, Collection<AuthorizationModel>> map =
new HashMap<String, Collection<AuthorizationModel>>();
/**
* 模拟登录的功能
* @param user 登录的用户
*/
public void login(String user) {
// 登录时就需要把该用户所拥有的权限,从数据库中取出来,放到缓存中去
Collection<AuthorizationModel> col = queryByUser(user);
map.put(user, col);
}
/**
* 判断某用户对某个安全实体是否拥有某种权限
* @param user 被检测权限的用户
* @param securityEntity 安全实体
* @param permit 权限
* @return true表示拥有相应权限, false表示没有相应权限
*/
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 + "没有登录或是没有被分配任何权限");
}
for (AuthorizationModel am : col) {
// 输出当前实例,看看是否同一个实例对象
System.out.println("am==" + am);
if (am.getSecurityEntity().equals(securityEntity)
&& am.getPermit().equals(permit)) {
return true;
}
}
return false;
}
/**
* 从数据库中获取某人所拥有的权限
* @param user 需要获取所拥有的权限的人员
* @return 某人所拥有的权限
*/
private Collection<AuthorizationModel> queryByUser(String user) {
Collection<AuthorizationModel> col =
new ArrayList<AuthorizationModel>();
for (String s : TestDB.colDB) {
String ss[] = s.split(",");
if (ss[0].equals(user)) {
AuthorizationModel am = new AuthorizationModel();
am.setUser(ss[0]);
am.setSecurityEntity(ss[1]);
am.setPermit(ss[2]);
col.add(am);
}
}
return col;
}
}
\user\ClientUsual.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package user;
import usual.SecurityMgr;
public class ClientUsual {
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("f2==" + f2);
for (int i = 0; i < 3; i++) {
mgr.login("张三" + i);
mgr.hasPermit("张三" + i, "薪资数据", "查看");
}
}
}
运行结果
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
am==usual.AuthorizationModel@c21495
am==usual.AuthorizationModel@1d5550d
am==usual.AuthorizationModel@c2ea3f
f1==false
f2==true
am==usual.AuthorizationModel@a0dcd9
am==usual.AuthorizationModel@186d4c1
am==usual.AuthorizationModel@f9f9d8
[存在的问题]
对象实例数目太多。
在系统当中,存在大量的细粒度对象,而且存在大量的重复数据,
严重耗费内存,如何解决?
[使用模式的实现]
\pattern\Flyweight.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package pattern;
/**
* 描述授权数据的享元接口
*/
public interface Flyweight {
/**
* 判断传入的安全实体和授权,是否和享元对象内部状态匹配
*
* @param securityEntity
* 安全实体
* @param permit
* 权限
* @return true表示匹配, false表示不匹配
*/
public boolean match(String securityEntity, String permit);
}
\pattern\AuthorizationFlyweight.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package pattern;
/**
* 封装授权数据中重复出现部分的享元对象
*/
public class AuthorizationFlyweight implements Flyweight {
/**
* 内部状态,安全实体
*/
private String securityEntity;
/**
* 内部状态,权限
*/
private String permit;
/**
* 构造方法,传入状态数据
*
* @param state
* 状态数据,包含安全实体和权限的数据,用","分隔
*/
public AuthorizationFlyweight(String state) {
String ss[] = state.split(",");
securityEntity = ss[0];
permit = ss[1];
}
public String getSecurityEntity() {
return securityEntity;
}
public String getPermit() {
return permit;
}
@Override
public boolean match(String securityEntity, String permit) {
if (this.securityEntity.equals(securityEntity)
&& this.permit.equalsIgnoreCase(permit)) {
return true;
}
return false;
}
}
\pattern\FlyweightFactory.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package pattern;
import java.util.HashMap;
import java.util.Map;
/**
* 享元工厂,通常实现成为单例
*/
public class FlyweightFactory {
private static FlyweightFactory factory =
new FlyweightFactory();
private FlyweightFactory() {
}
public static FlyweightFactory getInstance() {
return factory;
}
/**
* 缓存多个Flyweight对象
*/
private Map<String, Flyweight> fsMap =
new HashMap<String, Flyweight>();
/**
* 获取key对应的享元对象
* @param key 获取享元对象的key
* @return 对应的享元对象
*/
public Flyweight getFlyweight(String key) {
Flyweight f = fsMap.get(key);
if (f == null) {
f = new AuthorizationFlyweight(key);
fsMap.put(key, f);
}
return f;
}
}
\pattern\TestDB.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package pattern;
import java.util.ArrayList;
import java.util.Collection;
/**
* 供测试用,在内存中模拟数据库中的值
*/
public class TestDB {
/**
* 用来存放授权数据的值
*/
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 + ",人员列表,查看");
}
}
}
\pattern\SecurityMgr.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package pattern;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* 安全管理,实现成单例
*/
public class SecurityMgr {
private static SecurityMgr securityMgr = new SecurityMgr();
private SecurityMgr() {
}
public static SecurityMgr getInstance() {
return securityMgr;
}
/**
* 在运行期间,用来存放登录人员对应的权限
* 在Web应用中,这些数据通常会存放到session中
*/
private Map<String, Collection<Flyweight>> map =
new HashMap<String, Collection<Flyweight>>();
/**
* 模拟登录的功能
* @param user 登录的用户
*/
public void login(String user) {
// 登录时就需要把该用户所拥有的权限,从数据库中取出来,放到缓存中去
Collection<Flyweight> col = queryByUser(user);
map.put(user, col);
}
/**
* 判断某用户对某个安全实体是否拥有某种权限
* @param user 被检测权限的用户
* @param securityEntity 安全实体
* @param permit 权限
* @return true表示拥有相应权限, false表示没有相应权限
*/
public boolean hasPermit(String user, String securityEntity
, String permit) {
Collection<Flyweight> col = map.get(user);
if (col == null || col.size() == 0) {
System.out.println(user + "没有登录或是没有被分配任何权限");
}
for (Flyweight fm : col) {
// 输出当前实例,看看是否同一个实例对象
System.out.println("fm==" + fm);
if (fm.match(securityEntity, permit)) {
return true;
}
}
return false;
}
/**
* 从数据库中获取某人所拥有的权限
* @param user 需要获取所拥有的权限的人员
* @return 某人所拥有的权限
*/
private Collection<Flyweight> queryByUser(String user) {
Collection<Flyweight> col = new ArrayList<Flyweight>();
for (String s : TestDB.colDB) {
String ss[] = s.split(",");
if (ss[0].equals(user)) {
Flyweight fs = FlyweightFactory.getInstance()
.getFlyweight(ss[1] + "," + ss[2]);
col.add(fs);
}
}
return col;
}
}
\user\ClientPattern.java
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
package user;
import pattern.SecurityMgr;
public class ClientPattern {
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("f2==" + f2);
for (int i = 0; i < 3; i++) {
mgr.login("张三" + i);
mgr.hasPermit("张三" + i, "薪资数据", "查看");
}
}
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
fm==pattern.AuthorizationFlyweight@c2ea3f
fm==pattern.AuthorizationFlyweight@c2ea3f
fm==pattern.AuthorizationFlyweight@a0dcd9
f1==false
f2==true
fm==pattern.AuthorizationFlyweight@c2ea3f
fm==pattern.AuthorizationFlyweight@c2ea3f
fm==pattern.AuthorizationFlyweight@c2ea3f
@@@模式的实现:
享元模式设计的重点就在于分离变与不变。
把一个对象的状态分为不可变的内部状态和可变的外部状态。
然后通过共享不变的部分,达到减少对象数量并节约内存的目的。
@@@模式的优点:
减少对象数量,节省内存空间。
@@@模式的缺点:
维护共享对象,需要额外内存。
@@@模式的本质:
分离与共享。
@@@模式体现的设计原则:
NA