设计模式之结构型模式

84 阅读8分钟

二、结构型模式

6、适配器模式

package com.znd.factory.adapter;

//1、继承(类适配器,单继承)
//2、组合(对象适配器:常用)

//真正的适配器,需要连接USB,网线
public class Adapter2 implements NetToUsb {

    private Adaptee adaptee;

    public Adapter2(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void handleRequest() {
        adaptee.request();
    }
}

推荐使用这种组合模式(对象适配器)

    public static void main(String[] args) {
        //电脑,适配器,网线
        Computer computer = new Computer(); //电脑
        Adaptee adaptee = new Adaptee();    //网线
//        Adapter adapter = new Adapter();    //转接器
        Adapter2 adapter = new Adapter2(adaptee);    //转接器

        computer.net(adapter);
    }

7、桥接模式

场景:

在抽象类Type中组合Brand达到桥接作用

public abstract class Type {
    //组合,品牌
    protected Brand brand;

    public Type(Brand brand) {
        this.brand = brand;
    }

    public void info(){
        brand.info();//自带品牌
    }
}
public interface Brand {
    void info();
}
package com.znd.bridge;

public class Test {
    public static void main(String[] args) {
        //苹果笔记本
        Type computer = new Laptop(new Apple());
        computer.info();
        // 联想台式机
        Type computer1 = new Desktop(new Lenovo());
        computer1.info();
        //戴尔手表
        Type computer2 = new Watch(new Dell());
        computer2.info();
    }
}

场景:

  • Java语言通过Java虚拟机实现了平台的无关性
  • AWT中的Peer架构
  • JDBC驱动程序也是桥接模式的应用之一

8、代理模式

为什么要学习代理模式?

因为SpringAOP(面向切面编程)的底层

  • 静态代理
  • 动态代理

8.1 静态代理

角色分析:

  • 抽象角色:一般会用接口或者抽象类来解决
  • 真实角色:被代理的角色
  • 代理角色:代 理真实角色,代理真实角色后,我们一般会做一些附属操作
  • 客户:访问代理对象的人

代码步骤:

1、接口

//租房
public interface Rent {
    public void rent();
}

2、真实角色

//房东
public class Host implements Rent{

    @Override
    public void rent() {
        System.out.println("房东出租房子");
    }
}

3、代理角色

public class Proxy implements Rent{
    private Host host;

    public Proxy() {
    }

    public Proxy(Host host) {
        this.host = host;
    }

    @Override
    public void rent() {
        seeHouse();
        host.rent();
        fare();
        heTong();
    }

    public void seeHouse(){
        System.out.println("中介看房流");
    }

    public void fare(){
        System.out.println("手中介费");
    }

    public void heTong(){
        System.out.println("签租赁合同");
    }
}

4、客户端访问代理角色

public class Client {
    public static void main(String[] args) {
        //房东
        Host host = new Host();
        //代理,中介帮房东租房子,但是代理一般会有附属操作
        Proxy proxy = new Proxy(host);

        //直接找代理租房
        proxy.rent();
    }
}

代理模式的好处:

  • 可以是真实角色的操作更加纯粹!不去关注一些公共的业务
  • 公共也就交给代理角色,实现了业务的分工
  • 公共业务发生扩展的时候,方便集中管理

缺点:

  • 一个真实角色就会产生一个代理角色:代码量会翻倍~开发效率变低

8.2 静态代理Pro

1、接口

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

2、真实对象

//真实对象
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("增加");
    }

    @Override
    public void delete() {
        System.out.println("删除");
    }

    @Override
    public void update() {
        System.out.println("跟新");
    }

    @Override
    public void query() {
        System.out.println("查询一个");
    }
}

3、代理

public class UserServiceProxy implements UserService {
   private UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    @Override
    public void add() {
        log("add");
        userService.add();
    }

    @Override
    public void delete() {
        log("delete");
        userService.delete();
    }

    @Override
    public void update() {
        log("update");
        userService.update();
    }

    @Override
    public void query() {
        log("query");
        userService.query();
    }

    public void log(String msg){
        System.out.println("【Debug】使用了"+msg+"方法");
    }
}

4、客户端访问

public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        UserServiceProxy userServiceProxy = new UserServiceProxy();
        userServiceProxy.setUserService(userService);
        userServiceProxy.add();
    }
}

AOP 的切面机制

8.3 动态代理

  • 动态代理和静态代理角色一样
  • 动态代理的类是动态生成的,不是我门直接写好的
  • 动态代理分为两大类:基于接口的动态大力,基于类的动态代理
    • 基于接口----JDK 动态代理
    • 基于类:cglib
    • java字节码实现:JAVAssist(在jboss实现“AOP”)

了解两个类:Proxy: 代理,InvocationHandler: 调用处理程序

工具类:

package com.znd.proxy.demo04;

import com.znd.proxy.demo03.Rent;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyInvocationHandler implements InvocationHandler {

    //被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    //生成得到代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    //处理代理实例并返回结果
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());
        //动态代理的本质,就是使用反射机制实现!
        Object result = method.invoke(target, args);
        return result;
    }

    public void log(String msg){
        System.out.println("【Debug】执行了"+msg+"方法");
    }
}

客户端:

public class Client {
    public static void main(String[] args) {
        //真实角色
        UserServiceImpl userService = new UserServiceImpl();
        //代理角色,现不存在
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        //设置要代理的对象
        pih.setTarget(userService);
        //动态生成代理类
        UserService proxy = (UserService) pih.getProxy();

        proxy.add();
        proxy.query();
    }
}

动态代理的好处:

  • 可以是真实角色的操作更加纯粹!不去关注一些公共的业务
  • 公共也就交给代理角色,实现了业务的分工
  • 公共业务发生扩展的时候,方便集中管理
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可

9、装饰模式

10、外观模式(门面)

package com.znd.Facade;

public class FacadePattern {
    public static void main(String[] args) {
        System.out.println(new Facade().prove());
    }
}
class SubFlow1{
    boolean isTrue(){
        return true;
    }
}
class SubFlow2{
    boolean isOK(){
        return true;
    }
}
class SubFlow3{
    boolean isGoodMan(){
        return true;
    }
}
class Facade{
    SubFlow1 s1 = new SubFlow1();
    SubFlow2 s2 = new SubFlow2();
    SubFlow3 s3 = new SubFlow3();
    boolean prove(){
        return s1.isTrue()&&s2.isOK()&&s3.isGoodMan();
    }
}

隐藏系统复杂性,但是违反了开闭原则

11、组合模式

解决树形结构的问题,学校-学院-专业,专业是叶子节点

)

  1. Component:组合中对象声明接口,实现所有类共有的接口默认行为,用户访问和管理Component子部件,可以是抽象类或者接口
  2. Leaf:在组合中表示叶子节点,叶子节点没有子节点
  3. Composite:非叶子节点,用户存储子部件,在Component接口中实现子部件的相关操作

1、接口

public abstract class OrganizationComponent {

    private String name; //名字
    private String des;  //描述

    protected void add(OrganizationComponent organizationComponent){
        //默认实现
        throw new UnsupportedOperationException();
    }
    protected void remove(OrganizationComponent organizationComponent){
        //默认实现
        throw new UnsupportedOperationException();

    }

    public OrganizationComponent(String name, String des) {
        this.name = name;
        this.des = des;
    }

    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;
    }
    //print做成抽象的
    protected abstract void print();
}

2、子节点-学校

//University 就是Composite,可以管理College
public class University extends OrganizationComponent {

    List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();

    public University(String name,String des){
        super(name,des);

    }

    @Override
    protected void add(OrganizationComponent organizationComponent) {
        organizationComponents.add(organizationComponent);
    }

    @Override
    protected void remove(OrganizationComponent organizationComponent) {
        organizationComponents.remove(organizationComponent);
    }

    @Override
    protected void print() {
        System.out.println("---------"+getName()+"---------");
        for ( OrganizationComponent organizationComponent:organizationComponents){
            organizationComponent.print();
        }
    }
}

3、子节点-学院

public class College extends OrganizationComponent{

    List<OrganizationComponent> organizationComponents = new ArrayList<OrganizationComponent>();

    @Override
    protected void add(OrganizationComponent organizationComponent) {
        organizationComponents.add(organizationComponent);
    }

    @Override
    protected void remove(OrganizationComponent organizationComponent) {
        organizationComponents.remove(organizationComponent);
    }


    public College(String name, String des) {
        super(name, des);
    }

    @Override
    protected void print() {
        System.out.println("========="+getName()+"===========");
        for (OrganizationComponent organizationComponent:organizationComponents){
            organizationComponent.print();
        }
    }
}

4、叶子节点-专业

public class Department extends OrganizationComponent {
    public Department(String name, String des) {
        super(name, des);
    }
    //叶子节点没有add,remove操作
    @Override
    protected void print() {
        System.out.println(getName());
    }
}

5、客户端

public class Client {
    public static void main(String[] args) {
        //从大到小创建对象
        University university = new University("清华大学", "niubidaxue");
        College college = new College("计算机学院", "kkkk");
        College college1 = new College("属虚的学院", "444");
        college.add(new Department("软件工厂","222"));
        college.add(new Department("网络工程","sss"));
        college.add(new Department("计算机嵌入","dsda"));

        college1.add(new Department("高数","sdadasd"));
        college1.add(new Department("dsad","sdasd"));

        university.add(college);
        university.add(college1);

//        university.print();
        college.print();
//        college1.print();
    }
}

组合模式在JDK集合的源码分析

Java的集合类-HashMap就是使用了组合模式

  • Map就是一个抽象的构建(类似我们的Component)
  • HashMap是一个中间的构建(Composite),实现继承了相关方法put,putall
  • Node 是HashMap的静态内部类,类似Leaf叶子节点,这里就没有put,putall
    • static class Node<k,v> implements Map.Entry<k,v>
public class Composite {
    public static void main(String[] args) {
        Map<Integer,String> hashMap = new HashMap<Integer, String>();
        hashMap.put(0,"东游记");
        Map<Integer,String> map = new HashMap<Integer, String>();
        map.put(1,"西游记");
        map.put(2,"红楼梦");
        hashMap.putAll(map);
        System.out.println(hashMap);
        System.out.println(map);
    }
}

如果节点和叶子有很多差异性的话,若很多方法和属性都不一样,不适合使用组合模式

12、享元模式

所有人都骑着自己的自行车,势必导致交通拥堵,共享单车减轻

  • 享元模式:主要用于减少创建对象的数量,以减少内存占用和提高性能

  • 内部状态:在享元对象内部并且不会随环境改变而改变的共享部分

    (用工厂类来创建)

  • 外部状态:随环境改变而改变,不可以共享的状态

    (通过参数调用传递)

1、接口

public interface Bike {
    public void use(User user);
}

2、实体类生产bike(内部状态)

public class ConcreteBike implements Bike {
    private String name;

    public ConcreteBike(String name) {
        this.name = name;
    }

    @Override
    public void use(User user) {
        System.out.println(user.getName()+"骑走了"+this.name+"自行车");
    }

}

3、User(外部状态)

public class User {
    private String name;
    public User(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}

4、工厂(关键)

public class BikeFactory {
    private Hashtable hashtable = new Hashtable();
	
    //判断是否已有
    public Bike getBike(String key){
        if (!hashtable.containsKey(key)){
            hashtable.put(key,new ConcreteBike(key));
        }
        return (Bike) hashtable.get(key);
    }
    public int bikeCount(){
        return hashtable.size();
    }
}

5、Client

public class Client {
    public static void main(String[] args) {
        BikeFactory bikeFactory = new BikeFactory();
        Bike mb = bikeFactory.getBike("mb");
        mb.use(new User("小红"));
        Bike mb1 = bikeFactory.getBike("mb");
        mb1.use(new User("小华"));

        Bike qj = bikeFactory.getBike("qj");
        qj.use(new User("张三"));
        System.out.println("新建自行车的数量:"+bikeFactory.bikeCount());
    }
}

意图:

​ 运用共享技术有效地支持大量细粒度的对象

应用场景:

  1. 系统有大量相似的对象
  2. 需要缓冲池的场景

优点:

​ 大大减少对象的创建,降低系统的内存,是效率提高。

缺点:

​ 提高了系统的复杂度,需要分理处外部状态和内部状态而且外部状态不应该随着内部状态的变化而变化,否则会造成系统的混乱。

注意:

1. 注意划分内部状态和外部状态,否则可能会引起线程安全问题。

 	2. 这些类必须有一个工厂对象加以控制。