代码Github连接 :https://github.com/tangbi123/Tab-Design-Pattern
Flyweight模式
共享对象,避免浪费(轻量级,所使用的内存的大小)
当需要某个实例时,并不总是通过new关键字来生成实例,而是尽量共用已经存在的实例。
1、示例
示例,用HashMap来保存已经存在的实例
代码清单
1)big1.txt、big2.txt、big3.txt…
......##........
..######........
......##........
......##........
......##........
......##........
..##########....
................
....######......
..##......##....
..........##....
......####......
....##..........
..##............
..##########....
................
....######......
..##......##....
..........##....
......####......
..........##....
..##......##....
....######......
................
2)BigChar
public class BigChar {
private char charname;
private String fontdata;
public BigChar(char charname){
this.charname = charname;
try{
BufferedReader reader = new BufferedReader(
//注意 文件的路径
new FileReader("src/FlyWeight/big" + charname + ".txt")
);
String line;
StringBuffer buf = new StringBuffer();
while((line = reader.readLine()) != null){
buf.append(line);
buf.append("\n");
}
reader.close();
this.fontdata = buf.toString();
}catch (IOException e){
this.fontdata = charname + "?";
System.out.println("cannot find" + fontdata);
}
}
public void print(){
System.out.println(fontdata);
}
}
3)BigCharFactory
public class BigCharFactory {
private HashMap pool = new HashMap();
private static BigCharFactory singleton = new BigCharFactory();
private BigCharFactory(){}
public static BigCharFactory getInstance(){
return singleton;
}
public synchronized BigChar getBigChar(char charname){
BigChar bc = (BigChar) pool.get("" + charname);
if(bc == null){
bc = new BigChar(charname);
pool.put("" + charname, bc);
}
return bc;
}
}
4)BigString
public class BigString {
private BigChar[] bigchars;
public BigString(String string){
bigchars = new BigChar[string.length()];
BigCharFactory factory = BigCharFactory.getInstance();
for(int i = 0; i < bigchars.length; i++){
bigchars[i] = factory.getBigChar(string.charAt(i));
}
}
public void print(){
for(int i = 0; i < bigchars.length; i++){
bigchars[i].print();
}
}
}
5)main
public class FlyWeightMain {
public static void main(String[] args) {
if(args.length == 0){
System.out.println("Usage: java FlyWeightMain digits");
System.out.println("Example: java FlyWeightMain 1212123, 注意main文件路径");
System.exit(0);
}
BigString bs = new BigString(args[0]);
bs.print();
}
}
6)main 2
public class FlyWeightMain {
public static void main(String[] args) {
BigString bs = new BigString("321123");
bs.print();
bs = new BigString("123321");
bs.print();
}
}
2、角色
1)Flyweight
表示的是那些实例会被共享(多次使用)的类。
2)FlyweightFactory
是生成Flyweight角色的工厂,生成的Flyweight角色可以实现共享实例。
3)Client
使用FlyweightFactory角色来生成Flyweight角色。
3、思路要点
对多个地方产生影响
如果要改变过被共享的对象,就会对过个地方产生影响。
Instrinsic和Extrinsic
应该被共享的信息:Instrinsic信息,本质的,固有的。
不应该被共享的信息:Exstrinsic信息,外在的,非本质的。
不要让被共享的实例被垃圾回收器回收了
删除引用:从HashMao中移出该实例的Entry
内存之外的其他资源
Proxy模式
只在必要时生成实例
当代理人遇到无法自己解决色事情就会去找本人解决该问题。
1、示例
1)Printable
public interface Printable {
public abstract void setPrinterName(String name);
public abstract String getPrinterName();
public abstract void print(String string);
}
2)Printer
public class Printer implements Printable{
private String name;
public Printer(){
heavyJob("正在生成Printer的实例。");
}
public Printer(String name){
this.name = name;
heavyJob("正在生成Printer的实例(" + name + ")");
}
@Override
public void setPrinterName(String name) {
this.name = name;
}
@Override
public String getPrinterName() {
return name;
}
@Override
public void print(String string) {
System.out.println("===== " + name + " =====");
System.out.println(string);
}
private void heavyJob(String msg){
System.out.print(msg);
for(int i =0; i < 5; i++){
try{
Thread.sleep(1000);
}catch (InterruptedException e){
}
System.out.print(".");
}
System.out.println("结束。");
}
}
3)PrinterProxy
public class PrinterProxy implements Printable{
private String name;
private Printer real; //不本人
public PrinterProxy() {
}
public PrinterProxy(String name) {
this.name = name;
}
@Override
public synchronized void setPrinterName(String name) {
if(real != null){
real.setPrinterName(name);
}
this.name = name;
}
@Override
public String getPrinterName() {
return name;
}
@Override
public void print(String string) {
realize();
real.print(string);
}
private synchronized void realize(){
if(real == null){
real = new Printer(name);
}
}
}
- Main
public class ProxyMain {
public static void main(String[] args) {
Printable p = new PrinterProxy("Alice");
System.out.println("现在的名字是 "+ p.getPrinterName());
//p.print("Hello world");
p.setPrinterName("Bob");
System.out.println("现在的名字是 " + p.getPrinterName());
p.print("Hello world");
}
}
2、角色
1)Subject
定义了使Proxy角色和RealSubject角色之间具有一致性的接口;由于存在Subject角色,所以Client角色不必在意他所使用的究竟是Proxy角色还是RealSubject角色。
2)Proxy
会尽量处理来自Client角色的请求,只有当自己不能处理时,她才会将工作交给RealSubject角色。
3)RealSubject
本人角色会在Proxy角色无法胜任工作时出场。
4)Client
使用Proxy模式。
3、思路要点
使用代理人来提升处理速度
Proxy角色作为代理人尽力肩负着工作使命。
如果在一个大型系统的初始化过程中,存在大量的耗时处理;如果在启动系统时连那些暂时不会被使用的功能也初始化了,那么应用程序的启动时间将会非常漫长,者将会引发用户的不满。而如果我们只是在需要使用某个功能时才将其初始化,则可以帮助我们改善用户体验。
有必要划分代理人和本人吗
我们也可以不划分,直接在Printer类中加入惰性求值功能(只有必要时才生成实例的功能)。
划分可以使得他们成为独立的组件,在进行修改时也不会互相之间产生影响。(分而治之)
代理和委托
代理人无法解决的问题,转交给本人,就是委托
透明性
proxy和本人都实现了同一接口,main不必在意用的是谁。
可以说proxy类具有透明性。
HTTP代理
HTTP代理:位于HTTP服务器和HTTP客户端之间,为Web页面提供高速缓存等功能的软件。
ex:页面高速缓存功能。
通过Web浏览器访问Web页面时,并不会每次都去访问远程Web服务器来获取页面的内容,而是会先去获取HTTP代理缓存的页面,只有当需要最新页面内容或是页面缓存期限过期时,才去访问远程Web服务器。
Web服务器:Client、RealSubject角色
HTTP代理:Proxy角色。
各种Proxy模式
1、Virtual Proxy(虚拟代理)
只有当真正需要实例时,他才生成和初始化实例。
2、RemoteProxy(远程代理)
可以让我们完全不必在意RealSubject角色是否在远程网络上,可以如同她在自己身边一样(透明性的)调用他的方法。
3、Access Proxy
用于在调用RealSubject角色的功能时设置访问限制。只允许指定用户 调用方法,其他用户调用方法时报错。