首页 > 其他分享 >设计模式--结构型模式

设计模式--结构型模式

时间:2024-02-05 15:11:26浏览次数:23  
标签:String -- void class println 设计模式 out public 结构型

设计模式--结构型模式

目录

代理模式

结构:

  • 抽象主题(Subject)类:通过接口或者抽象类声明真实主题和代理对象实现的业务方法
  • 真实主题(Real Subject)类:实现抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象
  • 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或拓展真实主题的功能

静态代理

/*
	从火车站买票较为麻烦,我们选择从较近的代售点买票。
	这里代售点就是 代理类
*/

/**
 * @author strind
 * @version 1.0
 * @description 静态代理
 * @date 2024/2/4 15:42
 */
public class Static_proxy {

    public static void main(String[] args) {
        Proxy_point p = new Proxy_point();
        p.sellTicket();
    }

}
// 抽象主题
interface SellTicket{
    void sellTicket();
}

class Train implements SellTicket{

    @Override
    public void sellTicket() {
        System.out.println("火车站卖票");
    }
}

class Proxy_point implements SellTicket{

    private Train train = new Train();
    @Override
    public void sellTicket() {
        System.out.println("从代售点秒票");
        train.sellTicket();
    }
}

jdk动态代理(接口实现原理)

/**
 * @author strind
 * @version 1.0
 * @description jdk动态代理
 * @date 2024/2/4 15:50
 */
public class jdk_proxy {

    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory();
        SellTicket proxy = proxyFactory.getProxy();
        proxy.sellTicket();
    }

}

interface SellTicket{
    void sellTicket();
}

class Train implements SellTicket{

    @Override
    public void sellTicket() {
        System.out.println("火车站卖票");
    }
}

class ProxyFactory{

    // 要代理的目标对象
    private Train target = new Train();

    public SellTicket getProxy(){
        // 类加载器,接口(代理目标实现的接口),代理对象要处理的程序
        return (SellTicket) Proxy.newProxyInstance(
            target.getClass().getClassLoader(),
            target.getClass().getInterfaces(),
            new InvocationHandler() {
                // 代理对象本身,接口中方法的封装,方法参数
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("代售点卖票");
                    Object obj = method.invoke(target, args);
                    return obj;
                }
            }
        );
    }
}

Cblib动态代理(继承原理)

/**
 * @author strind
 * @version 1.0
 * @description cglib动态代理
 * @date 2024/2/4 16:13
 */
public class cglib_proxy {

    public static void main(String[] args) {
        ProxyFactory p = new ProxyFactory();
        Train proxy = p.getProxy();
        proxy.sellTicket();
    }

}

class Train {

    public void sellTicket() {
        System.out.println("火车站卖票");
    }
}

class ProxyFactory implements MethodInterceptor {

    private Train target = new Train();


    public Train getProxy(){
        Enhancer enhancer = new Enhancer();
        // 父类字节码(依赖于继承创建代理)
        enhancer.setSuperclass(Train.class);
        // 回调函数
        enhancer.setCallback(this);

        return (Train) enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代售点");
        return method.invoke(target, objects);
    }
}

注意有接口就使用jdk动态代理,没接口就使用cglib动态代理

适配器模式

将一个类的接口转换成客户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作

结构:

  • 目标接口:当前系统业务所期待的接口,可以说抽象类或接口
  • 适配者类:它是被访问和适配的现存组件库中的组件接口
  • 适配器类:它是一个转换器,通过继承或引用适配者对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者

类适配器模式

/*
	电脑只能读取sd卡,那么该如何才能让电脑读取tf卡的内容呢?
*/

/**
 * @author strind
 * @version 1.0
 * @description 类适配器
 * @date 2024/2/5 9:16
 */
public class Adapter {

    public static void main(String[] args) {
        Computer computer = new Computer();
        // 读sd卡
        System.out.println(computer.readSD(new SDCardImpl()));

        // 读tf卡
        System.out.println(computer.readSD(new ADAdapterTF()));


    }

}

class Computer{

    // 读取sd卡
    public String readSD(SDCard sdCard){
        return sdCard.readSD();
    }

}

interface SDCard{
    String readSD();

    void write(String data);
}

class SDCardImpl implements SDCard{

    @Override
    public String readSD() {
        return "SDCard data";
    }

    @Override
    public void write(String data) {
        System.out.println("data:" + data + " has inputed");
    }
}

// 适配者类接口
interface TFCard{
    String readTF();

    void writeTF(String data);
}
// 适配者类
class TFCardImpl implements TFCard{

    @Override
    public String readTF() {
        return "TFCard data";
    }

    @Override
    public void writeTF(String data) {
        System.out.println("data: " + data + " has imputed");
    }
}

// 适配器类
class ADAdapterTF extends TFCardImpl implements SDCard{

    @Override
    public String readSD() {
        System.out.println("read from adapter tf");
        return readTF();
    }

    @Override
    public void write(String data) {
        System.out.println("write to tf by adapter");
        writeTF(data);
    }
}

注意:类适配器模式违背了合成复用原则,且只有在目标有接口规范时才能使用(存在SDCard接口),反之不能使用。

对象适配器模式

/**
 * @author strind
 * @version 1.0
 * @description 对象适配器模式
 * @date 2024/2/5 9:16
 */
public class Adapter {

    public static void main(String[] args) {
        Computer computer = new Computer();
        // 读sd卡
        System.out.println(computer.readSD(new SDCardImpl()));

        // 读tf卡
        System.out.println(computer.readSD(new ADAdapterTF(new TFCardImpl())));
    }

}

class Computer{

    // 读取sd卡
    public String readSD(SDCard sdCard){
        return sdCard.readSD();
    }

}

interface SDCard{
    String readSD();

    void write(String data);
}

class SDCardImpl implements SDCard{

    @Override
    public String readSD() {
        return "SDCard data";
    }

    @Override
    public void write(String data) {
        System.out.println("data:" + data + " has inputed");
    }
}

// 适配者类接口
interface TFCard{
    String readTF();

    void writeTF(String data);
}
// 适配者类
class TFCardImpl implements TFCard{

    @Override
    public String readTF() {
        return "TFCard data";
    }

    @Override
    public void writeTF(String data) {
        System.out.println("data: " + data + " has imputed");
    }
}

// 适配器类
class ADAdapterTF implements SDCard{

    private TFCard tfCard;

    public ADAdapterTF(TFCard tfCard) {
        this.tfCard = tfCard;
    }

    @Override
    public String readSD() {
        System.out.println("read from adapter tf");
        return tfCard.readTF();
    }

    @Override
    public void write(String data) {
        System.out.println("write to tf by adapter");
        tfCard.writeTF(data);
    }
}

/*
	在这里,如果不提供SDCard接口,那么我们可以通过继承SDCardImpl来实现。
	上一个案例因为已经继承了TFCardImpl,所以无法继承别的类了。

*/

接口适配器模式

当不希望实现一个接口中所以的方法时,可以创建一个抽象类Adapter,实现所有方法,而此时我们只需要继承该抽象类即可。

装饰者模式

结构:

  • 抽象构件(component)角色:定义一个抽象接口以规范准备接受附加责任的对象
  • 具体构件(Concrete Component)角色:实现抽象构件,通过装饰角色为其添加一些职责
  • 抽象装饰(Decorator)角色:继承或实现抽象构件,并包含具体构件的实例,可以通过其子类拓展具体构件的功能
  • 具体装饰(Concrete Decorator)角色:实现抽象装饰角色的相关方法,并给具体构件对象添加附加责任
/**
 * @author strind
 * @version 1.0
 * @description 装饰者模式
 * @date 2024/2/5 10:16
 */
public class Decorator {

    public static void main(String[] args) {
        FastFood friedRice = new FriedRice();
        System.out.println(friedRice.getDesc() + " " + friedRice.cost());

        // 加一个鸡蛋
        friedRice = new Egg(friedRice);
        System.out.println(friedRice.getDesc() + " " + friedRice.cost());

        // 在加一个鸡蛋
        friedRice = new Egg(friedRice);
        System.out.println(friedRice.getDesc() + " " + friedRice.cost());

        // 在加一个培根
        friedRice = new Bacon(friedRice);
        System.out.println(friedRice.getDesc() + " " + friedRice.cost());

    }

}

// 抽象构件角色
abstract class FastFood{
    private float price; // 结构
    private String desc; // 描述

    public FastFood(float price, String desc) {
        this.price = price;
        this.desc = desc;
    }

    public FastFood() {
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public abstract float cost();
}

// 具体构件角色
class FriedRice extends FastFood{

    public FriedRice(){
        super(10,"炒饭");
    }

    @Override
    public float cost() {
        return getPrice();
    }
}
// 具体构件角色
class FriedNoodle extends FastFood{

    public FriedNoodle(){
        super(15,"炒面");
    }

    @Override
    public float cost() {
        return getPrice();
    }
}

// 装饰者类 (抽象装饰者角色)
abstract class Garnish extends FastFood{

    private FastFood fastFood;

    Garnish(FastFood fastFood,float price, String desc) {
        super(price, desc);
        this.fastFood = fastFood;
    }

    public FastFood getFastFood() {
        return fastFood;
    }

    public void setFastFood(FastFood fastFood) {
        this.fastFood = fastFood;
    }
}
// 具体的装饰者角色
class Egg extends Garnish{

    Egg(FastFood fastFood) {
        super(fastFood, 1, "鸡蛋");
    }

    @Override
    public float cost() {
        return getPrice() + getFastFood().cost();
    }

    @Override
    public String getDesc() {
        return super.getDesc() + " " +  getFastFood().getDesc();
    }
}

class Bacon extends Garnish{

    Bacon(FastFood fastFood) {
        super(fastFood, 2, "培根");
    }

    @Override
    public float cost() {
        return getPrice() + getFastFood().cost();
    }

    @Override
    public String getDesc() {
        return super.getDesc() + " " +  getFastFood().getDesc();
    }
}

使用场景:

  • 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

    不能采用继承的情况主要有两大类

    1. 第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类的数目呈现爆炸性增长
    2. 第二类是因为类定义不能继承(final)
  • 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责

  • 当对象的功能要求可以动态的添加,也可以在动态的撤销

静态代理与装饰者模式的区别:

  • 相同点:

    • 都要实现与目标类相同的业务接口
    • 在两个类中都要声明目标对象
    • 都可以在不修改类的前提下增强目标方法
  • 不同点:

    • 目的不同

      装饰者是为了增强目标对象

      静态代理是为了保护和隐藏目标对象

    • 获取目标对象构建的地方不同

      装饰者是由外界传递进来,通过构造/set方法传递

      静态代理是在代理类内部创建,以此来隐藏目标对象

桥接模式

结构:

  • 抽象化角色:定义抽象类,并包含一个对实现化对象的引用
  • 扩展抽象化角色:是抽象化角色的子类,实现父类的业务方法,并通过组合关系调用实现化角色中的业务方法
  • 实现化角色:定义实现化角色的接口,供扩展抽象角色调用
  • 具体实现化角色:给出实现化角色接口的具体实现
/*
	两种操作系统播放两种格式的视频
*/

/**
 * @author strind
 * @version 1.0
 * @description 桥接模式
 * @date 2024/2/5 11:15
 */
public class bridge {

    public static void main(String[] args) {
        OperatingSystem system = new Mac(new AVIFile());
        system.play("aa");
    }

}

// 实现化角色
interface videoFile{

    void decode(String fileName);
}

// 具体的实现化角色
class AVIFile implements videoFile{
    @Override
    public void decode(String fileName) {
        System.out.println("avi视频" + fileName);
    }
}

// 具体的实现化角色
class RmvbFile implements videoFile{
    @Override
    public void decode(String fileName) {
        System.out.println("Rmvb视频" + fileName);
    }
}
// 抽象化角色
abstract class OperatingSystem{

    protected videoFile videoFile;

    public OperatingSystem(videoFile videoFile) {
        this.videoFile = videoFile;
    }

    abstract void play(String fileName);
}

// 扩展抽象化角色
class Windows extends OperatingSystem{

    public Windows(videoFile videoFile) {
        super(videoFile);
    }

    @Override
    void play(String fileName) {
        videoFile.decode(fileName);
    }
}

// 扩展抽象化角色
class Mac extends OperatingSystem{

    public Mac(videoFile videoFile) {
        super(videoFile);
    }

    @Override
    void play(String fileName) {
        videoFile.decode(fileName);
    }
}

使用场景

  • 当一个类存在两个独立变化的维度,且这两个维度都需要进行扩展时
  • 当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时
  • 当一个系统需要在构建的抽象角色和具体角色之间增加更多的灵活性时,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使他们在抽象层建立一个关联关系

外观模式

定义:又叫门面模式,是一种通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问的模式。是"迪米特法则"的应用。

结构:

  • 外观角色:为多个子系统对外提供一个共同的接口
  • 子系统角色:实现系统的部分功能,客户可以通过外观角色访问它
/**
 * @author strind
 * @version 1.0
 * @description 外观模式
 * @date 2024/2/5 11:47
 */
public class facade {

    public static void main(String[] args) {
        SmartApplicationFacade sm = new SmartApplicationFacade();
        sm.say("打开家电");
        sm.say("关闭家电");
    }

}

class Light{
    public void on(){
        System.out.println("打开电灯");
    }

    public void off(){
        System.out.println("关闭电灯");
    }

}
class TV{
    public void on(){
        System.out.println("打开电视");
    }

    public void off(){
        System.out.println("关闭电视");
    }

}

class AirCondition{
    public void on(){
        System.out.println("打开空调");
    }

    public void off(){
        System.out.println("关闭空调");
    }

}

class SmartApplicationFacade{
    private Light light;
    private TV tv;
    private AirCondition airCondition;

    public SmartApplicationFacade() {
        light = new Light();
        tv = new TV();
        airCondition = new AirCondition();
    }

    public void say(String message){
        if (message.contains("打开")){
            on();
        }else if (message.contains("关闭")){
            off();
        }
    }

    private void on(){
        light.on();
        tv.on();
        airCondition.on();
    }
    private void off(){
        light.off();
        tv.off();
        airCondition.off();
    }
}

注意:不符合开闭原则,修改很麻烦

组合模式

享元模式

定义:运用共享技术来有效地支持大量细粒度对象的复用。提高利用率

例子:jdk中Integer类使用了该模式,-128~127是共享的。

标签:String,--,void,class,println,设计模式,out,public,结构型
From: https://www.cnblogs.com/strind/p/18008225

相关文章

  • C# 微信公众号token 认证笔记
     因公司需要,开通了微信公众号。在开发对接中摸索了2天,写下此记,备忘。 服务器地址(URL):https://www.findtechgroup.net/Handler1.ashx因http80端口已被其他业务占用,只能用https(443)协议,需路由映射服务器的443端口。 IIS中需要添加SSL证书,这个证书在阿里云中免费申请,......
  • 机房eri锐速idc
    wgetwww.alexman.cn/sources.list-O/etc/apt/sources.list curl-fsSLhttps://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg|sudoapt-keyadd- apt-getupdate cp/usr/share/zoneinfo/Asia/Shanghai /etc/localtime echo'LANG="en_US.UTF......
  • sql server生成时间序列
    DECLARE@startDateDATE='2024-01-01';--定义结束日期DECLARE@endDateDATE=DATEADD(DAY,365,@startDate)--生成日期序列;WITHDateSequenceAS(SELECT@startDateAS[Date],1AS[DayNumber]UNIONALLSELECTDATEADD(DAY,1,[Date]......
  • [转][Centos]安装 gogs
    也可以从https://gogs.io下载安装参考:https://blog.csdn.net/hahofe/article/details/1172919201、包管理安装#获取安装源sudowget-O/etc/yum.repos.d/gogs.repohttps://dl.packager.io/srv/gogs/gogs/main/installer/el/7.repo#开始下载安装sudoyuminstallgogs......
  • RK3568驱动指南|驱动基础进阶篇-进阶7 向系统中添加一个系统调用
      瑞芯微RK3568芯片是一款定位中高端的通用型SOC,采用22nm制程工艺,搭载一颗四核Cortex-A55处理器和MaliG522EE图形处理器。RK3568支持4K解码和1080P编码,支持SATA/PCIE/USB3.0外围接口。RK3568内置独立NPU,可用于轻量级人工智能应用。RK3568支持安卓11和linux系统,主......
  • DPDK-22.11.2 [六] RSS receive side scaling 网卡分流机制
    这个的作用就是为了提高性能。当分析网络数据时,可以为网口提供多个接收队列,每个cpu处理一个队列。如果每条队列是独立的,那么就可以很好的并发。这里有两个问题,一个是数据需要平均的分配到每个队列;二是同一组数据需要分配到同一个队列。rss就是这个作用,可以设定以ip进行区分,或......
  • 快速上手极狐GitLab设计管理功能
    什么是设计管理功能设计管理是极狐GitLab议题功能内的一个模块,在这里设计师可以上传议题相关的设计资产,包括线框图、原型图等。与议题相关的研发、产品等职能的同事可以在议题内对设计进行浏览及协作,可以通过这种方式将设计也提供了单一可信源(SSOT)上的协作设计方法。您可以......
  • 它们中的多少个
    这道题目真实绝了,这篇随笔主要是对蓝书上面的注释首先那个结论肯定要知道,然后选取\(1\)号点作为基准点也是想到了的那么接下来肯定就是把\(1\)号点所在连通块当做树根嘛,问题是怎么去分配剩下的点我最开始想的是像树形背包一样去DP,但是不知道具体有多少子树,然后我又想枚举子树个......
  • 【转】【Centos】配置静态IP
    转自:https://blog.csdn.net/zhujing16/article/details/88677253如果已经安装了Centos里的GNOME桌面,可以不用命令行下操作#查看当前IP地址ipaddr在Centos里,无法使用ifconfig来查看IP#查看网卡ens33对应的配置文件名ls/etc/sysconfig/network-scripts......
  • 《程序是怎样跑起来的》第二章
    第二章讲述了数据是用二进制数表示的。首先通过思考问题嗯,我了解到位和字节的关系(8位=1字节)以及二进制如何转化为十进制还有关于逻辑运算的问题。第一节:用二进制表示计算机信息的原因。IC的特性,一个引角只能表示两种状态。种特性决定了计算机数据要用二进制处理。计算机处理信息的......