图解设计模式 -- 避免浪费

本文详细介绍了设计模式中的Flyweight模式和Proxy模式。Flyweight模式通过共享对象来减少内存消耗,强调对多个地方产生影响以及区分内在和外在信息。Proxy模式则在必要时生成实例,提升处理速度,提供了透明性和多种代理类型,如虚拟代理、远程代理和访问代理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码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);
        }
    }
}
  1. 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角色的功能时设置访问限制。只允许指定用户 调用方法,其他用户调用方法时报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值