0
点赞
收藏
分享

微信扫一扫

组合模式、代理模式(静态代理、动态代理)原理及实例

组合模式

基本介绍

  1. 组合模式(Composite Pattern),又叫部分整体模式,它创建了对象组的树形结构,将对象组合成树状结构以表示“整体-部分”的层次关系。
  2. 组合模式依据树形结构来组合对象,用来表示部分以及整体层次。
  3. 这种类型的设计模式属于结构型模式。
  4. 组合模式使得用户对单个对象和组合对象的访问具有一致性,即:组合能让客
    户以一致的方式处理个别对象以及组合对象

解决的问题

  1. 组合模式解决这样的问题,当我们的要处理的对象可以生成一颗树形结构,而我们要对树上的节点和叶子进行操作时,它能够提供一致的方式,而不用考虑它是节点还是叶子
  2. 对应的示意图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DZ9Bm81V-1643880828541)(F:\StudyNotepad\img\image-20211122183230228.png)]

实例演示

分析

1)UML类图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hA6k3IPk-1643880828544)(F:\StudyNotepad\img\image-20211122183510729.png)]

2)创建父类

/*
* 定义一个基本的组件,不管它其中还包含了什么首先它都是电脑的组件
* */
public abstract class OriginalComponent {
    private String name;
    private String brand;

    public OriginalComponent(String name, String brand) {
        this.name = name;
        this.brand = brand;
    }

    /*
     * 我们先以最小组件的角度来看,它可以有哪些方法,其他如CPU这些
     * 也是一个类,但是当它们继承的这个父类的时候,这些方法的使用具体
     * 还要看它们的重写。在父类中默认我们的实现是抛出异常,也就是说
     * 如果继承的类不重写这个方法,那么就是没有使用这个方法的权限。
     * */
    protected void add(OriginalComponent originalComponent){
        throw new UnsupportedOperationException();
    }

    protected void remove(OriginalComponent originalComponent){
        throw new UnsupportedOperationException();
    }

    /*
    * 输出组件的信息是基本的功能,应该是每一个组件都有的,那么我们就将这个
    * 方法定义为抽象的,每一个继承父类的子类都要实现这个方法。
    * */
    protected  abstract void print();
}

3)根节点

/*
* 机箱内部也含有其他组件
* */
public class ComputerCase extends OriginalComponent{
    List<OriginalComponent> componentList = new ArrayList<>();

    public ComputerCase(String name, String brand) {
        super(name, brand);
    }

    @Override
    protected void add(OriginalComponent originalComponent) {
        componentList.add(originalComponent);
    }

    @Override
    protected void remove(OriginalComponent originalComponent) {
        componentList.remove(originalComponent);
    }

    @Override
    protected void print() {
        for (OriginalComponent originalComponent : componentList) {
            System.out.println("---机箱---");
            originalComponent.print();
        }
    }
}

4)叶子结点

public class CPU extends OriginalComponent{

    public CPU(String name, String brand) {
        super(name, brand);
    }

    @Override
    protected void print() {
        System.out.println("部件名称:"+this.getName()+"\t 部件品牌"+getBrand());
    }
}

5)组合

public class Client {
    public static void main(String[] args) {
        Computer computer = new Computer("电脑", "pox");
        ComputerCase computerCase = new ComputerCase("机箱", "pox");
        ComputerMotherboard computerMotherboard = new ComputerMotherboard("主板", "pox");
        ComputerKeyboard computerKeyboard = new ComputerKeyboard("键盘", "pox");
        Memory memory = new Memory("内存条", "pox");

        Application application = new Application("应用", "pox");
        Game game = new Game("绝地求生", "蓝洞");

        computer.add(computerCase);
        computer.add(computerKeyboard);
        computerCase.add(computerMotherboard);
        computerMotherboard.add(memory);
        computer.add(application);
        application.add(game);

        computer.print();
    }
}

6)测试

public class Game extends OriginalComponent{

    public Game(String name, String brand) {
        super(name, brand);
    }

    @Override
    protected void print() {
        System.out.println("游戏名称:"+this.getName()+"\t 游戏公司: "+getBrand());
        System.out.println("安装完毕~~");
        System.out.println("启动游戏....进入战场");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sz2S1lB8-1643880828546)(F:\StudyNotepad\img\image-20211122184432580.png)]

小结

补充

=====HashMap部分源码,关于put======
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

=====调用putVal方法存放=====
// 部分源码
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    // 存放到Node中
    Node<K,V>[] tab; Node<K,V> p; int n, i;
}

代理模式

基本介绍

  1. 代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
  2. 被代理的对象可以是远程对象、创建开销大的对象或需要安全控制的对象
  3. 代理模式有不同的形式, 主要有三种 静态代理、动态代理 (JDK代理、接口代理)和 Cglib代理 (可以在内存动态的创建对象,而不需要实现接口, 他是属于动态代理的范畴) 。

静态代理

实例演示

1)UML类图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4eiRKke1-1643880921389)(F:\StudyNotepad\img\image-20211122213327890.png)]

2)创建公共接口
public interface SellTickets {
    void sell();
    // 这里getname是为了后续分辨票的类型
    String getName();
}
3)创建实现类
public class AirTickets implements SellTickets{
    private String name = "Air";

    @Override
    public void sell() {
        System.out.println("售卖飞机票~~");
    }

    @Override
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
4)编写动态代理类
public class GoWhereProxy implements SellTickets{
    SellTickets sellTickets;
    private String name;

    public GoWhereProxy(SellTickets sellTickets) {
        name = "去哪儿";
        this.sellTickets = sellTickets;
    }

    /*
    * 这里可以根据传入的票的类型,做出相应的功能
    * */
    @Override
    public void sell() {
        if (sellTickets.getName().equals("Air")){
            System.out.println("飞机票收取5%手续费");
            sellTickets.sell();
            System.out.println("出票~~");
        } else if (sellTickets.getName().equals("Bus")){
            System.out.println("汽车票收取1%手续费");
            sellTickets.sell();
            System.out.println("出票~~");
        } else if (sellTickets.getName().equals("Train")){
            System.out.println("火车票收取3%手续费");
            sellTickets.sell();
            System.out.println("出票~~");
        }
    }

    @Override
    public String getName() {
        return name;
    }
}
5)测试
public class Client {
    public static void main(String[] args) {
        AirTickets airTickets = new AirTickets();
        BusTicket busTicket = new BusTicket();
        TrainTicket trainTicket = new TrainTicket();

        /*
        * 开设三个窗口,每个窗口售卖指定类型的票
        * 分别代理飞机、汽车、火车
        * */
        GoWhereProxy goWhereProxy1 = new GoWhereProxy(airTickets);
        goWhereProxy1.sell();

        GoWhereProxy goWhereProxy = new GoWhereProxy(busTicket);
        goWhereProxy.sell();

        GoWhereProxy goWhereProxy2 = new GoWhereProxy(trainTicket);
        goWhereProxy2.sell();
    }
}
6)结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yw6F3uCS-1643880921391)(F:\StudyNotepad\img\image-20211122214044057.png)]

小结

优点:在不修改目标对象的功能前提下, 能通过代理对象对目标功能扩展

缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类

一旦接口增加方法,目标对象与代理对象都要维护

动态代理

基本介绍

  1. 代理对象,不需要实现接口,但是目标对象要实现接口,否则不能用动态代理
  2. 代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象
  3. 动态代理也叫做:JDK代理、接口代理

实例测试

1)UML类图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dVgLAiQh-1643880921392)(F:\StudyNotepad\img\image-20211122215351375.png)]

2)创建公共接口
public interface SellTickets {
    void sell();
}
3)实现公共接口
public class AirTicket implements SellTickets{
    @Override
    public void sell() {
        System.out.println("售卖飞机票~~");
    }
}
4)编写动态代理
public class DynamicProxy {
    private Object target;

    public DynamicProxy(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 {
                        System.out.println("代理模式开始~~");
                        
                        /*
                        * target.getClass().getName().equals("dynamicproxy.AirTicket")就可以进行判断来做出不同的代理
                        * 为什么是:dynamicproxy.AirTicket,这个其实可以通过在控制台来打印获取到名称,这里我就是通过
                        * System.out.println(target.getClass().getName());来在控制台输出获取到类的名称的
                        * */
                        /*
                        * 11.30改进
                        * - 将获取类的信息改为instance判断
                        * */
                        if (target instanceof AirTicket){
                            System.out.println("收取5%的手续费");
                        } else if (target instanceof TrainTicket){
                            System.out.println("收取3%手续费");
                        } else if (target instanceof BusTicket){
                            System.out.println("收取1%手续费");
                        } else {
                            System.out.println();
                        }

                        Object invoke = method.invoke(target, args);
                        System.out.println("出票~~");
                        return invoke;
                    }
                });
    }
}

小结

举报

相关推荐

0 条评论