java

设计模式之二:结构型模式

2019-06-10  本文已影响0人  suxin1932

https://www.cnblogs.com/liuzhen1995/category/896299.html

结构型模式

结构型模式涉及如何组合类和对象以形成更大的结构:
和类有关的结构型模式设计如何合理地使用继承机制;
和对象有关的结构型模式涉及如何合理地使用对象组合机制。

(1)适配器模式:
将一个类的接口转换成客户希望的另外一个接口。
Adapter模式使原本由于接口不兼容而不能一起工作的那些类可以一起工作。
(2)组合模式:
将对象组合成数形结构以表示”部分-整体“的层次结构。
Composite使用户对单个对象和组合对象的使用具有一致性。
(3)代理模式:
为其他对象提供一种代理以控制对这个对象的访问。
(4)享元模式:
运用共享技术有效地支持大量细粒度的对象。
(5)外观模式:
为系统的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使这一子系统更加容易使用。
(6)桥接模式:
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
(7)装饰模式:
动态地给对象添加一些额外的职责,就功能来说装饰模式相比生成子类更为灵活。

1.适配器模式

#适配器模式
是将一个类的接口(被适配者)转换成客户希望的另外一个接口(目标)的成熟模式,
该模式中涉及有目标、被适配者和适配器。
适配器模式的关键是建立一个适配器,这个适配器实现了目标接口并包含有被适配者的引用。
将一个类的转接口转换成客户希望的另外一个接口,
适配器模式使得原来由于接口不兼容的而不能的工作的哪些类可以工作, 主要作用就是兼容。

#应用场景: 
编码解码、 一拖三充电头、HDMI 转 VGA
在spring中 基本adapter结尾都是适配器

#适配器模式的结构
(1)目标(Target):目标是一个接口,该接口是客户想使用的接口。
(2)被适配者(Adaptee):被适配者是一个已存在的接口或者抽象类,这个接口或者抽象类需要适配。
(3)适配器(Adapter):适配器实现了目标接口并包含有被适配者的应用,即适配器的职责是对被适配者接口与目标接口进行适配。

#分类:
类适配器 (通过引用适配者进行组合实现)
对象适配器(通过继承适配者进行实现)
接口适配器 (通过抽象类来实现适配)

1.1demo01

适配器demo01.png
package com.zy.designPattern.adapter;
/**
 * 目标: target
 *  用来表示三相插座
 */
public interface ThreePhaseSocket {
    /**
     * 插入三相插座
     */
    void input();
}
package com.zy.designPattern.adapter;
/**
 * 被适配者: adaptee
 *  用来表示两相插座
 */
public interface TwoPhaseSocket {
    /**
     * 插入两相插座
     */
    void input();
}
package com.zy.designPattern.adapter;

import lombok.AllArgsConstructor;
/**
 * 适配器
 */
@AllArgsConstructor
public class ThreePhaseAdapter implements ThreePhaseSocket {
    //定义一个二相插座的引用对象
    private TwoPhaseSocket twoPhaseSocket;
    @Override
    public void input() {
        // 通过二相插座引用对象调用其具体方法,实现二相插座通电
        twoPhaseSocket.input();
    }
}
package com.zy.designPattern.adapter;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
/**
 * 冰箱:
 * 需要使用三相插座
 */
@AllArgsConstructor
@NoArgsConstructor
public class Refrigerator implements ThreePhaseSocket {
    private String name;
    @Override
    public void input() {
        cold();
    }
    public void cold() {
        System.out.println("开始冷冻衣服");
    }
}
package com.zy.designPattern.adapter;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
/**
 * 电脑:
 * 使用两相插座
 */
@AllArgsConstructor
@NoArgsConstructor
public class PC implements TwoPhaseSocket {
    private String name;
    @Override
    public void input() {
        playApp();
    }
    public void playApp() {
        System.out.println("运行app ..............");
    }
}
package com.zy.designPattern.adapter;

public class AdapterTest {
    public static void main(String[] args) {
        // 目标接口(三相插座)
        ThreePhaseSocket threePhaseSocket;
        // 冰箱 ---> 使用三相插座
        System.out.println("------------");
        Refrigerator refrigerator = new Refrigerator();
        threePhaseSocket = refrigerator;
        threePhaseSocket.input();
        System.out.println("------------");
        // PC ----> 使用三相适配器
        PC pc = new PC();
        ThreePhaseAdapter adapter = new ThreePhaseAdapter(pc);
        threePhaseSocket = adapter;
        threePhaseSocket.input();
    }
}

1.2接口适配器模式demo

当存在这样一个接口,其中定义了N多的方法,而我们现在却只想使用其中的一个到几个方法,
如果我们直接实现接口,那么我们要对所有的方法进行实现,
哪怕我们仅仅是对不需要的方法进行置空也会导致这个类变得臃肿,
调用也不方便,这时我们可以使用一个抽象类作为中间件,即适配器,用这个抽象类实现接口,
而在抽象类中所有的方法都进行置空,那么我们在创建抽象类的继承类,而且重写我们需要使用的那几个方法即可。
接口适配器模式.png
package com.zy.designPattern.adapter.interfacePattern;

public class AC220 {
    public int output220V(){
        int output = 220;
        return output;
    }
}
package com.zy.designPattern.adapter.interfacePattern;

public interface DCOutput {
    /**
     * 5V直流电
     * @return
     */
    int output5V();
    /**
     * 9V直流电
     * @return
     */
    int output9V();
    /**
     * 12V直流电
     * @return
     */
    int output12V();
    /**
     * 24V直流电
     * @return
     */
    int output24V();
}
package com.zy.designPattern.adapter.interfacePattern;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

/**
 * 接口型适配器:
 *  抽象类
 */
@AllArgsConstructor
@NoArgsConstructor
public abstract class PowerAdapter implements DCOutput {
    protected AC220 ac220;
    @Override
    public int output5V() {
        return ac220.output220V();
    }
    @Override
    public int output9V() {
        return ac220.output220V();
    }
    @Override
    public int output12V() {
        return ac220.output220V();
    }
    @Override
    public int output24V() {
        return ac220.output220V();
    }
}
package com.zy.designPattern.adapter.interfacePattern;

import lombok.AllArgsConstructor;

public class Power5VAdapter extends PowerAdapter {
    public Power5VAdapter(AC220 ac220) {
        super(ac220);
    }
    @Override
    public int output5V() {
        int output = 0;
        if (ac220 != null) {
            output = ac220.output220V() / 44;
        }
        return output;
    }
}
package com.zy.designPattern.adapter.interfacePattern;

public class AdapterDemo {

    public static void main(String[] args) {
        PowerAdapter adapter = new Power5VAdapter(new AC220());
        System.out.println(adapter.output5V());
    }
}

3.代理模式

https://blog.csdn.net/weixin_39452731/article/details/88937828

静态代理
jdk动态代理(效率高, 依赖接口)
cglib动态代理(效率低, 不依赖接口)

示例`: 基于代理的aop实现日志同一拦截打印

<properties>
   <spring.version>5.1.7.RELEASE</spring.version>
</properties>

<dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- 单元测试包开始 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-all</artifactId>
            <version>1.10.19</version>
        </dependency>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.14.3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- 异步测试包 -->
        <dependency>
            <groupId>org.awaitility</groupId>
            <artifactId>awaitility</artifactId>
            <version>3.1.6</version>
            <scope>test</scope>
        </dependency>
        <!-- 单元测试包结束 -->

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>20.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
</dependencies>
package com.zy.designPattern.proxy.aop;

import java.lang.annotation.*;

@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAspect {
}
package com.zy.designPattern.proxy.aop;

import com.google.common.base.Joiner;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
public class LogAspectAdvice {

    @Around("@within(com.zy.designPattern.proxy.aop.LogAspect) || @annotation(com.zy.designPattern.proxy.aop.LogAspect)")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        // 获取参数
        Object[] args = point.getArgs();
        // 获取signature
        MethodSignature signature = (MethodSignature) point.getSignature();
        // 获取要代理的类的全限定名
        String className = signature.getDeclaringType().getName();
        // 获取要代理的方法的名称
        String methodName = signature.getName();
        // 获取方法入参的值
        String params = Joiner.on(",").useForNull("null").join(args);
        // 方法执行前打印日志
        //log.info(String.format("class: %s, method: %s, params-in: %s;", className, methodName, params));
        System.out.println((String.format("class: %s, method: %s, params-in: %s;", className, methodName, params)));
        // 执行方法
        Object result = point.proceed();
        // 方法执行后打印日志
        //log.info(String.format("class: %s, method: %s, params-out: %s;", className, methodName, result));
        System.out.println(String.format("class: %s, method: %s, params-out: %s;", className, methodName, result));
        return result;
    }

}
package com.zy.designPattern.proxy.aop;

import com.zy.designPattern.common.Stu;
import org.springframework.stereotype.Service;

@Service("logAspectService")
public class LogAspectServiceImpl {

    @LogAspect
    public Object hello(Stu stu) {
        return stu.toString() + "---> end";
    }

}
package com.zy.designPattern;

import com.zy.designPattern.common.Stu;
import com.zy.designPattern.proxy.aop.LogAspectServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:META-INF/applicationContext.xml")
public class LogAspectServiceImplTest {

    @Autowired
    private LogAspectServiceImpl logAspectService;

    @Test
    public void testHello() {
        logAspectService.hello(new Stu(1, "tom"));
    }
}

7.装饰器模式

#装饰器模式的角色
>> 抽象构件角色(component):
给出一个抽象类/接口, 以规范准备接收附加责任的对象, 如InputStream
>> 具体构件角色(concrete component):
定义一个将要接收附加责任的类, 如FileInputStream
>> 装饰器角色(decorator):
持有一个构件(component)对象的引用, 并实现抽象构件角色的抽象类/类, 如FilterInputSteram
>> 具体装饰器角色(concrete decorator):
负责给构件对象"贴上"附加的责任, 如BufferedInputStream

#装饰器模式的特点
>> 装饰对象和真实对象实现相同的接口/抽象类。
>> 装饰对象包含真实对象的引用。
>> 装饰对象接收所有客户端的请求, 并转发给真实对象。
>> 装饰对象可以在转发这些请求之前或之后增加一些功能。

#装饰器模式 VS 继承
1.装饰模式:
>> 用来扩展特定'对象'的功能
>> 不需要子类
>> 动态
>> 运行时分配职责
>> 防止由于子类而导致的复杂和混乱
>> 更多的灵活性
>> 对于一个给定的对象, 可能有不同的一个或多个装饰对象
2.继承
>> 用来扩展一类对象的功能
>> 需要子类
>> 静态
>> 编译时分配职责
>> 导致很多子类产生
>> 缺乏灵活性

#适用范围
>> 想要透明并且动态地给对象增加新的方法而又不影响其他对象
>> 给对象增加的职责在未来可能发生改变
>> 用子类扩展功能不可行的情况下
package com.zy.designPattern.decorator.tree;

/**
 * 接口
 */
public interface Tree {
    void operator();
}
package com.zy.designPattern.decorator.tree;

import lombok.AllArgsConstructor;

/**
 * 普通圣诞树
 */
@AllArgsConstructor
public class ChristmasTree implements Tree {
    private String name;
    @Override
    public void operator() {
        System.out.println(this.name + "普通圣诞树");
    }
}
package com.zy.designPattern.decorator.tree;

import lombok.AllArgsConstructor;

/**
 * 装饰器
 */
@AllArgsConstructor
public class Decorator implements Tree {
    protected Tree tree;
    @Override
    public void operator() {
        tree.operator();
    }
}
package com.zy.designPattern.decorator.tree;

/**
 * 具体装饰器
 */
public class SockesTree extends Decorator {
    private String name;
    public SockesTree(Tree tree, String name) {
        super(tree);
        this.name = name;
    }
    @Override
    public void operator() {
        super.operator();
        System.out.println(this.name + "装饰着" + tree);
    }
}
package com.zy.designPattern.decorator.tree;

import org.junit.Test;
public class DecoratorTest {
    @Test
    public void fn01() {
        Tree christmasTree = new ChristmasTree("普通圣诞树");
        christmasTree.operator();

        SockesTree sockesTree = new SockesTree(christmasTree, "放袜子的圣诞树");
        sockesTree.operator();
    }
}
上一篇下一篇

猜你喜欢

热点阅读