千家信息网

如何使用结构型模式

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章主要讲解了"如何使用结构型模式",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何使用结构型模式"吧!适配器模式所谓适配器模式,就是把一个类的结
千家信息网最后更新 2026年11月02日如何使用结构型模式

这篇文章主要讲解了"如何使用结构型模式",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"如何使用结构型模式"吧!

适配器模式

所谓适配器模式,就是把一个类的结构转换成另外一个类的接口。使得原本由于接口不兼容而不能工作的类都能够一起工作。

在生活中比较常见的就是当我们想连接显示器的时候,vga需要转成hdmi,还有电源适配,比如可能需要220v的充电头,但是只有110v的充电头,那么就需要将220v的充电头适配成110v的充电头。

Adaptee: 需要适配的就代码,旧接口

Adapter: 将调用转发给Adaptee 的适配器类

Target: 支持的新接口

适配器模式UML

类适配器模式

Target

public interface Target {    void output110v();}

Adaptee

public class Adaptee {    public void output220v() {        System.out.println("输出电压");    }}

Adapter

public class Adapter extends Adaptee implements Target {    @Override    public void output110v() {        this.output220v();    }}

这里需要注意的是Adapter 是继承了源类而实现了目标类

Client

public class Client {    public static void main(String[] args) {        Target target = new Adapter();        target.output110v();    }}

虽然我们是使用了output110v的充电头,但是经过Adapter后,最终通过this.output220v() 会调用output220v的充电头,这就是把output220v适配成了output110v。

对象适配器模式

其实说得这么高大上,其实就是Adaptor 的实现方式不同,类适配器模式采用继承了源类(也就是需要适配的类)实现了目标类。

这样就存在一个问题,当我们需要适配多个类的时候就会出现问题,因为java中是允许实现多个接口,但是只能继承一个类。

为了解决这个问题,我们可以把需要适配的类作为Adapter 的成员变量,然后通过构造函数进行适配

public class NewAdapter implements Target{    Adaptee adaptee;    public NewAdapter(Adaptee adaptee) {        this.adaptee = adaptee;    }    @Override    public void output110v() {        adaptee.output220v();    }}

代理模式


代理模式也算是比较常用的设计模式之一,大家接触最多的spring aop,就是采用动态代理模式来完成的。代理模式可以分为普通代理模式,强制代理模式,动态代理模式,也是本文着重讲解的,当然还有其代理模式。

先来用一段代码来体会代理模式,场景是玩家打游戏。

Subject: 共同接口,客户端使用的现有接口

RealSubject: 真实对象的类

ProxySubject: 代理对象类

代理模式UML

普通代理模式


通过上面的例子,相信对大家都对代理模式有点感觉了,但是好像又不那么恰当,上面的测试类种,还是需要新建一个player,这就相当于什么,相当于我们是在手机上登录了游戏,然后再把手机给代练者代练。而事实上,经常是把账号密码给代练即可。

这就引出了普通代理模式,客户端不能访问真实角色,只能访问代理角色,我们能够知道代理的存在。

Subject

public interface SubjectNormalGamePlayer {    public void login();    public void upgrade();    public void matches();}

RealSubject

public class RealSubjectNormalPlayerImpl implements SubjectNormalGamePlayer {    private String name;    private String password;    public RealSubjectNormalPlayerImpl(String name, String password) {        this.name = name;        this.password = password;    }    @Override    public void login() {        if(name.equals("cutey") && password.equals("123456")) {            System.out.println(name + "登录成功");        }    }    @Override    public void upgrade() {          System.out.println(name + "升级");    }    @Override    public void matches() {        System.out.println(name + "打排位赛");    }}

ProxySubject

public class ProxySubjectNormalPlayerImpl implements SubjectNormalGamePlayer {    SubjectNormalGamePlayer gamePlayer;    //注意这里的区别,我们是拿账号和密码去登录真实角色    //并不是直接拿真实角色的手机来打    public ProxySubjectNormalPlayerImpl(String name, String password) {        gamePlayer = new RealSubjectNormalPlayerImpl(name, password);    }    @Override    public void login() {        System.out.print("代练:");        gamePlayer.login();    }    @Override    public void upgrade() {        System.out.print("代练:");        gamePlayer.upgrade();    }    @Override    public void matches() {        System.out.print("代练:");        gamePlayer.matches();    }}

Client

public class Client {    public static void main(String[] args) {        //通过测试类也很明显区别,不必要显示构造真实角色类        SubjectNormalGamePlayer proxy = new ProxySubjectNormalPlayerImpl("cutey", "123456");        proxy.login();        proxy.upgrade();        proxy.matches();    }}

强制代理


普通代理呢是去找到一个代理对象帮打,但是强制代理呢,主要是体现在"强制",角色类会指定一个代理,其它方式找来的代理不能帮我打,一定要用我指定的代理才行。

Subject

和普通代理模式大部分代码一样,不同的是加了一个强制指定代理对象。

public interface SubjectForceGamePlayer {         //省略登录、升级和打排位等方法        //强制指定代理对象    public SubjectForceGamePlayer getForceProxy();}

RealSubject

public class ForceGamePlayerImpl implements IForceGamePlayer {    private String name;    private String password;    private IForceGamePlayer proxy = null;      //指定需要谁来代理    public ForceGamePlayerImpl(String name, String password) {        this.name = name;        this.password = password;    }        @Override    public IForceGamePlayer getForceProxy() {        //强制指定代理类,并且只有这样才能给proxy赋值        proxy =  new ForceProxyGamePlayerImpl(this);        return proxy;    }    @Override    public void login() {        //只要不是自己指定的proxy,其它方式proxy肯定是null        if(proxy != null) {            if(name.equals("imperfect") && password.equals("123456")) {                System.out.println(name + "登录成功");            }        } else {            System.out.println("需要代理");        }    }    @Override    public void upgrade() {        if(proxy != null) {            System.out.println(name + "升级");        } else {            System.out.println("需要代理");        }    }    @Override    public void matches() {        if(proxy != null) {            System.out.println(name + "打排位赛");        } else {            System.out.println("需要代理");        }    }}

ProxySubject

public class ProxySubjectForcePlayerImpl implements SubjectForceGamePlayer {    private SubjectForceGamePlayer gamePlayer;        //接收被代理对象的指定    public ProxySubjectForcePlayerImpl(SubjectForceGamePlayer gamePlayer) {        this.gamePlayer = gamePlayer;    }    //省略登录、升级和打比赛的方法    //没有代理对象,暂时返回自己    @Override    public SubjectForceGamePlayer getForceProxy() {        return this;    }}

Client

public class Client {    public static void main(String[] args) {        wrongProxy1();        wrongProxy2();        correctProxy();    }    public static void correctProxy() {        SubjectForceGamePlayer player = new RealSubjectForcePlayerImpl("cutey", "123456");        //你这个代理必须是我指定的,并且强制要有        SubjectForceGamePlayer proxy = player.getForceProxy();        proxy.login();        proxy.upgrade();        proxy.matches();    }    public static void wrongProxy1() {        SubjectForceGamePlayer player = new RealSubjectForcePlayerImpl("cutey", "123456");        SubjectForceGamePlayer proxy = new ProxySubjectForcePlayerImpl(player);        proxy.login();        proxy.upgrade();        proxy.matches();    }    public static void wrongProxy2() {        SubjectForceGamePlayer player = new RealSubjectForcePlayerImpl("cutey", "123456");        player.login();        player.upgrade();        player.matches();    }}

动态代理


这个应该是代理模式中用的比较多的,也是我觉得最需要各位小伙伴理解并且掌握的。所谓动态代理是指,不用在编译器指定为谁代理,而是在运行期再获得被代理的对象并且执行代理的方法。

下面将要讲的例子是利用jdk中提供的InvocationHandler和Proxy类

Subject 、RealSubject 都和普通代理模式一样

ProxySubject

我们不知道要给谁代理,所以要用到的是继承InvocationHandler类

public class ProxySubjectDynamicPlayerImpl implements InvocationHandler {    Class cls = null;        //要代理的类    Object obj = null;       //需要代理的对象    //指定需要代理的对象    public ProxySubjectDynamicPlayerImpl(Object obj) {        this.obj = obj;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        //调用代理对象的方法        Object result = method.invoke(this.obj, args);        if(method.getName().equalsIgnoreCase("login")) {            System.out.println("异地登陆提醒:有人登录我的账户");        }        return result;    }}

Client

public class Client {    public static void main(String[] args) {        SubjectDynamicPlayer player = new RealSubjectDynamicPlayerImpl("imperfect", "123456");        //把需要代理的信息交给handler,还记得invoke方法吗        //在invoke方法中已经实现了被代理对象的方法        InvocationHandler handler = new ProxySubjectDynamicPlayerImpl(player);        //获取被代理类的类加载属性        ClassLoader cl = player.getClass().getClassLoader();        //获取被代理类的接口        Class[] interfaces = player.getClass().getInterfaces();        //把上述的三个信息交给Proxy创建出一个代理类        SubjectDynamicPlayer proxy = (SubjectDynamicPlayer) Proxy.newProxyInstance(cl, interfaces, handler);        proxy.login();        proxy.upgrade();        proxy.matches();    }}

在编译时我们是完全不知道给谁代理,一切都是在运行时才知道,这就是"动态"

装饰模式

装饰模式就是动态地给一个对象添加一些恩爱的职责,就增加功能来说,装饰模式比生成子类更为灵活。

无论干什么,最重要的都是扬长避短,对于卖手机也是如此,肯定是把卖点详细地介绍,而对于缺点能不提就不提。

Component: 定义一个对象的接口,可以给这些对象动态地添加职责

ConcreteComponent: 具体的对象

Decorator: 装饰抽象类,继承了Component,从外类来扩展Component

ConcentrateDecorator: 具体的装饰类

装饰模式UML

装饰模式

Component

public abstract class ComponentMobile {    //产品名字    private String name;    //省略get,set,tostring方法    public abstract void showDetails();    public abstract void onSale(String userName);}

Concentrate Component

public class ConcreteComponentOnePlus extends ComponentMobile {    public ConcreteComponentOnePlus(String name) {        super(name);    }    @Override    public void showDetails() {        System.out.println("处理器:骁龙888 \r\n拍照:哈苏专业模式 \r\n屏幕:2k+120hz 柔性屏 \r\n充电:65w快充");    }    @Override    public void onSale(String userName) {        System.out.println(userName + "购买了" + getName());    }}

Decorator

public abstract class Decorator extends ComponentMobile {    //把要装饰的手机拿给我    private ComponentMobile mobile;    public Decorator(String name, ComponentMobile mobile) {        super(name);        this.mobile = mobile;    }        //细节还是要展示的    //只不过怎么展示呢,子类可以加以修饰    public void showDetails() {        mobile.showDetails();    }    //手机也是要出售的    public void onSale(String name) {        mobile.onSale(name);    }}

注意,我们手机的细节还是要展示的,不能说做的不好就不说出来,欺骗消费者。能把你认出来叫化妆,不能把你认出来叫整容,我们讲的是装饰模式,不是整容模式。

Concrete Decorator

public class ConcreteDecoratorSystem extends Decorator {    public ConcreteDecoratorSystem(String name, ComponentMobile mobile) {        super(name, mobile);    }    //装饰系统    public void decorateScreen() {        System.out.println("出厂配备了ColorOS,其它型号的手机也会逐步适配");    }    @Override    public void showDetails() {        //想先介绍了系统,再说其他参数        decorateScreen();        super.showDetails();    }}
public class ConcreteDecoratorPrice extends Decorator {    public ConcreteDecoratorPrice(String name, ComponentMobile mobile) {        super(name, mobile);    }    //公布价格    public void decoratePrice() {        System.out.println("8 + 128:4999");        System.out.println("8 + 256: 5499");    }    @Override    public void showDetails() {        super.showDetails();        //介绍完其它的后,公布性价比较高的价格        decoratePrice();    }}

Client

public class Client {    public static void main(String[] args) {        //手机发布会,原产品        ComponentMobile mobile = new ConcreteComponentOnePlus("OnePlus 9 Pro");        //装饰下系统        mobile = new ConcreteDecoratorSystem(mobile.getName(), mobile);        //装饰下价格        mobile = new ConcreteDecoratorPrice(mobile.getName(), mobile);        mobile.showDetails();        //用户一看,诶,不错不错,买了        mobile.onSale("cutey");    }}

感谢各位的阅读,以上就是"如何使用结构型模式"的内容了,经过本文的学习后,相信大家对如何使用结构型模式这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

代理 模式 对象 适配 手机 接口 就是 方法 强制 动态 适配器 登录 普通 代练 角色 结构 结构型 问题 升级 代码 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 精品咖啡豆 互联网科技工作委员会 互联网佳科技有限公司 深圳互联网络科技有限公司 碳银互联网科技 顺网科技2021年互联网排名 无锡溥仪互联网科技有限公司 岳阳华臻互联网科技有限公司 消费医药和互联网科技 互联网科技大奖都有哪些公司 翼展科技 首家互联网医院 互联网在线教育科技创业 雨阳互联网卡科技有限公司 云南省自由互联网科技有限公司 中天科技中国工业互联网 卡尔迅互联网科技有限公司 上海乐五互联网科技有限公司 陕西彩京云互联网科技有限公司 长沙易易互联网科技有限公司 网互联网络科技 互联网科技园 上海喔噻互联网科技有限公司 互联网科技工作委员会主任 工业互联网科技新基建 亿账通互联网科技 友谊互联网络科技 北京三清互联网科技 特约风豹互联网科技为什么扣费 领航科技大厦互联网公司 绵阳真晨互联网科技有限公司
0