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

设计模式--结构型模式

时间:2024-02-12 11:33:06浏览次数:26  
标签: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/18013750

相关文章

  • 目录
    《天下第一道序》写出来了,当前环境不适合做一个道德君子。《01-三种人性的人》讲解了社会上三种人性的人《18-狠人》《19-坏人》《20-坏人的片面思想》《21-坏人的思想》《22-坏人的优点》《62-坏人的信任》《40-天下第一鬼道》《175-天下第一道与坏人》《56-小人、伪君子、漂亮......
  • Python 机器学习 线性回归和岭回归
    ​ Python机器学习中,机器学习领域的线性回归和岭回归是两种常用的回归分析方法,用于预测一个或多个自变量(或称为特征)和因变量(或称为目标变量)之间的关系。这两种方法都试图找到最佳的线性组合来预测目标变量,但它们在处理数据的方法上有所不同。线性回归和岭回归都是常用的线性回......
  • VSCode的configuration错误
    问题首先通过报错语句,定位到错误代码。通过上图的报错语句,定位到了我的错误代码在train.py文件中parser.add_argument方法的问题,截图如下:  通过百度parser.add_argument语句,发现当required参数为True时,在运行时必须要为该命令指定路径。从上图可以看到第一条parser.add_ar......
  • JOISC 2017 题解
    JOISC2017loj上有几乎全部的题目,写了题意的就是loj上没有的。D1T1开场放大。首先,对于一个点,它最后覆盖的一定是一个矩形,这就意味着如果我们知道了\(u,d,l,r\)操作各用了多少次,他们之间的顺序是不重要的,我们可以直接当做把一种操作做完再做剩下的操作,这样就可以做到\(O(......
  • 牛客2.7比赛E,F题
    链接:https://ac.nowcoder.com/acm/contest/67743/E来源:牛客网智乃最近学习了冒泡排序和最长子段和,所以她现在想把它们合并成一个新的算法。众所周知,冒泡排序是一种通过交换相邻元素实现排序的算法,最长子段和是指从一个数组aaa中取出一段连续的非空数组区间[l,r][l,r][l,r],最大......
  • 如何获取多看阅读APP中的文件
    背景之前在多看里上传的一个txt小说,其原文件找不到了尝试多看APP里尝试查看文件路径,找不到MIUI自带的文件管理器,搜索文件名称,搜不到搜索duokan文件夹,里面只有一些db文件过程1.读取db既然能搜到duokan文件夹,且有db文件,就读取一下吧conn=sqlite3.connect('d:/Bookshel......
  • .NET(C#)遍历(for,foreach,while)字典(Dictionary)的几种方法
    ​ .NET(C#)中,Dictionary<TKey,TValue>是一种非常实用的集合类型,用于存储键值对的集合。遍历Dictionary的方法有多种,包括使用for循环、foreach循环和while循环。使用foreach循环是遍历Dictionary中所有键值对最常见和最简单的方法。for和while循环在遍历Dic......
  • 在k8S中,如何保证集群的安全性?
    在Kubernetes(k8s)中,确保集群的安全性需要从多个层面进行考虑和实施措施。以下是一些关键的策略和实践:网络安全:网络策略(NetworkPolicies):定义Pod间的网络通信规则,控制进出Pod的流量。防火墙与访问控制:配置节点防火墙限制对集群节点不必要的外部访问,仅允许来自受信任来源的......
  • 深度学习的始祖框架,grandfather级别的框架 —— Theano —— 示例代码学习(2)
    代码1:(ifelse判断结构)importtheanofromtheanoimporttensorfromtheano.ifelseimportifelsex=tensor.fscalar('x')y=tensor.fscalar('y')z=ifelse(x>0,2*y,3*y)#x>0的返回值是int8类型f=theano.function([x,y],z,allow_input_down......
  • 在k8S中,Kubernetes 准入机制是什么?
    在Kubernetes(k8s)中,准入控制机制(AdmissionControl)是一个关键的安全和策略执行层。它位于APIServer层级,在接收到对集群资源的创建、更新或删除请求后、但实际操作存储在etcd中的数据之前的一个环节。准入控制器是一系列插件式的组件,它们会对发送到APIServer的每个请求进行拦截和......