3.设计模式之后七种模式桥接装饰者组合外观享元代理模板

news2024/12/28 20:44:08

1.桥接模式 bridge(抽象类的实现的子类,通过聚合间接调用接口方法 就是桥)

  1. 实现和抽象分开,使他可以独立改变
  2. 结构型设计模式
  3. 基于类的最小设计原则(增加功能,增加最少个数的类),通过封装 聚合和继承让不同类实现不同职责
    图 23桥接模式原理图
    请添加图片描述

图 26桥接模式传统解决手机操作问题
请添加图片描述

图 24桥接模式解决手机操作问题
请添加图片描述

图 27桥接模式代码结构
请添加图片描述

--------传统方式实现,需要先实现后继承------

public interface Phone {
    void open();
    void call();
    void close();
}

public class Folded implements Phone {

    @Override
    public void open() {
        System.out.println("折叠手机开机");
    }

    @Override
    public void call() {
        System.out.println("折叠手机打电话");
    }

    @Override
    public void close() {
        System.out.println("折叠手机关机");

    }
}
public class VIVOFold extends Folded {

    public void open() {
        super.open();
        System.out.println("VIVO手机开机");
    }


    public void call() {
        super.call();
        System.out.println("VIVO手机打电话");
    }


    public void close() {
        super.close();
        System.out.println("VIVO手机关机");
    }
}
public class XIAOMIFold extends Folded {
    @Override
    public void open() {
        super.open();
        System.out.println("小米手机开机");
    }

    @Override
    public void call() {
        super.call();
        System.out.println("小米手机打电话");
    }

    @Override
    public void close() {
        super.close();
        System.out.println("小米手机关机");
    }
}

public class UpRight implements Phone {
    @Override
    public void open() {
        System.out.println("直立手机开机");
    }

    @Override
    public void call() {
        System.out.println("直立手机打电话");
    }

    @Override
    public void close() {
        System.out.println("直立手机关机");

    }
}
public class VIVOUpRight extends UpRight {

    public void open() {
        super.open();
        System.out.println("VIVO手机开机");
    }


    public void call() {
        super.call();
        System.out.println("VIVO手机打电话");
    }


    public void close() {
        super.close();
        System.out.println("VIVO手机关机");
    }
}
public class XIAOMIUpRight extends UpRight {
    @Override
    public void open() {
        super.open();
        System.out.println("小米手机开机");
    }

    @Override
    public void call() {
        super.call();
        System.out.println("小米手机打电话");
    }

    @Override
    public void close() {
        super.close();
        System.out.println("小米手机关机");
    }
}
//测试类
public class Client {
    public static void main(String[] args) {
        Phone phone=new VIVOFold();
        phone.open();
        phone.call();;
        phone.close();
        System.out.println("--------------");
        Phone phone1=new XIAOMIFold();
        phone1.open();
        phone1.call();;
        phone1.close();
        System.out.println("--------------");
        Phone phone2=new XIAOMIUpRight();
        phone2.open();
        phone2.call();;
        phone2.close();
    }
}


---改进的代码----------
   //1. 写桥接接口 子类实现接口
public interface BrandBridge {
    void open();
    void call();
    void close();
}
public class Vivo implements BrandBridge {
    @Override
    public void open() {
        System.out.println("vivo打开手机");
    }

    @Override
    public void call() {
        System.out.println("vivo打电话");
    }

    @Override
    public void close() {
        System.out.println("vivo关闭手机");

    }
}
public class XiaoMi implements BrandBridge {
    @Override
    public void open() {
        System.out.println("xiaomi打开手机");
    }

    @Override
    public void call() {
        System.out.println("xiaomi打电话");
    }

    @Override
    public void close() {
        System.out.println("xiaomi关闭手机");

    }
}


    //2.再写手机类, 聚合桥接类,写继承的手机子类
       public class Phone {
    BrandBridge brand;
    Phone(BrandBridge brand){
        this.brand=brand;
    }
    void open(){
        brand.open();
    }
    void call(){
        brand.call();
    }
    void close(){
        brand.close();
    }


}
  public class FoldedPhone extends Phone {
    public FoldedPhone(BrandBridge brand) {
        super(brand);
    }
    public void open(){
        System.out.println("折叠手机");
        super.open();
    }
    public void call(){
        System.out.println("折叠手机");
        super.call();
    }
    public void close(){
        System.out.println("折叠手机");
        super.close();
    }


}
//设计模式好不好用主要看客户端调用方便
public class Client {
    public static void main(String[] args) {
        FoldedPhone foldedPhone = new FoldedPhone(new Vivo());
        foldedPhone.open();
        foldedPhone.call();
        foldedPhone.close();
        System.out.println("====================");
        UpRightPhone upRightPhone = new UpRightPhone(new XiaoMi());
        upRightPhone.open();
        upRightPhone.call();
        upRightPhone.close();


    }
}

//总结: 如果我想一个类拓展性好, 那我先写桥接接口 再子类实现
//然后写个这个类聚合,然后子类调用桥接类方法,
//一句话: 逆序写代码…

2.桥接模式在JDBC的应用(与标准的有出入)
图 25桥接模式在JDBC源码分析 DriverManager是桥接类(不变的部分),(增加的部分是) ConnectionImpl …Oracle…
请添加图片描述

  1.调用了getConnection方法返回Connection对象
 Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jams", "root", "root");
  //源代码 getConnection()方法
  @CallerSensitive
public static Connection getConnection(String url,
    String user, String password) throws SQLException {
    java.util.Properties info = new java.util.Properties();

    if (user != null) {
        info.put("user", user);
    }
    if (password != null) {
        info.put("password", password);
    }

    return (getConnection(url, info, Reflection.getCallerClass()));
}

//往里面找

 //  Worker method called by the public getConnection() methods.
    private static Connection getConnection(
        String url, java.util.Properties info, Class<?> caller) throws SQLException {
     
        ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
        synchronized(DriverManager.class) {
            // synchronize loading of the correct classloader.
            if (callerCL == null) {
                callerCL = Thread.currentThread().getContextClassLoader();
            }
        }

        if(url == null) {
            throw new SQLException("The url cannot be null", "08001");
        }

        println("DriverManager.getConnection(\"" + url + "\")");

        // Walk through the loaded registeredDrivers attempting to make a connection.
        // Remember the first exception that gets raised so we can reraise it.
        SQLException reason = null;

        for(DriverInfo aDriver : registeredDrivers) { //我认为这里可能使用了桥接模式,寻找对应的驱动,找到mysql驱动返回
            // If the caller does not have permission to load the driver then
            // skip it.
            if(isDriverAllowed(aDriver.driver, callerCL)) {
                try {
                    println("    trying " + aDriver.driver.getClass().getName());
                    Connection con = aDriver.driver.connect(url, info);  //这里调用了Driver类实际上调用了DriverManager的 DriverManager.registerDriver(new Driver());,桥接了DriverManager
             //他的这个聚合直接使用静态类实现....
                    if (con != null) {
                        // Success!  
                        println("getConnection returning " + aDriver.driver.getClass().getName());
                        return (con);  
                    }
                } catch (SQLException ex) {
                    if (reason == null) {
                        reason = ex;
                    }
                }

            } else {
                println("    skipping: " + aDriver.getClass().getName());
            }

        }

        // if we got here nobody could connect.
        if (reason != null)    {
            println("getConnection failed: " + reason);
            throw reason;
        }

        println("getConnection: no suitable driver found for "+ url);
        throw new SQLException("No suitable driver found for "+ url, "08001");
    }
   //aDriver.driver.connect(url, info); 方法有DriverManager
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}
//public class NonRegisteringDriver implements Driver的类中
    public Connection connect(String url, Properties info) throws SQLException {
        if (url != null) {
            if (StringUtils.startsWithIgnoreCase(url, "jdbc:mysql:loadbalance://")) {
                return this.connectLoadBalanced(url, info);
            }

            if (StringUtils.startsWithIgnoreCase(url, "jdbc:mysql:replication://")) {
                return this.connectReplicationConnection(url, info);
            }
        }

        Properties props = null;
        if ((props = this.parseURL(url, info)) == null) {
            return null;
        } else {
            try {
                com.mysql.jdbc.Connection newConn = ConnectionImpl.getInstance(this.host(props), this.port(props), props, this.database(props), url); //ConnectionImpl其实是Mysql连接的类,没有注册过类,则默认注册mysql
                return newConn;
            } catch (SQLException var6) {
                throw var6;
            } catch (Exception var7) {
                SQLException sqlEx = SQLError.createSQLException(Messages.getString("NonRegisteringDriver.17") + var7.toString() + Messages.getString("NonRegisteringDriver.18"), "08001");
                sqlEx.initCause(var7);
                throw sqlEx;
            }
        }
    }

//总结: 1.如何学会看源代码 ,先看类的头部关系画uml类图(一个一个点进去,逐步画类 然后找类和类的关系),然后debug调试运行过程

3.优缺点

  1. 提高系统灵活性.帮助系统分层设计
  2. 桥接替代多层继承,可以减少类爆炸问题,减低系统维护成本
  3. 增加系统理解难度
  4. 要正确区分系统独立变化的2个维度(抽象和实现)

4.应用场景(一句话,代码需要增加分类功能 可以采用聚合调用聚合的方法)

  1. jdbc驱动
  2. 银行转账 普通用户(抽象 不变) 和网上转账(实现 后期增加的)
  3. 消息分类 消息类型:即时消息和延时消息(抽象) 消息分类: 数据短信 QQ消息(实现)

5.装饰者模式(工作常用)

图28装饰者模式原理图
请添加图片描述

图31装饰者模式星巴克咖啡传统
请添加图片描述

  1. 星巴克咖啡订单问题(计算不同搭配的钱/单品咖啡)导致类爆炸(排列组合实现cost方法)
  2. 改进为装饰者(使用非常方便,并且只加一个类就可以与其他类组合) 满足ocp原则
    图 29装饰者模式星巴克咖啡改进
    请添加图片描述
                   Drink coffee=new Coffee(); 
                        coffee.cost();//计算多少钱
                   Drink add=new Chocolate(coffee);
                      add.cost(); //计算咖啡和巧克力的全部费用
                      
              像打包一个快递 :主体(Component)  衣服 陶瓷 被装饰者
                                        包装(Decorator) 泡沫 木板    装饰者(递归加上价格)

-----全部代码-------
//全部方法和成员由父类创建 继承给子类调用

//1.创建抽象类

public abstract class Drink {
    private String desciption;
    private float price;

    public String getDesciption() {
        return desciption;
    }

    public void setDesciption(String desciption) {
        this.desciption = desciption;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }
}
//2.继承抽象类
public  class Coffee extends Drink{
}
//3.创建子类
public class Decaf extends Coffee {
    public Decaf(){
        setDesciption("Decaf");
        setPrice(9.0f);
    }
}
public class ShortBlack extends Coffee {
    ShortBlack(){
        setDesciption("ShortBlack");
        setPrice(10.0f);
    }
}
//4.创建装饰者类 继承和组合 被装饰者类  !!!
public  class Decorator extends Drink {
    Drink obj;
    Decorator(Drink obj){
        this.obj=obj;
    }


}
//5.创建装饰者的子类
public class Chocolate extends Decorator{
    public Chocolate(Drink obj) {
        super(obj);
        setDesciption(obj.getDesciption()+"巧克力");
        setPrice(obj.getPrice()+3.0f);
    }
}
public class Milk extends Decorator{
    Milk(Drink obj) {
        super(obj);
        setDesciption(obj.getDesciption()+"牛奶");
        setPrice(obj.getPrice()+2.0f);
    }
}

//测试类

public class Client {
    public static void main(String[] args) {
        Drink decaf = new Decaf();
        Drink chocolate = new Chocolate(decaf);
        Drink chocolate1 = new Chocolate(chocolate);
        float cost = chocolate1.getPrice();
        System.out.println(cost); //会得到全部加入购物车饮料的总钱数
        System.out.println(chocolate1.getDesciption());


    }
}

6.装饰者在JDK IO流的应用 InputStream(被装饰者)的FilterInputStream相当于(装饰者),下面的DataInputStream也继承
30装饰者模式jdkio源码原理图
请添加图片描述

//核心代码装饰者类继承和组合父类
public
class FilterInputStream extends InputStream { //继承父类 和 DataInputStream同级
    /**
     * The input stream to be filtered.
     */
    protected volatile InputStream in; //装饰父类 构造方法也是传入这个
//测试代码,子类的子类可以把父类组合到类内,这样的形式可能是装饰者模式
      DataInputStream dis = new DataInputStream(new FileInputStream("d:\\1.txt")); 
        DataInputStream dis1 = new DataInputStream(dis);
        //之前我就好奇为什么要把自己作为参数传给自己,原来是使用了装饰者
        System.out.println(dis1.read());
        dis.close();

7.组合模式(部分整体模式) 解决继承难以管理,树型结构组合对象,需要对象间有共同的功能
图组合32 33
在这里插入图片描述
请添加图片描述

在这里插入图片描述

1.几个概念
所有 整体和部分类继承 component(可以是接口/抽象类)然后实现他的 add() remove() print()方法空实现,方便管理,leaf是实现基础的get set方法

//传统的学校院系问题 学校 继承 学院 继承 院系 方便管理
----所有代码-----
//先写一个抽象类或接口,定义好整颗树,通用的方法

public abstract class Component {
    private String name; // 名字
    private String des; // 说明
    Component(String name,String des){

        this.name = name;
        this.des = des;
    }

    void add(Component component){
        throw new UnsupportedOperationException();
    };
    void remove(Component component){
        throw new UnsupportedOperationException();
    }
    void print(){
        throw new UnsupportedOperationException();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDes() {
        return des;
    }

    public void setDes(String des) {
        this.des = des;
    }
}

//每一层的树都继承 组件,使用list存放他的孩子

public class University extends Component{

    List<Component> components=new ArrayList<Component>();
    University(String name, String des) {
        super(name, des);
    }
    void add(Component component){
        components.add(component);
    };
    void remove(Component component){
        components.remove(component);
    }
    void print(){

        System.out.println("--------------" + getName() + "--------------");
        for (Component component : components) {
            component.print();
        }
    }
}
public class College extends Component {

    List<Component> components=new ArrayList<Component>();
    College(String name, String res) {
        super(name, res);
    }
    void add(Component component){
        components.add(component);
    };
    void remove(Component component){
        components.remove(component);
    }
    void print(){
        System.out.println("--------------" + getName() +"--------------");
        for (Component component : components) {
            component.print();
        }
    }
}

//最后一层叶子不放东西,所以不用list存放数据

public class Department extends Component {
    Department(String name,String res) {
        super(name, res);
    }

    void print(){
        System.out.println(getName()+getDes() );
    }
    public String getName() {
        return super.getName();
    }

    public String getDes() {
        return super.getDes();
    }


}

//这才是设计模式的精髓,直接让代码富有逻辑性,可读性增强,写新代码也容易

public class Client {
    public static void main(String[] args) {
        University university = new University("清华大学","中国一流大学");
        College college = new College("计算机学院", "计算机学院很好");
        college.add(new Department("计算机科学与技术", "王牌专业"));
        college.add(new Department("软件工程", "也是王牌专业"));
        university.add(college);

        College college1 = new College("财经学院", "财经很好");
        college1.add(new Department("会计专业","都是金融人才"));
        college1.add(new Department("金融工程专业","都是金融人才1"));
        university.add(college1);
        university.print();

    }
}
//输出结果(非常简单)
--------------清华大学--------------
--------------计算机学院--------------
计算机科学与技术王牌专业
软件工程也是王牌专业
--------------财经学院--------------
会计专业都是金融人才
金融工程专业都是金融人才1

//删除一个专业,可以自己定义删除的代码细节

public class Client {
    public static void main(String[] args) {
        University university = new University("清华大学","中国一流大学");
        College college = new College("计算机学院", "计算机学院很好");
        Department department = new Department("计算机科学与技术", "王牌专业");
        college.add(department);
        college.add(new Department("软件工程", "也是王牌专业"));
        college.remove(department);
        university.add(college);

        College college1 = new College("财经学院", "财经很好");
        college1.add(new Department("会计专业","都是金融人才"));
        college1.add(new Department("金融工程专业","都是金融人才1"));
        university.add(college1);
        university.print();

    }
}

8.组合模式在HashMap的应用
Map是component HashMap是composite 有put putall方法
Node是hashMap的静态内部类(叶子节点的),实现Map 相当于 Leaf没有put putall方法
全部都实现了Map所以map是component
请添加图片描述
9.外观(界面)(过程facade)模式,就是封装类的思想,加一层类 来屏蔽子系统的调用 和简单工厂越看越像不同的是工厂是创建类的,而外观是调用不同功能的

外观类: 知道哪些子系统负责什么,给调用端的请求到子系统
子系统: 处理外观类给的任务,功能的实际提供者

  1. 传统方式实现影院系统 直接Client调用各个子系统 如图: 35外观模式解决传统问题
  2. 外观模式实现 创建影院设备类, (通过构造方法饿汉式初始化,分成多个阶段的方法调用的类) client调用外观类 如图 36外观模式

请添加图片描述
请添加图片描述

//客户端调用

public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.ready();
        System.out.println("----------");
        facade.stop();
    }
}
//外观类 核心类
public class Facade {
    private  DVD dvd;
    private  Projector projector;
    private  Screen screen;
    private  Stere stere;
    private Lighting lighting;
    Facade(){
        dvd=DVD.getInstance();
        projector=Projector.getInstance();
        screen=Screen.getInstance();
        stere=Stere.getInstance();
        lighting=Lighting.getInstance();
    }

    public void ready(){
        screen.open();
        lighting.stop();
        projector.open();
        stere.open();
        dvd.play();
    }

    public void stop(){
        dvd.stop();
        stere.stop();
        projector.close();
        lighting.open();
        screen.close();

    }



}



//下面是子系统类
public class DVD {
    private static DVD instance=new DVD();

    public static DVD getInstance() {
        return instance;
    }
    public  void play(){
        System.out.println("开启播放dvd");
    }
    public  void stop(){
        System.out.println("关闭dvd");
    }
}
public class Lighting {
    private static Lighting instance=new Lighting();

    public static Lighting getInstance() {
        return instance;
    }
    public  void open(){
        System.out.println("开灯");
    }
    public  void stop(){
        System.out.println("关灯");
    }
}
public class Projector {
    private static Projector instance=new Projector();

    public static Projector getInstance() {
        return instance;
    }
    public  void open(){
        System.out.println("开启投影仪");
    }
    public  void close(){
        System.out.println("关闭投影仪");
    }
    
    
}
public class Screen {
    private static Screen instance=new Screen();

    public static Screen getInstance() {
        return instance;
    }
    public  void open(){
        System.out.println("打开幕布");
    }
    public  void close(){
        System.out.println("关闭幕布");
    }


}
public class Stere {
    private static Stere instance=new Stere();

    public static Stere getInstance() {
        return instance;
    }
    public  void open(){
        System.out.println("开启立体声");
    }
    public  void stop(){
        System.out.println("关闭立体声");
    }
}

10.外观模式在mybatis的应用
图 37.外观模式mybastis源码分析Configuration(外观类)的newMetaObject()方法
Configuration是外观类,子系统是DefaultObjectFactory DefaultObjectWrapperFactory DefaultReflectorFactory

请添加图片描述

import org.apache.ibatis.session.Configuration;
  public MetaObject newMetaObject(Object object) {
    return MetaObject.forObject(object, objectFactory, objectWrapperFactory);
  }
  public static MetaObject forObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {
    if (object == null) {
      return SystemMetaObject.NULL_META_OBJECT;
    } else {
      return new MetaObject(object, objectFactory, objectWrapperFactory);
    }
  }

//到MetaObject类

  private MetaObject(Object object, ObjectFactory objectFactory, ObjectWrapperFactory objectWrapperFactory) {
    this.originalObject = object;
    this.objectFactory = objectFactory;
    this.objectWrapperFactory = objectWrapperFactory;

    if (object instanceof ObjectWrapper) {
      this.objectWrapper = (ObjectWrapper) object;
    } else if (objectWrapperFactory.hasWrapperFor(object)) {
      this.objectWrapper = objectWrapperFactory.getWrapperFor(this, object);
    } else if (object instanceof Map) {
      this.objectWrapper = new MapWrapper(this, (Map) object);
    } else if (object instanceof Collection) {
      this.objectWrapper = new CollectionWrapper(this, (Collection) object);
    } else {
      this.objectWrapper = new BeanWrapper(this, object);
    }
  }

11.外观模式的注意事项

  1. 降低客户端访问子系统复杂性(解耦)
  2. 用于系统太过复杂需要分层的时候
  3. 子系统太少了,不如直接使用,不用外观模式
  4. 维护遗留大项目 可以使用外观模式

12.享元(蝇量 flyweight)(共享对象)模式(开发用得多 string和池技术) 需求相似度高不要copy

  1. 解决的问题 38享元模式原理图
    1. 避免重复对象内存浪费的问题,但是提供系统复杂度 s1=“aaa” 和new String(“aaa”);指向常量池的同一个位置
    2. 解决网站外包复用问题,传统方案是复制粘贴定制修改
  2. 4个角色
    1. FlyWeight 抽象的享元角色,定义了对象的内部和外部状态的接口/实现
    2. ConcreteFlyWeight 具体的享元角色,返回共享对象
    3. UnSharedConcreteFlyWeight 不可共享的享元角色,一般不会出现在享元工厂里
    4. FlyWeightFactory 享元工厂类,得到对象的方法 用集合HashMap/HashTable存放共享的对象,
    3.内部和外部状态 (内部放在集合,外部构造器传进来)
    内部: 不随环境改变的状态(对象内) 5子棋 棋的颜色
    外部: 随环境改变的 5子棋 位置
    请添加图片描述

----解决外包问题完整代码------

//抽象类
public abstract class WebSite {

    abstract void  use(User user);
}
//创建类
public class ConcreteWebSite extends WebSite {
    String type=""; //内部状态
    ConcreteWebSite(String type) {
        this.type=type;
    }

    @Override
    void use(User user) { //外部状态
        System.out.println("网站类型为"+type+"正在被"+user.getName()+"使用");
    }
}
//外部状态类
public class User {
    private String name;
    User(String name){
        this.name=name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

//享元工厂类!!!,共享数据类
public class WebSiteFactory {
    HashMap<String, ConcreteWebSite> pool=new HashMap<>();
    public WebSite getWebSiteCategory(String type){
        if(!pool.containsKey(type)){
            pool.put(type,new ConcreteWebSite(type));
        }
        return (WebSite)pool.get(type);

    }
    int getCount(){
        return pool.size();
    }
}

//客户端调用测试发现有缓存的效果
//其实强智系统也可能使用了享元模式,一个强智系统由多个大学使用

public class Client {
    public static void main(String[] args) {
        WebSiteFactory webSiteFactory = new WebSiteFactory();
        WebSite blog = webSiteFactory.getWebSiteCategory("博客"); //设置内部状态为博客(由我决定) 
        blog.use(new User("小明"));  //外部状态为小明(由客户决定)
        WebSite blog1 = webSiteFactory.getWebSiteCategory("博客");
        blog1.use(new User("小叶"));
        WebSite webSite = webSiteFactory.getWebSiteCategory("房地产");
        webSite.use(new User("小李子"));
        System.out.println(webSiteFactory.getCount());
    }
}

//输出
网站类型为博客正在被小明使用
网站类型为博客正在被小叶使用
网站类型为房地产正在被小李子使用
2 //创建了2个网站,博客和房地产,重复创建的会直接返回

13.jdk里面Integer使用了享元模式

   x=Integer.valueOf(127);//  x==y  -128到127使用享元模式,返回相同的对象,比new要快
   y=Integer.valueOf(127);
public static Integer valueOf(int i) { //外部状态
    if (i >= IntegerCache.low && i <= IntegerCache.high)  //-128 到127  内部状态
        return IntegerCache.cache[i + (-IntegerCache.low)];   //数组也是个集合 static final Integer cache[];  
    return new Integer(i);
}

14.代理(proxy)模式(替你做事,增强你的能力) 给对象(类)创建替身增强功能

  1. 解决的问题
    1.动态增加对象的功能
    2. 缺点 代理对象和被代理对象需要实现相同的接口,导致创建大量的代理对象,不好维护
  2. 代理的对象可以是远程对象,创建开销大的对象,需要安全控制的对象
  3. 代理的分类
    1.静态代理 需要类实现接口和聚合,有个代理类和被代理类
    请添加图片描述
public interface Play {
    void play();
}
//被代理类
public class PlayImpl implements Play{

    @Override
    public void play() {
        System.out.println("被代理类的方法");
    }
}
//代理类
public class PlayPoxy implements Play{
    Play play;
    public PlayPoxy(Play play){
        this.play=play;
    }

    @Override
    public void play() {
        System.out.println("代理前");
        play.play();
        System.out.println("代理后");

    }
}
public class Client {
    public static void main(String[] args) {
        PlayPoxy playPoxy = new PlayPoxy(new PlayImpl());
        playPoxy.play();
    }
}

2.动态代理(JDK代理) 使用jdk的方法, 传入一个接口 写个工厂

Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler(){ invoke方法的 returnVal=method.invoke(target,args); return returnVal;//可以没有,观察一下args})输出对象hashcode带有 $proxy说明是代理对象

public interface Play {
    void play();
}
public class PlayImpl implements Play {

    @Override
    public void play() {
        System.out.println("被代理类的方法");
    }
}
public class PlayPoxy {
    Object target;

    public PlayPoxy(Object target) {
        this.target=target;
    }

    public Object getProxyInstance(){

         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {    //代理全部方法调用可用method的方法判断调用哪个方法
                System.out.println("jdk动态代理前");
                Object invoke = method.invoke(target, args);
                System.out.println("jdk动态代理后");
                return invoke;
            }
        });
    }

}
public class Client {
    public static void main(String[] args) {
        Play target = new PlayImpl();
        PlayPoxy playPoxy = new PlayPoxy(target);
        Play proxyInstance = (Play)playPoxy.getProxyInstance();
        proxyInstance.play();
    }
}             

3.Cglib动态代理 在内存创建单个对象,不需要实现接口和聚合 spring AOP的底层
//导入cglib的jar文件 ,代理类实现 MethodIntercepttor类的方法 intercept和jdk代理写法一样
请添加图片描述

  1. 不能为final/static会报错,不会拦截和执行业务方法
public class PlayImpl  {


    public int play() {
        System.out.printl![请添加图片描述](https://img-blog.csdnimg.cn/a085daacf6a04548b588d5456fcdbe2a.png)
n("被代理类的方法"); return 1;
    }
}
public class PlayPoxy implements MethodInterceptor {
    private Object target;
    PlayPoxy(Object target){
        this.target = target;
    }
    //设置返回的代理对象方法
    public Object getProxyInstance() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();

    }
    //具体处理增强功能的方法
    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("Cglib代理模式 ~~ 开始");
        Object returnVal = method.invoke(target, args);
        System.out.println("Cglib代理模式 ~~ 提交");
        return returnVal;  //依赖函数的返回值也可以修改
    }
}
public class Client {
    public static void main(String[] args) {

        PlayPoxy playPoxy = new PlayPoxy(new PlayImpl());
        PlayImpl proxyInstance = (PlayImpl) playPoxy.getProxyInstance();
        proxyInstance.play();
    }
}

4.其他代理
防火墙代理:(内网穿透服务器对公网的访问)
缓存代理: 请求文件先到缓存取,如果没有就到数据库或公网取
远程代理: 本地的对象代理远程的对象像本地访问一样访问资源
同步代理: 代理需要多线程同步的对象(加上同步代码块)

1

5.模板(template method)模式

  1. 是什么?
    1.是行为型模式
    2.几个类的几个方法是一样的,部分不一样,有一个final方法写调用处理流程
    3.缺点是每个不同实现需要子类实现,类爆炸
  //抽象类写一个final方法以免被子类覆盖
   //改进加入构子方法直接返回状态,如果模板方法判断是否加另外的东西,不用改模板,可以让子类覆盖达到灵活控制的效果
  //覆盖,增加灵活性(实现其他功能)
public abstract class SoyMilk {
    
    final void  make(){
        select();
        if(customWantAdditions()==true){
            add();
        }
        soap();
        beat();
     };
    void  select(){
        System.out.println("挑选大豆");
    };
    abstract void  add();
    void  soap(){
        System.out.println("吸水");
    };
    void  beat(){
        System.out.println("打碎");
    };

    //构子增加拓展性
    boolean customWantAdditions(){
       return true;
    }
}

//写他的子类
public class RedSoyMilk extends SoyMilk {
    @Override
    void add() {
        System.out.println("添加红豆");
    }
}
public class GreenSoyBean extends SoyMilk {
    @Override
    void add() {
        System.out.println("加绿豆");
    }
}
public class PureSoyMilk extends SoyMilk {
    @Override
    void add() {
    }
    @Override
     boolean customWantAdditions(){
        return false;
    }
}
//测试
public class Client {
    public static void main(String[] args) {
        SoyMilk redSoyMilk = new RedSoyMilk();
        redSoyMilk.make();
        System.out.println("--------------");
        SoyMilk greenSoyBean = new GreenSoyBean();
        greenSoyBean.make();
        System.out.println("制作纯豆奶");

        SoyMilk pureSoyMilk = new PureSoyMilk();
        pureSoyMilk.make();
    }
}

//运行结果

挑选大豆
添加红豆
吸水
打碎
--------------
挑选大豆
加绿豆
吸水
打碎
制作纯豆奶
挑选大豆
吸水
打碎

16.模板方法在spring是应用
//抽象类定义模板方法的实现过程
//上面的类又有继承 ,到ClassPathXmlApplicationContext我们就可以直接使用了因为一层一层方法继承下来,所有功能完成了实现
请添加图片描述

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
    String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
    String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
    String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
    String ENVIRONMENT_BEAN_NAME = "environment";
    String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
    String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";

    void setId(String var1);

    void setParent(ApplicationContext var1);

    ConfigurableEnvironment getEnvironment();

    void setEnvironment(ConfigurableEnvironment var1);

    void addBeanFactoryPostProcessor(BeanFactoryPostProcessor var1);

    void addApplicationListener(ApplicationListener<?> var1);

    void refresh() throws BeansException, IllegalStateException;

    void registerShutdownHook();

    void close();

    boolean isActive();

    ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

//AbstractApplicationContext的refresh相当于make

 public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean //继承和实现确定处理过程
    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);
	//处理的过程 只是这里依赖外部依赖(组合进来)
            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var5) {
                this.destroyBeans();
                this.cancelRefresh(var5);
                throw var5;
            }

        }
    }
  //空实现
  //onfreash是构子
  protected void onRefresh() throws BeansException {
    }
  //GenericApplicationContext类覆盖了父类的方法(子类覆盖父类具体实现方法,但没有全部实现的流程)

    protected final void refreshBeanFactory() throws IllegalStateException {
        if (this.refreshed) {
            throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
        } else {
            this.beanFactory.setSerializationId(this.getId());
            this.refreshed = true;
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/709524.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(六)Spring源码解析:Spring AOP源码解析

〇、AOP概念 Aspect&#xff1a;切面 给业务方法增加到功能&#xff0c;切面泛指交叉业务逻辑。上例中的事务处理、日志处理就可以理解为切面。常用的切面是通知&#xff08;Advice&#xff09;。实际就是对主业务逻辑的一种增强。 Pointcut&#xff1a;切入点 切入点指声明的…

Nerf-Wild神经辐射场论文学习笔记 Neural Radiance Fields for Unconstrained Photo Collections

前言&#xff1a; 本文为记录自己在Nerf学习道路的一些笔记&#xff0c;包括对论文以及其代码的思考内容。公众号&#xff1a; AI知识物语 B站讲解&#xff1a;出门吃三碗饭 本篇文章主要针对其数学公式来学习其内容&#xff0c;欢迎批评指正&#xff01;&#xff01;&#x…

10-C++学习笔记-字符串

&#x1f4da; 前言 字符串是在编程中广泛使用的数据类型&#xff0c;用于表示一系列字符。在C中&#xff0c;我们可以使用C风格字符串和string类来处理字符串操作。本篇学习笔记将详细介绍字符串的相关知识。 &#x1f4d6; 1 C风格字符串 ✨ C风格字符串初始化 C风格字符…

什么是EMC存储 Clarrion存储的cache dirty或者cache lost(CACD)?

CACD是Cant assign, Cache Dirty的缩写&#xff0c;DELL EMC的专业术语。 在开始之前&#xff0c;先介绍下cache dirty的概念&#xff0c;朴素的语言就是有了脏数据&#xff0c;脏数据当然就是不能使用的数据了。为什么数据会脏呢&#xff1f;先从存储的基本概念聊起来。 为了加…

PoseiSwap 将向 Zepoch 节点持有者发放新一轮空投,生态启动在即

目前&#xff0c;随着各类 Layer2 空投不断内卷&#xff0c;越来越多的用户疲于参与其中&#xff08;参与交互也很有可能难以获得空投资格&#xff09;。Nautilus Chain 作为目前模块化 Layer3 架构链&#xff0c;在初期就明确了空投计划&#xff0c;即所有上线的应用都将会拿出…

各类农作物分布遥感监测数据大全

最近收集整理了大量的农作物分布的遥感监测数据&#xff0c;废话不多说&#xff0c;分享给大家&#xff0c;后面会持续更新&#xff01;&#xff01; 数据查看地址&#xff1a; https://www.dilitanxianjia.com/%e9%81%a5%e6%84%9f%e8%a7%a3%e8%af%91%e5%90%8e%e6%88%90%e6%9…

LeetCode 0002. 两数相加

【LetMeFly】2.两数相加 力扣题目链接&#xff1a;https://leetcode.cn/problems/add-two-numbers/ 给你两个 非空 的链表&#xff0c;表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的&#xff0c;并且每个节点只能存储 一位 数字。 请你将两个数相加&#xff…

2016年全国硕士研究生入学统一考试管理类专业学位联考逻辑试题——纯享题目版

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;考取过HCIE Cloud Computing、CCIE Security、CISP、RHCE、CCNP RS、PEST 3等证书。&#x1f433; &#x1f495;兴趣爱好&#xff1a;b站天天刷&…

华为OD机试真题 Java 实现【开心消消乐】【2023 B卷 100分】

目录 一、题目描述二、输入描述三、输出描述四、Java算法源码五、效果展示1、输入2、输出3、说明 一、题目描述 给定一个N行M列的二维矩阵&#xff0c;矩阵中每个位置的数字取值为0或1。矩阵示例如&#xff1a; 1 1 0 0 0 0 0 1 0 0 1 1 1 1 1 1 现需要将矩阵中所有的1进行反…

maven高级开发

分模块设计 例如 如果需要用到其他的模块&#xff0c;直接导入模块坐标就可以了 分模块开发&#xff0c;需建立的模块&#xff0c;选择maven模型 分模块设计需要先针对模块功能进行设计&#xff0c;再进行编码。 继承与聚合 继承&#xff1a;描述的是两个工程间的关系&…

UE4/5通过插件,用GeneratedDynamicMeshActor编辑静态网格到content中

目录 制作 直接复制下面代码到蓝图中粘贴即可&#xff1a; 效果1【用了第一个函数】&#xff1a; 效果2【用了第二个函数】&#xff1a; 制作 首先我们要打开插件&#xff1a; 然后继承GeneratedDynamicMeshActor进行创建&#xff1a; 我们制作一个函数&#xff0c;这个函数将…

Draw.io | 一款强大且支持在线编辑和导出的流程图绘制神器

目录 &#x1f48c; 写在前面 &#x1f5a5;️ 软件介绍 &#x1f5a5;️ 使用方式 1. Draw.io 的核心设计元素 1.1 绘图区 1.2 快速开始 2. Draw.io 的基本操作 2.1 移动、多选、复制与删除 2.2 创建链接 2.3 图形替换与旋转 3. 使用 Draw.io 绘制简单流程图 3.1 基本…

ChatGPT Plugins内幕、源码及案例实战(三)

ChatGPT Plugins内幕、源码及案例实战(三) ChatGPT Plugins内幕、源码及案例实战 6.4 ChatGPT Retrieval Plugin全流程内幕解析 以ChatGPT检索插件为例,我们讲解一下它整个的流程,让大家有一个比较明确、清晰的统一认知:  数据存储:设立的前提是你有文档,会有一些文…

大学教材征订管理系统数据库设计

摘 要 随着计算机及Internet迅速的发展&#xff0c;越来越多的行业实现了管理的信息化和自动化&#xff0c;教育行业也不例外。但在很多高校中,教材征订作为学校教学工作中很重要的一个环节还没完全实现信息化管理。因此本系统针对高校教材征订管理过程中人工管理存在的困难&a…

(02)Cartographer源码无死角解析-(67) 2D后端优化→FastCorrelativeScanMatcher2D -分支定界算法(BranchAndBound)1

讲解关于slam一系列文章汇总链接:史上最全slam从零开始&#xff0c;针对于本栏目讲解(02)Cartographer源码无死角解析-链接如下: (02)Cartographer源码无死角解析- (00)目录_最新无死角讲解&#xff1a;https://blog.csdn.net/weixin_43013761/article/details/127350885 文…

Java——包(package)

一、Java中的包(package) 在Java中&#xff0c;包&#xff08;package&#xff09;是一种用于组织类和接口的命名空间的机制。它用于将相关的类和接口组织在一起&#xff0c;以便更好地管理和维护代码。 其实就是一个个文件夹 二、包(package)的作用 防止类和接口命名冲突&…

时间序列分解 | Matlab变分模态分解(VMD)的信号分解

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 时间序列分解 | Matlab变分模态分解(VMD)的信号分解 部分源码 %--------------------

尚硅谷Docker2022版学习笔记(基础篇 下)

目录 五、本地镜像发布到阿里云 5.1、本地镜像发布到阿里云流程 5.2、镜像的生成方法 基于当前容器创建一个新的镜像&#xff08;第一种方法&#xff09; DockerFile&#xff08;第二种方法&#xff09; 5.3、将本地镜像推送到阿里云 本地镜像素材原型 创建仓库镜像 选…

hive row_number()对单列进行去重

学到一个高级用法 row_number() select * ,row_number() over (partition by c_id order by s_score) from score; https://www.jb51.net/article/254952.htm