学点设计模式,盘点Spring等源码中与设计模式的那些事之结构型模型

学点设计模式,盘点Spring等源码中与设计模式的那些事之结构型模型

首先,我们先要了解结构型设计模式都包括哪些:适配器模式(Adapter)、桥接模式(Bridge)、过滤器模式(Filter)、组合模式(Composite)、装饰器模式(Decorator/Wrapper)、外观模式(Facade)、享元模式(Flyweight)、代理模式(Proxy)

结构型模型主要关注怎样组合对象或者类,所以结构型模式又分为类结构模式(类的组合,继承)和对象结构模式(类与对象的组合,关联关系)。又因为合成复用原则告诉我们,要尽量使用关联关系代替继承关系,所以结构模型大多数都是对象结构模型。

1、适配器模式

  • 定义:将一个接口转换成用户希望的另一个接口,使接口不兼容的类可以一起工作
  • 举例:日本人想要观看咱们中国的电影,我们不直接去修改电影播放器让其出现双语字母,而是新建一个适配器,让外国人使用适配器播放,适配器带有语言转换的能力。
    在这里插入图片描述
    对于这个场景,既可以使用类结构(继承)也可以使用对象结构(组合),代码没啥差别,下边采用对象结构实现
//播放器接口
public interface Player {
    String play();
}
//翻译器接口
public interface Translator {
    String translate(String content);
}
//播放器实现
public class MoviePlayer implements Player {
    @Override
    public String play() {
        System.out.println("正在播放:java从入门到精通");
        String content = "你好";
        System.out.println(content);
        return content;
    }
}
//转换器实现
public class Zh_JPTranslator implements Translator{
    @Override
    public String translate(String content) {
        if("你好".equals(content)){
            return "空尼几哇";
        }
        if ("什么".equals(content)){
            return "纳尼";
        }
        return "*******";
    }
}
//播放器适配器
public class JPMoviePlayerAdapter implements Player {
    //组合的方式
    private Translator translator = new Zh_JPTranslator();
    private Player target;//被适配对象
    public JPMoviePlayerAdapter(Player target){
        this.target = target;
    }

    @Override
    public String play() {
        String play = target.play();
        //转换字幕
        String translate = translator.translate(play);
        System.out.println("日文:"+translate);
        return play;
    }
}

在这里插入图片描述

  • 核心:系统中所有原有的东西都不能修改,扩展一个新的类,来连接两个之前不同的类

2、桥接模式

  • 定义:将抽象与实现解耦,使两者都可以独立变化(真正引起类变化的维度抽取出来),桥接将继承转为关联,降低类之间的耦合度,减少代码量。

  • 举个栗子:有两种手机,拍照手机和性能手机,两种手机在线上和线下的价格都不同,考虑这个类里边的一些东西会扩展很多,就应该把这个东西分离出来。
    在这里插入图片描述

  • 代码示例:

/**
 * 1、抽象手机类
 *  手机有各种销售渠道价格都不一样
 */
public abstract class AbstractPhone {
    //【真正会引起此类变化的一个维度直接抽取出来,通过组合的方式接起来】
    AbstractSale sale; //分离渠道【桥接的关注点】
    
    //当前手机的描述
    abstract String getPhone();

    public void setSale(AbstractSale sale) {
        this.sale = sale;
    }
}

/**
 * 抽象销售渠道
 */
public abstract class AbstractSale {

    private String type;
    private Integer price;
    public AbstractSale(String type,Integer price){
        this.type = type;
        this.price = price;
    }

    String getSaleInfo(){
        return "渠道:"+type+"==>"+"价格:"+price;
    }
}

//哪种手机,根据手机种类实现......多个
public class PhotoPhone extends AbstractPhone{
    @Override
    String getPhone() {
        return "PhotoPhone:"+sale.getSaleInfo();
    }
}

/**
 * 线上渠道,根据渠道实现......多个
 */
public class OnlineSale extends AbstractSale{
    public OnlineSale(String type, Integer price) {
        super(type, price);
    }
}

//TestClass
public class MainTest {
    public static void main(String[] args) {
        //拍照手机的线上渠道
        PhotoPhone iPhone = new PhotoPhone();
        iPhone.setSale(new OnlineSale("线上",2599));

        String phone = iPhone.getPhone();
        System.out.println(phone);
    }
}

3、装饰器模式

  • 定义:创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能
  • 对比适配器模式:适配器是连接两个类,可以增强一个类;装饰器是只增强一个类不用连接两个类。
    附一个网上很常见的例子
  • 代码示例
//附一个网上很常见的例子,给图像增加颜色
//抽象的图像
public interface Shape {
   void draw();
}

//具体的图像:圆......可以多个,这里只示例一个
public class Circle implements Shape {
   @Override
   public void draw() {
      System.out.println("Shape: Circle");
   }
}

//抽象的装饰类
public abstract class ShapeDecorator implements Shape {
   protected Shape decoratedShape;
 
   public ShapeDecorator(Shape decoratedShape){
      this.decoratedShape = decoratedShape;
   }
   public void draw(){
      decoratedShape.draw();
   }  
}

//具体的装饰类
public class RedShapeDecorator extends ShapeDecorator {
 
   public RedShapeDecorator(Shape decoratedShape) {
      super(decoratedShape);     
   }
   @Override
   public void draw() {
      decoratedShape.draw();         
      setRedBorder(decoratedShape);
   }
   private void setRedBorder(Shape decoratedShape){
      System.out.println("Border Color: Red");
   }
}

4、代理模式

  • 定义:给某一个对象提供一个代理,并由代理对象控制对原对象的引用

  • 代理模式又分为静态代理和动态代理,静态代理和装饰器十分相似,所以大家经常认为装饰器是代理的一种。

下面来看一下动态代理

  • jdk动态代理示例
    在这里插入图片描述
//一个抖音直播例子
//首先,来两个抽象接口,因为JDK要求被代理对象必须有接口
//抽象的跳舞接口
public  interface DanceTikTok {
   void dance();
}
//抽像的卖货接口
public interface SellTikTok {
    void sell();
}
//实现这两个接口
public class MyTikTok implements DanceTikTok,SellTikTok {
    @Override
    public void dance() {
        System.out.println("跳个舞......");
    }
    @Override
    public void sell() {
        System.out.println("3,2,1 上车......");
    }
}
//动态代理核心类,万能代理类
public class JdkTiktokProxy<T> implements InvocationHandler {

    private T target;
    //接受被代理对象
    JdkTiktokProxy(T target){
        this.target = target;
    }

    //获取被代理对象的  代理对象
    public static<T> T getProxy(T t) {
        /**
         * ClassLoader loader, 当前被代理对象的类加载器
         * Class<?>[] interfaces, 当前被代理对象所实现的所有接口
         * InvocationHandler h,
         *  当前被代理对象执行目标方法的时候我们使用h可以定义拦截增强方法
         */
        Object o = Proxy.newProxyInstance(
                t.getClass().getClassLoader(),
                t.getClass().getInterfaces(), //必须接口
                new JdkTiktokProxy(t));
        return (T)o;
    }
    
    //定义目标方法的拦截逻辑;每个方法都会进来的
    @Override
    public Object invoke(Object proxy,
                         Method method,
                         Object[] args) throws Throwable {
        //反射执行
        System.out.println("真正执行被代理对象的方法");
        Object invoke = method.invoke(target, args);
        System.out.println("执行完返回......");
        return invoke;
    }
}
  • cglib动态代理(使用cglib时记得加依赖)

  • cglib在底层通过直接操作字节码的方式,使用继承的方式得到目标对象方法。

  • 代码演示:

//要被代理增强的类
public class MyTikTok {
    public void tiktok() {
        System.out.println("开始直播....");
    }
}
//cglib核心代码
public class CglibProxy {

    //为任意对象创建代理
    public static<T> T createProxy(T t){
        //1、创建一个增强器
        Enhancer enhancer = new Enhancer();

        //2、设置要增强哪个个类的功能。增强器为这个类动态创建一个子类
        enhancer.setSuperclass(t.getClass());

        //3、设置回调
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj,
                                    Method method,
                                    Object[] args,
                                    MethodProxy proxy) throws Throwable {
                //编写拦截的逻辑
                System.out.println("cglib开场秀 .......");
                //目标方法进行执行
                Object invoke = proxy.invokeSuper(obj,args);
                return invoke;
            }
        });

        Object o = enhancer.create();
        return (T) o;
    }
}
//测试
public class CglibTest {
    public static void main(String[] args) {
        MyTikTok tikTok = new MyTikTok();
        MyTikTok proxy = CglibProxy.createProxy(tikTok);
        proxy.tiktok();
    }
}

5、组合模式

  • 定义:把一组相似的对象当作一个单一的对象。将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
    在这里插入图片描述
//部分代码展示
public class Menu {

    private Integer id;
    private String name;
    public Menu(Integer id,String name){
        this.id = id;
        this.name = name;
    }

    //组合模式关注点
    private List<Menu> childs = new ArrayList<>();

    //提供添加层级的方法
    void addChildMenu(Menu menu){
        childs.add(menu);
    }

    //层级遍历方法
    void printMenu(){
        System.out.println(name);
        if(childs.size() > 0){
            for (Menu child : childs) {
                child.printMenu();
            }
        }
    }
}
  • 组合模式的优缺点:
    • 优点:1、高层模块调用简单。 2、节点自由增加。
    • 缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

6、外观模式

  • 定义:通过为多个复杂的子系统提供一个一致的接口,而使这些子系统更加容易被访问
  • 举例:比如你现在想在一个城市定居落户,你需要去公安局办理身份证,监狱局认证学籍,社保局交社保,来回跑比较麻烦,这时政府推出了一个微信小程序,在小程序上就可以办理完所有的事。
    在这里插入图片描述
//办一个新身份证
public class Police {
    public void resgister(String name){
        System.out.println(name + "办一个新身份证");
    }
}
//存学籍档案
public class Edu {
    public void school(String name){
        System.out.println(name+"存学籍档案");
    }
}
//开通当地社保
public class Social {
    public void handleSocial(String name){
        System.out.println(name+"开通当地社保");
    }
}
//落户小程序
public class WeiXinFacade {

    Police police = new Police();
    Edu edu = new Edu();
    Social social = new Social();

    public void handleXxx(String name){
        police.resgister(name);
        edu.school(name);
        social.handleSocial(name);
    }
}
//Test......

7、享元模式

  • 定义:现在有很多对象需要大量重复的使用,考虑到使用池化技术,享元模式就是来告诉我们使用池化技术应该怎么考虑的。
  • 举例:比如一个店里有很多的服务员,如果某个服务员处于空闲状态,那么我们每个人都可以叫这些服务员为我们服务。
    在这里插入图片描述
/**
 * 可共享和不可共享状态
 */
public abstract class AbstractWaitressFlyweight {

    boolean canService = true;//能否服务

    //正在服务。   享元的不可共享属性留给外部进行改变的接口
    abstract void service();
    //服务完成。   享元的不可共享属性留给外部进行改变的接口
    abstract void end();

    public boolean isCanService() {
        return canService;
    }
}
/**
 * 具体享元类
 */
@AllArgsConstructor
public class BeautifulWaitress extends AbstractWaitressFlyweight{
    String id;//工号
    String name;//名字
    int age;//年龄
    //以上是不变的

    @Override
    void service() {
        System.out.println("工号:"+id+";"+name+" "+age+" 正在为您服务...");
        //改变外部状态
        this.canService = false;
    }

    @Override
    void end() {
        System.out.println("工号:"+id+";"+name+" "+age+" 服务结束...请给五星好评");
        this.canService = true;
    }
}
//享元工厂
public class Shop {
    private static Map<String,AbstractWaitressFlyweight> pool = new HashMap<>();
    //享元,池子中有对象
    static {
        BeautifulWaitress waitress =
                new BeautifulWaitress("1111","张三",18);

        BeautifulWaitress waitress2 =
                new BeautifulWaitress("9527","李四",20);
        
        pool.put(waitress.id,waitress);
        pool.put(waitress2.id,waitress2);
    }

    public static AbstractWaitressFlyweight getWaitress(String name){
        AbstractWaitressFlyweight flyweight = pool.get(name);
        if(flyweight == null){
            for (AbstractWaitressFlyweight value : pool.values()) {
                //当前共享对象能否服务
                if(value.isCanService()){
                    return value;
                }
            };
            return null;
        }
        return flyweight;
    }
}
//Test......
  • 享元模式优缺点
    • 优点:大大减少对象的创建,降低系统的内存,使效率提高。
    • 缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。

结构型模型到这里就学习完了,下一篇:行为型模型…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Anton丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值