110.【十万字带你深入学习23种设计模式】(十三)

简介: 110.【十万字带你深入学习23种设计模式】
(6).模式扩展

建造者模式除了上面的用途外,在开发中还有一个常用的使用方式,就是当一个类构造器需要传入很多参数时,如果创建这个类的实列,代码可读性会非常差,而且很容易引入错误,此时就应该利用建造者模式进行重构。

package com.jsxs.pattern.build.demo2;
/**
 * @Author Jsxs
 * @Date 2023/4/18 17:18
 * @PackageName:com.jsxs.pattern.build.demo2
 * @ClassName: Phone
 * @Description: TODO
 * @Version 1.0
 */
public class Phone {
    private String cpu;
    private String Screen;
    private String money;
    private String mainBoard;
    // 私有构造方法
    private Phone(Builder builder) {
        this.cpu = builder.cpu;
        this.Screen = builder.Screen;
        this.money = builder.money;
        this.mainBoard = builder.mainBoard;
    }
    //  静态内部类
    public static final class Builder{
        private String cpu;
        private String Screen;
        private String money;
        private String mainBoard;
        public Builder cpu(String cpu) {
            this.cpu = cpu;
            return this;
        }
        public Builder screen(String screen) {
            this.Screen = screen;
            return this;
        }
        public Builder money(String money) {
            this.money = money;
            return this;
        }
        public Builder mainBoard(String mainBoard) {
            this.mainBoard = mainBoard;
            return this;
        }
        public Phone build(){
            return new Phone(this);   // 传递这个内部类
        }
        @Override
        public String toString() {
            return "Builder{" +
                    "cpu='" + cpu + '\'' +
                    ", Screen='" + Screen + '\'' +
                    ", money='" + money + '\'' +
                    ", mainBoard='" + mainBoard + '\'' +
                    '}';
        }
    }
    @Override
    public String toString() {
        return "Phone{" +
                "cpu='" + cpu + '\'' +
                ", Screen='" + Screen + '\'' +
                ", money='" + money + '\'' +
                ", mainBoard='" + mainBoard + '\'' +
                '}';
    }
}
package com.jsxs.pattern.build.demo2;
/**
 * @Author Jsxs
 * @Date 2023/4/18 17:26
 * @PackageName:com.jsxs.pattern.build.demo2
 * @ClassName: Client
 * @Description: TODO
 * @Version 1.0
 */
public class Client {
    public static void main(String[] args) {
        // 利用建造者创建对象 ----  因为这些方法的返回值对象都是当前对象,所以可以使用链式编程
        Phone.Builder builder = new Phone.Builder()
                .cpu("inter")
                .screen("三星")
                .mainBoard("苹果")
                .money("1200");
        Phone phone = builder.build();
        System.out.println(phone);
    }
}

重构后的代码在使用起来更方便,某种程度上可以提高开发效率。从软件设计,对程序员的要求比较高。

7.创建者模式对比

(1).工厂方法模式VS建造者模式

工厂方法模式注重的是整体对象的创建方式(结果);而建造者模式注重的是部件构建的过程(过程),意在通过一步步地精确构造出一个复杂地对象。

我们举个简单的列子来说明两者地差异: 如要制造一个超人,如果使用工厂方法模式,直接生产出来地就是一个力大无穷、能够飞翔、内裤外穿地超人;而如果使用建造者模式,则需要组装收、头、脚、驱赶,然后再把内裤外穿,于是一个超人就诞生了。

(2).抽象工厂模式VS建造者模式

抽象工厂模式实现对产品家族地创建,一个产品家族是这样地一系列产品;具有不同分类欸都地产品组合,采用抽象工厂模式是不需要关心构建过程,只关心什么产品由什么工厂生产即可。

建造者模式则是要求按照指定地蓝图建造产品,他的主要目的是通过组件装零配件而生产地一个新产品

如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族地产品.那么建造者模式就是一个汽车组装工厂,通过对部件地组装可以返回一量完整的汽车。

(三)、结构性模式(7种)

结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构性模式对象结构型模式,前者采用继承机制来组织接口和类,后者采用组合或聚合来组合对象。

由于组合关系或聚合关系比继承关系的耦合度低,满足合成复用原则,所以对象结构型模式类结构型模式具有更大的灵活性。

1.代理模式

(1).概述

由于某些原因需要给某个对象(结婚对象)提供一个代理(婚介)以控制对该对象的访问(结婚仪式)。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介

eg: 结婚: 找婚介。

Java中的代理按照代理类生成时机不同分为静态代理动态代理。静态代理类在编译期就生成,而动态代理类则是在Java运行时动态生成。动态代理又有JDK和GCLib代理两种。

(2).结构

代理模式分为三种角色:

  • 抽象主题类: 通过接口或抽象类声明真实主题和代理对象实现的业务方法(结婚)。
  • 真实主题类:实现了抽象主题的具体业务,是代理对象所代表的真实对象,是最终要引入的对象(新人)。
  • 代理类: 提供了与真实主题相同的接口,其内部含有对真实主题的引用,他可以访问、控制或扩展真实主题的功能(婚介所)。
(3).静态代理

我们通过案列来感觉一下静态代理。

eg: 火车站买票

如果要买火车票的话,我们需要去火车站买票,排队等一系列的操作,显然比较麻烦。而火车站多个地方都有代售点,我们去代售点买火车票就方便很多了。这个列子其实就是典型的代理模式,火车站是目标对象代售点是代理对象

抽象主题类

package com.jsxs.structure.proxy.static_proxy;
/**
 * @Author Jsxs
 * @Date 2023/4/19 13:40
 * @PackageName:com.jsxs.structure.proxy.static_proxy
 * @ClassName: SellTickets
 * @Description: TODO   卖火车票的接口
 * @Version 1.0
 */
public interface SellTickets {
    void sell();
}

真实主题类

package com.jsxs.structure.proxy.static_proxy;
/**
 * @Author Jsxs
 * @Date 2023/4/19 13:41
 * @PackageName:com.jsxs.structure.proxy.static_proxy
 * @ClassName: TrainStation
 * @Description: TODO   火车站类
 * @Version 1.0
 */
public class TrainStation implements SellTickets{
    @Override
    public void sell() {
        System.out.println("在火车站进行卖票业务");
    }
}

代理类

package com.jsxs.structure.proxy.static_proxy;
/**
 * @Author Jsxs
 * @Date 2023/4/19 13:42
 * @PackageName:com.jsxs.structure.proxy.static_proxy
 * @ClassName: ProxyPoint
 * @Description: TODO  代售点
 * @Version 1.0
 */
public class ProxyPoint implements SellTickets{
    private TrainStation trainStation=new TrainStation();
    @Override
    public void sell() {
        System.out.println("代售点收取服务费帮火车站卖票,票的来源是火车站");
        trainStation.sell();
    }
}

从上面的代码中我们可以看出测试类直接访问的是ProxyPoint类对象,也就是说ProxyPoint作为访问对象和目标对象的中介。同时也对sell方法进行了增强(代理点收取一些服务费用)

(4).JDK动态代理

我们使用上面的案例进行动态代理,先说说JDK提供的动态代理。Java中提供了一个动态代理类Proxy,Proxy并不是我们上述所说的代理对象的类,而是提供了一个创建代理对象的静态方法来获取对象

抽象主题类

package com.jsxs.structure.proxy.jdk_proxy;
/**
 * @Author Jsxs
 * @Date 2023/4/19 13:40
 * @PackageName:com.jsxs.structure.proxy.static_proxy
 * @ClassName: SellTickets
 * @Description: TODO   卖火车票的接口
 * @Version 1.0
 */
public interface SellTickets {
    void sell();
}

真实主题类

package com.jsxs.structure.proxy.jdk_proxy;
/**
 * @Author Jsxs
 * @Date 2023/4/19 13:41
 * @PackageName:com.jsxs.structure.proxy.static_proxy
 * @ClassName: TrainStation
 * @Description: TODO   火车站类
 * @Version 1.0
 */
public class TrainStation implements SellTickets {
    @Override
    public void sell() {
        System.out.println("在火车站进行卖票业务");
    }
}

JDK动态代理类

package com.jsxs.structure.proxy.jdk_proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * @Author Jsxs
 * @Date 2023/4/19 14:04
 * @PackageName:com.jsxs.structure.proxy.jdk_proxy
 * @ClassName: ProxyFactory
 * @Description: TODO   获取代理对象的工厂类
 * @Version 1.0
 */
public class ProxyFactory {
    // 1.声明目标对象
    private TrainStation trainStation=new TrainStation();
    // 2.获取代理对象的方法
    public SellTickets getProxyObject(){
        // 返回代理对象即可
        /**
         *  1.类加载器: 用于加载代理类。可以通过目标对象获取类加载器
         *  2.代理类实现的接口的字节码对象
         *  3. 代理对象的调用处理程序:
         */
        SellTickets proxyObject = (SellTickets)Proxy.newProxyInstance(trainStation.getClass().getClassLoader(), trainStation.getClass().getInterfaces(), new InvocationHandler() {
            /**
             *
             * @param proxy 代理对象: 和proxyObject对象是同一个对象,在invoke方法中基本不用
             * @param method 对接口中的方法进行封装的method对象
             * @param args 调用方法的参数
             * @return 方法的返回值
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("代售点收取一定的服务费用(JDK动态代理)...");
                Object invoke = method.invoke(trainStation, args);
                return invoke;
            }
        });
        return proxyObject;
    }
}

客户端

package com.jsxs.structure.proxy.jdk_proxy;
/**
 * @Author Jsxs
 * @Date 2023/4/19 14:18
 * @PackageName:com.jsxs.structure.proxy.jdk_proxy
 * @ClassName: Client
 * @Description: TODO
 * @Version 1.0
 */
public class Client {
    public static void main(String[] args) {
        // 1.创建代理类工厂
        ProxyFactory proxyFactory = new ProxyFactory();
        // 2.获取代理对象
        SellTickets proxyObject = proxyFactory.getProxyObject();
        // 3.调用售卖的方法
        proxyObject.sell();
    }
}

使用动态代理,我们思考下面问题

  • Proxy是代理类嘛?
  • ProxyFactory不是代理模式中所说的代理类,而代理类是程序在运行过程中动态的在内存中生成的类。通过阿里巴巴开源的Java诊断工具(Arthas)查看代理类的结构。

相关文章
|
3月前
|
设计模式 监控 安全
多线程设计模式【多线程上下文设计模式、Guarded Suspension 设计模式、 Latch 设计模式】(二)-全面详解(学习总结---从入门到深化)
多线程设计模式【多线程上下文设计模式、Guarded Suspension 设计模式、 Latch 设计模式】(二)-全面详解(学习总结---从入门到深化)
84 0
|
2月前
|
设计模式 存储 算法
设计模式学习心得之五种创建者模式(2)
设计模式学习心得之五种创建者模式(2)
23 2
|
2月前
|
设计模式 uml
设计模式学习心得之前置知识 UML图看法与六大原则(下)
设计模式学习心得之前置知识 UML图看法与六大原则(下)
18 2
|
2月前
|
设计模式 安全 Java
设计模式学习心得之五种创建者模式(1)
设计模式学习心得之五种创建者模式(1)
19 0
|
2月前
|
设计模式 数据可视化 程序员
设计模式学习心得之前置知识 UML图看法与六大原则(上)
设计模式学习心得之前置知识 UML图看法与六大原则(上)
18 0
|
3月前
|
设计模式 安全 Java
【JAVA学习之路 | 基础篇】单例设计模式
【JAVA学习之路 | 基础篇】单例设计模式
|
3月前
|
设计模式 安全 Java
【设计模式学习】单例模式和工厂模式
【设计模式学习】单例模式和工厂模式
|
3月前
|
设计模式 算法 程序员
Python从入门到精通:2.1.3深入学习面向对象编程——设计模式的学习与实践
Python从入门到精通:2.1.3深入学习面向对象编程——设计模式的学习与实践
|
3月前
|
设计模式 存储 前端开发
JS的几种设计模式,Web前端基础三剑客学习知识分享,前端零基础开发
JS的几种设计模式,Web前端基础三剑客学习知识分享,前端零基础开发
|
3月前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式