设计模式——结构型模型

本文详细介绍了设计模式中的结构型模式,包括装饰者模式、代理模式、组合模式、桥接模式、适配器模式、蝇量模式和外观模式。装饰者模式动态增加对象职责,代理模式控制访问,组合模式实现部分-整体结构,桥接模式分离抽象与实现,适配器模式使不兼容接口协同工作,蝇量模式实现对象复用,外观模式简化子系统调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一:目录
1. 装饰者模式(Decorator)
2. 代理模式(Proxy)
3. 组合模式(Composite)
4. 桥接模式(Bridge)
5. 适配器模式(Adapter)
6. 蝇量模式(Flyweight)
7. 外观模式(Facade)

二:详细介绍

2.1 装饰者模式(Decorator)
2.1.1 简介:
动态的给一些对象增加一些额外的职责。采用组合的方式,比继承更为灵活。
应用场景:
问题:你从何处来,要到哪里去,能够解决什么样的问题,有什么样的应用场景,和别的模式有什么区别?
2.1.2 类图:

在这里插入图片描述
1. 组件接口:

public interface Component
{
    void operation();
}

2. 组件实现类:

public class ConcreteComponent implements Component
{
    public void operation()
    {
        // Write your code here
    }
}

3. 装饰器接口:

interface Decorator {
	
	void operation();
}

4. 装饰器实现类:

class ConcreteDecorator implements Decorator{
	
	private Component component;
	
    public void operation(){
        //addBehavior也可以在前面
    	component.operation();
        
        addBehavior();
    }
    
    private void addBehavior()
    {
        //your code
    }
}

2.1.4 实例:
Java IO设计,就用到了装饰者模式,见上边的类图(PS:拓展,看看NIO)

2.2 代理模式(Proxy)
2.2.1 简介:
代理模式(Proxy)与装饰者模式(Decorator)的区别:
装饰模式是新增行为,代理模式是控制访问

2.2.2 类图:
在这里插入图片描述

2.2.3 代码:

简单静态模式代码:

public class ProxyDemo {
    public static void main(String args[]){
        Subject subject = new RealSubject();
        Proxy p = new Proxy(subject);
        p.request();
    }
}
interface Subject {
    void request();
}
class RealSubject implements Subject{
    public void request(){
        System.out.println("request");
    }
}
class Proxy implements Subject{
    private Subject subject;
    public Proxy(Subject subject){
        this.subject = subject;
    }
    public void request(){
        System.out.println("PreProcess");
        subject.request();
        System.out.println("PostProcess");
    }
}

实例

Java动态代理(只能代理接口):

interface UserDao {
    void drink();
}
class UserImpl implements UserDao {

    @Override
    public void drink() {
         System.out.println(getClass().getName() + " drink.");
    }
}
class UserProxy implements InvocationHandler {
    
    private UserDao userDao;
    
    public UserProxy(UserDao userDao) {
         this.userDao = userDao;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
             throws Throwable {
         this.beforeDrink();
         userDao.drink();
         this.afterDrink();
         return null;
    }
    public void beforeDrink() {
         System.out.println(getClass().getName() + " beforeDrink.");
    }
    public void afterDrink() {
         System.out.println(getClass().getName() + " afterDrink.");
    }
}

public class ProxyClient {
    
    public static void main(String[] args) {
         UserDao userDao = new UserImpl();
         UserProxy userProxy = new UserProxy(userDao);
         UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), userProxy);
         userDaoProxy.drink();
    }
}

Java Cglib代理:
Cglib代理可以代理类,广泛的应用在Spring AOP、日志记录里
Cglib包的底层是用字节码处理框架ASM来转换字节码并生成新的子类
代理的类不能是final,否则会报错;目标对象的方法为final/static,那么就不会拦截

class User {
    public void eat() {
        System.out.println(this.getClass().getName() + " is eating!");
    }
}

class ProxyFactory implements MethodInterceptor {
    
    private Object target;
    
    public ProxyFactory(Object target) {
         this.target = target;
    }
    
    public Object getProxyInstance() {
         //1.工具类
         Enhancer en = new Enhancer();
         //2.设置父类
         en.setSuperclass(target.getClass());
         //3.设置回调函数
         en.setCallback(this);
         //4.创建子类(代理对象)
         return en.create();
    }
    
    @Override
    public Object intercept(Object paramObject, Method method, Object[] args,
             MethodProxy paramMethodProxy) throws Throwable {
        System.out.println(this.getClass().getName() + " before proxy.");
         Object returnValue = method.invoke(target, args);
        System.out.println(this.getClass().getName() + " after proxy.");
         System.out.println("返回结果:" + returnValue);
         return null;
    }
    
}

public class CglibDynamicProxyClient {
    
    public static void main(String[] args) {
         User user = new User();
         User proxyUser = (User) new ProxyFactory(user).getProxyInstance();
         proxyUser.eat();
    }
}

Java远程代理:

在这里插入图片描述

虚拟代理:
使用虚拟代理的场景:
(1) 由于对象本身的复杂性或者网络等原因导致一个对象需要较长的加载时间,此时可以用一个加载时间相对较短的代理对象来代表真实对象。
(2) 当一个对象的加载十分耗费系统资源的时候,也非常适合使用虚拟代理。为节省空间,可以延迟加载。

缓冲代理:
使用缓冲代理的作用:
(1) 它为某一个操作的结果提供临时的缓存存储空间,以便在后续使用中能够共享这些结果,从而可以避免某些方法的重复执行,优化系统性能。

保护代理:
使用保护代理的作用:
(1) 保护代理可以控制对一个对象的访问权限,为不同用户提供不同级别的使用权限。

2.3 组合模式(Composite)

2.3.1 简介:
组合模式定义了如何将容器对象和叶子对象进行递归组合,使得客户在使用的过程中无需进行区分,可以对他们进行一致的处理。
有一个应用场景为文件夹的遍历。
优点:
1. 可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构建也更容易。
2. 客户端使用简单,客户端可以一致的使用组合结构或其中单个对象。
3. 定义了包含叶子对象和容器对象的类层次结构,叶子对象可以被组合成更复杂的容器对象,而这个容器对象又可以被组合,不断递归,可以形成复杂的树状结构,就像文件夹系统一样。
4. 使得在组合体内加入对象构建更加容易,客户端不必因为加入了新的对象构建而更改原有代码

缺点:
1. 使得设计变得更加抽象,对象的业务逻辑如果很复杂,则实现难度会很大,并且不是所有的方法都与叶子对象子类有关联

使用场景:
1. 组合模式用于将多个对象组合成树状结构以表示“整体-部分”的结构层次。组合模式对单个对象(叶子对象)和组合对象(容器对象)的使用具有一致性
2. 组合对象的关键在于它定义了一个抽象构建类,它既可以表示叶子对象,也可以表示容器对象,客户仅需要对这个抽象构建进行编程,无论是叶子还是容器对象,都一致对待

2.3.2 类图:

在这里插入图片描述

2.3.3 代码:
PS:上面的类图用的是接口,下面用的是虚类,道理是一样的。

abstract class File {
    String name;
    abstract void display();
}
class ImageFile extends File {
    
    public ImageFile(String name) {
         this.name = name;
    }
    @Override
    void display() {
         System.out.println(getClass().getName() + " " + name + " display.");
    }
}

class TextFile extends File {
    
    public TextFile(String name) {
         this.name = name;
    }
    @Override
    void display() {
         System.out.println(getClass().getName() + " " + name + " display.");
    }
}

class Folder extends File {
    
    private List<File> files ;
    public Folder(String name) {
         this.name = name;
         files = new ArrayList<>();
    }
    @Override
    void display() {
         for(File file : files) {
             file.display();
         }
    }
    public void addFile(File file) {
         files.add(file);
    }
    public void deleteFile(File file) {
         files.remove(file);
    }
}

public class CompositeClient {
    
    public static void main(String[] args) {
         File image = new ImageFile("Image");
         File text = new TextFile("Text");
         Folder folder = new Folder("folder");
         Folder subFolder = new Folder("subFolder");
         File subImage = new ImageFile("subImage");
         File subText = new TextFile("subText");
         folder.addFile(image);
         folder.addFile(text);
         folder.display();
         folder.addFile(subFolder);
         subFolder.addFile(subImage);
         subFolder.addFile(subText);
         folder.display();
    }
    
}

2.4 桥接模式(Bridge)

2.4.1 简介:
桥梁模式是对象的结构模式。又称为柄体(Handle and Body)模式(注:水杯的杯柄与杯子的关系)或接口(Interface)模式
桥梁模式的用意是:将抽象化(Abstraction)与实现化(Implementation)脱耦,使得二者可以独立的变化。
通过组合的方式,使重复逻辑以及类的数量最小化,更加方便扩展。
优点:
分离抽象、实现部分,极大的提供了系统的灵活性。

抽象化:从众多的事物中,抽取出共同的、本质的特征,而舍弃其非本质的特征,就是抽象化。在抽象中,同与不同,取决于从哪个角度进行抽象,而角度取决于分析问题的目的。

实现化:抽象化给出的具体实现,就是实现化。
一个类的实例就是类的实例化,一个具体自雷就是他的抽象超类的实例化。

耦合:指的是两个实体行为的某种强关联。而将他们的强关联去掉,就是耦合的解脱,或称脱耦。
在这里,脱耦是指将抽象化与实现化之间的耦合解脱开,或者说将他们的强关联改成弱关联。

在这里插入图片描述

上图两个层级结构:
1. 由抽象化角色和修正抽象化角色组成的抽象化等级结构
2. 由实现化角色和两个具体实现化角色所组成的实现化等级结构

涉及到的角色:
抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用
修正抽象化(RefinedAbstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义
实现化角色(Implementor):这个角色给出实现化角色的接口,但不给出具体的实现。一般,实现化角色只给出底层的操作,而抽象化角色给出更高一层的操作
具体实现化角色(ConcreteImplementor):这个角色给出实现化角色接口的具体实现

桥梁模式的应用实例

在这里插入图片描述

2.5 适配器模式(Adapter)
2.5.1 简介
适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配无法一起工作的两个类能协同工作
适配器模式里有一种缺省适配器,应用比较广泛。他是为了方便建立一个不平庸的适配器类而提供的一种平庸实现。
2.5.2 类图

在这里插入图片描述

2.6 蝇量模式(Flyweight)
2.6.1简介:
享元模式(Flyweight Pattern):运用共享技术有效的支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又被称为轻量级模式,它是一种对象结构型模式。
Flyweight(抽象享元类):通常是一个接口或抽象类,其中生命了具体想元类公共的方法
ConcreteFlyweight(具体享元类):实现了抽象想元类,实例被称为享元对象;通常结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象。
UnsharedConcreteFlyweight(非共享具体享元类):并不是抽象想元类的子类都要被共享,不能被共享的子类可设计为此;
FlyweightFactory(享元工厂类):享元工厂类用于创建并管理享元对象,提供一个享元对象的享元池。一般设计为单例模式
2.6.1类图:

在这里插入图片描述

2.6.1应用实例:
Java的String类设计就用了Flyweight模式.String对象为final,内部char[]存储在常量池里

2.7 外观模式(Facade)

2.7.1简介:
通过引入一个外观角色来简化客户端与子系统之间的交互,为复杂的子系统调用提供一个统一的入口,降低子系统与客户端的耦合度,且方便客户端调用

2.7.2结构图:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值