设计模式学习笔记(3)——结构型设计模式

一:装饰者模式

1. 定义

又名包装模式。装饰模式以对客户端透明的方式,把经常改变的模块作为装饰,动态扩展对象的功能,是继承关系的一个替代方案。

  • 透明装饰者模式:具体组件和装饰器的接口与抽象组件的接口完全一致,属于同一超类型(具体组件不再扩展其他功能)
  • 半透明装饰者模式:具体组件和装饰器的接口与抽象组件的接口不一致(具体组件需要扩展其他功能)

2. 使用

  • 基本组件
  • 扩展组件:继承基本组件(保证同一类型)
  • 抽象装饰者:继承基本组件(保证同一类型)
    • 扩展或重新实现行为
  • 具体装饰者
    • 记录被装饰者
    • 扩展组件的状态或重新实现行为
(1)组件
package DecoratorPattern;

/**
 * 基本组件
 */
public interface Component {
    /**
     * 基本操作
     */
    public String operation();
}

package DecoratorPattern;

/**
 * 具体组件
 */
public class ComponentA implements Component{

    @Override
    public String operation() {
        return "具体组件A的具体操作";
    }
}

(2)装饰
package DecoratorPattern;

/**
 * 抽象装饰器
 */
public abstract class Decorator implements Component {
    /**
     * 装饰方法
     */
    public abstract String operation();

}

package DecoratorPattern;

/**
 * 具体装饰器
 */
public class DecoratorA extends Decorator{

    //记录被装饰者
    Component component;

    public DecoratorA(Component component){
        this.component = component;
    }

    //重新实现
    @Override
    public String operation() {
        //委托被装饰者的实现
        String s = component.operation();
        //进行装饰
        return s + ",装饰类A的装饰操作";
    }
    //扩展功能
    public String extend(){
        return "装饰类A的扩展功能";
    }
    
}

package DecoratorPattern;

/**
 * 具体装饰器
 */
public class DecoratorB extends Decorator{

    //记录被装饰者
    Component component;

    public DecoratorB(Component component){
        this.component = component;
    }

    //重新实现
    @Override
    public String operation() {
        //委托被装饰者的实现
        String s = component.operation();
        //进行装饰
        return s + ",装饰类B的装饰操作";
    }
    //扩展功能
    public String extend(){
        return "装饰类B的扩展功能";
    }
}

(3)测试
package DecoratorPattern;

public class Test {
    public static void main(String[] args) {
        Component component = new ComponentA();
        System.out.println(component.operation());
        Decorator decorator = new DecoratorA(component);
        System.out.println(decorator.operation());
        decorator = new DecoratorB(decorator);
        System.out.println(decorator.operation());

    }
}

3. 特点

  • 需要比继承关系较少的类
  • 产生比继承关系更多的对象
  • 装饰者与被装饰者属于同一超类型(抽象类或接口)
  • 可以用多个装饰者包装同一个对象
  • 可以动态装饰
  • 装饰者可以在被装饰者的之前或之后加上自己的行为,甚至取代其行为
  • 装饰者对组件的客户是透明的

4. 简化装饰器

  • 只有一个具体组件类
    • 去掉抽象的组件类(接口)
    • 把装饰器作为一个具体组件类的子类
  • 只有一个具体装饰器类
    • 去掉抽象的装饰器类
    • 把装饰器和具体装饰器合并成一个类

二:适配器模式

1. 定义

把一个类的接口变换成客户端所期待的另一种接口,使原本因接口不匹配而无法在一起工作的两个类能够在一起工作

2. 使用

把适配的类的API转换成为目标类的API

(1)类适配——多重继承
  • 抽象目标(由于JAVA无法实现双重继承,此处为抽象接口)
  • 抽象被适配者
  • 适配器:继承目标+被适配器,转换具体被适配对象
  • 客户:通过目标接口,调用适配器的方法,发出适配请求,得到适配对象

特点:

  • 是静态的定义方式
  • 只能处理具体的被适配类
  • 适配器可以重新定义被适配类的部分行为,相当于子类覆盖父类的部分实现方法
  • 不需要重新实现整个被适配类,只需要实现需要转换的方法即可
目标
package AdapterPattern.ClassAdapter;

/**
 * 抽象目标
 */
public interface Target {

    //目标方法1
    public void operator1();

    //目标方法2
    public void operator2();
}

被适配者
package AdapterPattern.ClassAdapter;

/**
 * 被适配者
 */
public class Adaptee {

     //被适配的方法
    public void operator1(){
        System.out.println("被适配的方法");
    }
}

适配器
package AdapterPattern.ClassAdapter;

/**
 * 适配器
 */
public class Adapter extends Adaptee implements Target
{

    @Override
    public void operator2() {
        System.out.println("把被适配的方法映射为目标的方法2");
    }
}

测试
package AdapterPattern.ClassAdapter;

public class Test {
    public static void main(String[] args) {
        Target target = new Adapter();
        target.operator1();
        target.operator2();
    }
}


(2)对象适配——组合
  • 抽象目标接口
  • 抽象被适配者
  • 适配器:实现目标接口,转换具体被适配对象
  • 客户:通过目标接口,把具体被适配器对象通过适配器的方法,得到适配对象

特点:

  • 是动态组合的方式
  • 同一个适配器可以把类和它的子类都适配到目标接口
  • 需要定义被适配者的子类来实现重定义,然后让适配器组合子类
  • 需要重新实现整个被适配类
目标
package AdapterPattern.ObjectAdapter;

/**
 * 抽象目标
 */
public interface Target {

    //目标方法1
    public void operator1();

    //目标方法2
    public void operator2();
}

被适配者
package AdapterPattern.ObjectAdapter;

/**
 * 被适配者
 */
public class Adaptee {

    //被适配的方法1
    public void operator1(){
        System.out.println("被适配的方法1");
    }
}

适配器
package AdapterPattern.ObjectAdapter;


/**
 * 适配器
 */
public class Adapter implements Target
{
    private Adaptee adaptee;

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

    @Override
    public void operator1() {
        adaptee.operator1();
    }

    @Override
    public void operator2() {
        System.out.println("把被适配的方法映射为目标的方法");
    }
}

测试
package AdapterPattern.ObjectAdapter;


public class Test {
    public static void main(String[] args) {
        Adaptee adaptee = new Adaptee();
        Target target = new Adapter(adaptee);
        target.operator1();
        target.operator2();
    }
}

3. 特点

  • 在实现适配器功能的时候,可以调用自己开发的功能,自然地扩展系统的功能
  • 方便复用现有的类

4. 缺省适配

如果不准备实现一个接口的所有方法时,就可以使用“缺省适配模式”制造一个抽象类,给出所有方法的平庸的具体实现。

package AdapterPattern.DefaultAdapter;

/**
 * 公共接口
 */
public interface Service {

    public void operator1();

    public int operator2();

    public String operator3();
}

package AdapterPattern.DefaultAdapter;

public abstract class DefaultAdapter implements Service{
    @Override
    public void operator1() {

    }

    @Override
    public int operator2() {
        return 0;
    }

    @Override
    public String operator3() {
        return null;
    }
}

三:外观模式

1. 定义

又叫门面模式。提供一个高层次的接口,使得子系统更易于使用,同时依然暴露子系统的完整功能

2. 使用

  • 子系统:多个具体对象
  • 简化外观接口
    • 组合子系统的所有对象
    • 委托所有对象执行对应的方法
子系统
package AppearencePattern;

/**
 * 子系统的A模块
 */
public class ModuleA {
    public void operateA(){
        System.out.println("A模块的方法");
    }
}

package AppearencePattern;

/**
 * 子系统的B模块
 */
public class ModuleB {
    public void operateB(){
        System.out.println("B模块的方法");
    }
}

外观
package AppearencePattern;

/**
 * 子系统的外观
 */
public class Appearence {

    //外观接口
    public void operate(){
        ModuleA a = new ModuleA();
        a.operateA();
        ModuleB b = new ModuleB();
        b.operateB();
    }
}

测试
package AppearencePattern;

public class Test {
    public static void main(String[] args) {
        Appearence appearence = new Appearence();
        appearence.operate();
    }
}

3. 特点

  • 在不影响客户的情况下,改变子系统(只起到协调作用,无法提供新的行为)
  • 有助于隐藏子系统的内部方法
  • 更好的划分访问层次,可以将子系统继续划分为多个子系统

四:组合模式

1. 定义

又叫合成模式、“部分——整体”模式。允许把对象组合成树形结构来表现“整体-部分”层次结构,让客户以一致的方式处理个别对象以及对象组合。

2. 使用

  • 抽象组件接口:管理所有的子对象
    • 具体叶子结点:定义组合内元素的行为(具体业务)
    • 具体树枝结点:定义组件的行为(操作组件)
  • 业务:使用抽象接口操作组合中的对象
(1)安全式组合

要求管理聚集的方法只出现在树枝中,而不出现在树叶中
不够透明,因为树叶类和树枝类将具有不同的接口

  • 抽象组件:管理所有的子对象,定义通用方法
    • 具体叶子结点:定义元素的行为(具体业务)
    • 具体树枝结点:定义管理子对象的行为(操作组件)
  • 业务:使用抽象接口操作组合中的对象
组件
package ComposePattern.SafeCompose;

/**
 * 抽象组件
 */
public interface Component {
    public void printTree(String pre);
}

package ComposePattern.SafeCompose;

/**
 * 具体叶子
 */
public class Leaf implements Component {

    private String name;

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

    @Override
    public void printTree(String pre) {
        System.out.printf("%s%s\n",pre,name);
    }
}

package ComposePattern.SafeCompose;

import java.util.ArrayList;
import java.util.List;

/**
 * 具体组合(树枝)
 */
public class Composite implements Component {

    //维护所有组件
    private List<Component> components;

    private String name;

    public Composite(String name) {
        this.name = name;
        components = new ArrayList<>();
    }

    //自定义方法

    /**
     * 添加组件
     *
     * @param component 组件
     */
    public void addComponent(Component component) {
        components.add(component);
    }

    /**
     * 删除组件
     *
     * @param component 组件
     */
    public void delComponent(Component component) {
        components.remove(component);
    }

    /**
     * 获取所有组件
     *
     * @return 组件集合
     */
    public List<Component> getComponents() {
        return components;
    }

    @Override
    public void printTree(String pre) {
        System.out.printf("%s%s\n", pre, this.name);
        if (getComponents().size() != 0) {
            pre += "\t";
            for (Component com : components) {
                com.printTree(pre);
            }
        }

    }
}

测试
package ComposePattern.SafeCompose;

public class Test {
    public static void main(String[] args) {
        Composite root = new Composite("服装");
        Composite c1 = new Composite("男装");
        Composite c2 = new Composite("女装");

        Leaf leaf1 = new Leaf("衬衫");
        Leaf leaf2 = new Leaf("夹克");
        Leaf leaf3 = new Leaf("裙子");
        Leaf leaf4 = new Leaf("套装");

        root.addComponent(c1);
        root.addComponent(c2);
        c1.addComponent(leaf1);
        c1.addComponent(leaf2);
        c2.addComponent(leaf3);
        c2.addComponent(leaf4);

        root.printTree("");
    }
}

(2)透明式组合

要求所有的具体构件类,不论树枝构件还是树叶构件,均符合一个固定接口
不够安全,有发生误操作的可能

  • 抽象组件:管理所有的子对象,定义所有业务方法
    • 具体叶子结点:定义元素的行为(具体业务)
    • 具体树枝结点:定义管理子对象的行为(操作组件)
  • 业务:使用抽象接口操作组合中的对象
组件
package ComposePattern.TransparentPattern;

import java.util.List;

/**
 * 抽象组件
 */
public abstract class Component {
    public void addComponent(Component component){
        throw new UnsupportedOperationException("对象不支持此功能");
    }
    public void delComponent(Component component){
        throw new UnsupportedOperationException("对象不支持此功能");
    }
    public List<Component> getComponents(){
        throw new UnsupportedOperationException("对象不支持此功能");
    }
    public void printTree(String pre){
        throw new UnsupportedOperationException("对象不支持此功能");
    }
}

package ComposePattern.TransparentPattern;

/**
 * 具体叶子
 */
public class Leaf extends Component {

    private String name;

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

    public void printTree(String pre) {
        System.out.printf("%s%s\n",pre,name);
    }
}

package ComposePattern.TransparentPattern;

import java.util.ArrayList;
import java.util.List;

/**
 * 具体组合(树枝)
 */
public class Composite extends Component {

    //维护所有组件
    private List<Component> components;

    private String name;

    public Composite(String name) {
        this.name = name;
        components = new ArrayList<>();
    }


    public void addComponent(Component component) {
        components.add(component);
    }

    public void delComponent(Component component) {
        components.remove(component);
    }

    public List<Component> getComponents() {
        return components;
    }

    public void printTree(String pre) {
        System.out.printf("%s%s\n", pre, this.name);
        if (getComponents().size() != 0) {
            pre += "\t";
            for (Component com : components) {
                com.printTree(pre);
            }
        }
    }
}

测试
package ComposePattern.TransparentPattern;

public class Test {
    public static void main(String[] args) {
        Component root = new Composite("服装");
        Component c1 = new Composite("男装");
        Component c2 = new Composite("女装");

        Component leaf1 = new Leaf("衬衫");
        Component leaf2 = new Leaf("夹克");
        Component leaf3 = new Leaf("裙子");
        Component leaf4 = new Leaf("套装");

        root.addComponent(c1);
        root.addComponent(c2);
        c1.addComponent(leaf1);
        c1.addComponent(leaf2);
        c2.addComponent(leaf3);
        c2.addComponent(leaf4);

        root.printTree("");
    }
}

3. 特点

对于组合模式而言,在安全性和透明性上,会更看重透明性。让客户端不再区分操作的是树枝对象还是树叶对象,而是以一个统一的方式来操作

五:代理模式

1. 定义

为另一个对象提供一个代理对象,控制对这个对象的访问

2. 分类

  • 远程代理(另一个JVM的对象)
  • 虚拟代理(开销大的对象)
  • 保护代理(不安全的对象)
  • 缓存代理(减小开销)
  • 同步代理(多线程的安全访问)
  • 防火墙代理(保护网络资源)
  • 智能引用代理(引用某个对象时的处理)
  • 复杂隐藏代理
  • 写入时复制代理

3. 使用

  • 抽象对象:声明了目标对象和代理对象的共同接口,定义抽象的业务
  • 真正对象:被代理和被控制访问的对象,实现具体的业务
  • 代理对象:持有真正对象的引用,创建和销毁真正的对象、控制真正的对象
(1)远程代理

代理作为另一个JVM对象的本地代表,利用网络转发请求,在调用远程方法时作为替身

  • 服务器
    • 抽象对象
    • 真正对象
  • RMI代理对象
    • 客户辅助对象stub:打包调用信息,转发请求
    • 服务辅助对象skeleton:解开包,接收请求,调用方法,返回结果
  • 客户端:调用代理对象的方法
服务端:
  1. 定义抽象接口:定义业务方法(继承Remote、变量和返回值使用原语或序列化的类)
  2. 定义真正对象:实现业务方法(继承UnicastRemoteObject、构造器)、注册registry
  3. 产生代理对象:利用RMIC产生stub、skeleton
  4. 启动RMI registry:记录客户代理
  5. 远程服务
客户端:
  1. 获取代理对象stub:通过抽象接口,在服务器的registry寻找具体代理对象,返回stub
  2. 使用代理对象stub
(2)虚拟代理

代理作为创建开销大的对象的代表,在需要使用时才创建真正对象。在创建前和创建中都是由虚拟代理作为替身

  • 抽象对象:抽象的业务
  • 真正对象:实现业务方法
  • 代理对象:如果真正对象创建好了,则委托请求。否则开始新的线程创建真正对象,先提供默认实现
  • 客户端:调用抽象的业务方法
业务
package ProxyPattern;

/**
 * 抽象接口
 */
public interface Subject {
    public void operate();
}

package ProxyPattern;

/**
 * 真正对象
 */
public class RealSubject implements Subject {
    @Override
    public void operate() {
        System.out.println("真正的业务实现");
    }
}

代理
package ProxyPattern;

/**
 * 代理
 */
public class Proxy implements Subject{

    private RealSubject realSubject;

    @Override
    public void operate() {
        if (realSubject == null) {
            new Thread(){
                public void run(){
                    realSubject = new RealSubject();
                    System.out.println("创建完成");
                    realSubject.operate();
                }
            }.start();
            System.out.println("业务的默认实现");
        }
        else
            realSubject.operate();
    }
}

测试
package ProxyPattern;

public class Test {
    public static void main(String[] args) {
        Subject subject = new Proxy();
        System.out.println("首次调用");
        subject.operate();
//        System.out.println("第二次调用");
//        subject.operate();
    }
}

(3)保护代理

使用JAVA的动态代理,根据访问权限,决定用户能否访问对象的代理

  • 抽象对象:抽象的业务
  • 真正对象:实现具体的业务
  • 代理对象:持有真正对象的引用,控制真正的对象
  • 实际代理对象:代理收到方法后,请求实际工作的对象
    • 抽象对象
    • invoke(代理,方法名,参数) :判断方法能否执行
  • 客户端:根据真正对象获取其对应的代理对象
    • 创建代理+类加载器+代理实现接口+实际代理对象
业务
package ProxyPattern.ProtectProxy;

/**
 * 抽象接口
 */
public interface Subject {

    public void operateA();

    public void operateB();
}

package ProxyPattern.ProtectProxy;

/**
 * 真正对象
 */
public class RealSubject implements Subject {

    @Override
    public void operateA() {
        System.out.println("真正的业务实现A");
    }

    @Override
    public void operateB() {
        System.out.println("真正的业务实现B");
    }
}

代理对不同实体对象的具体处理过程
package ProxyPattern.ProtectProxy;

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

/**
 * 真正的代理处理过程
 */
public class MyInvocationHandler implements InvocationHandler {

    private Subject subject;

    public MyInvocationHandler(Subject subject){
        this.subject = subject;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
	    //对于实体RealSubject进行以下限制:
	    //对B结尾的方法进行保护,抛出异常
        //对A结尾的方法正常访问
        try {
            if (method.getName().endsWith("A"))
                return method.invoke(subject,args);
            if (method.getName().endsWith("B"))
                throw new Exception();
        }
        catch (Exception e){
            System.out.println("无法操作B有关的方法");
        }
        return null;
    }
}

测试
package ProxyPattern.ProtectProxy;

public class Test {
    public static void main(String[] args) {
        Subject subject = new RealSubject();
        Subject proxy = getProxy(subject);
        proxy.operateA();
        proxy.operateB();
    }

    //根据业务的类和接口以及自己实现的处理过程,获取代理
    static Subject getProxy(Subject subject){
        return (Subject) java.lang.reflect.Proxy.newProxyInstance(
                subject.getClass().getClassLoader(),
                subject.getClass().getInterfaces(),
                new MyInvocationHandler(subject)
        );
    }
}

六:桥接模式

1. 定义

又称为柄体模式或接口模式,将抽象化与实现化解耦,使得二者可以独立地变化

  • 抽象:从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征,就是抽象化(接口、抽象类)
  • 实现:抽象化给出的具体实现,就是实现化(类的实例、抽象类的子类)
  • 解耦:在一个软件系统的抽象化和实现化之间使用聚合关系而不是继承关系

2. 使用

  • 抽象超类型A:定义高级抽象化,关联上实现超类型B
  • 扩展实现A’:扩展高级抽象,改变和修正抽象化的定义
  • 实现超类型B:定义低级抽象化,实现高级抽象化A的基本方法
  • 具体实现B’:实现低级抽象
抽象超类型
package BridgePattern;

/**
 * 高级抽象
 */
public abstract class Abstraction {

    //关联
    private Implementor implementor;

    public Abstraction(Implementor implementor){
        this.implementor = implementor;
    }

    //抽象方法
    public void operate(){
        implementor.operateImpl();
    }
}

实现超类型
package BridgePattern;

/**
 * 低级抽象
 */
public abstract class Implementor {

    //实现低级的抽象方法
    public abstract void operateImpl();
}

具体实现
package BridgePattern;

/**
 * 实现低级抽象
 */
public class ConcreteImplementor extends Implementor {
    @Override
    public void operateImpl() {
        System.out.println("高级抽象方法的具体实现");
    }
}

扩展抽象
package BridgePattern;

/**
 * 修正高级抽象
 */
public class ConcreteAbstraction extends Abstraction{

    public ConcreteAbstraction(Implementor implementor) {
        super(implementor);
    }

    public void myOperate(){
        System.out.println("高级抽象的扩展方法");
    }
}

测试
package BridgePattern;

public class Test {
    public static void main(String[] args) {
        Implementor implementor = new ConcreteImplementor();
        Abstraction abstraction = new ConcreteAbstraction(implementor);
        abstraction.operate();
        ((ConcreteAbstraction) abstraction).myOperate();
    }
}

3. 特点

  • 业务的变化具有两个维度,一个纬度的变化会引起另一个纬度进行相应的变化
  • 将抽象和实现解耦
  • 增加了复杂度

七:蝇量模式

1. 定义

又叫享元模式。一个类的实例可以提供多个虚拟实例,用同个方法控制。以共享的方式高效地支持大量的细粒度对象。

  • 内蕴状态:不会随环境的改变而改变的,存储在实际对象内部
  • 外蕴状态:随环境的改变而改变的,不可以共享。由客户端保存,在需要使用的时候再传入到实际对象内部

2. 使用

(1)单纯蝇量模式

所有的实际对象都是可以共享的

  • 抽象蝇量:定义蝇量的基本方法
  • 具体蝇量类:实现抽象方法,为内蕴状态提供存储空间
  • 蝇量工厂:创建和管理蝇量。检查系统中是否已经有一个符合要求的对象。如果已经有了就提供;否则,创建一个合适的对象。
  • 客户:通过蝇量工厂获取蝇量并使用
package FlyweightPattern;

/**
 * 抽象蝇量
 */
public interface Flyweight {

    //业务方法
    public void operate(String ExternalState);
}

package FlyweightPattern;

/**
 * 具体蝇量
 */
public class ConcreteFlyweight implements Flyweight {

    //内蕴状态
    private String internalState;

    public ConcreteFlyweight(String state){
        this.internalState = state;
    }

    //业务方法
    @Override
    public void operate(String externalState) {
        System.out.println("外蕴状态:"+externalState);
        System.out.println("内蕴状态:"+internalState);
    }
}

package FlyweightPattern;

import java.util.HashMap;

/**
 * 生成工厂
 */
public class FlyweightFactory {
    HashMap<String,Flyweight> flyweights;

    public FlyweightFactory() {
        this.flyweights = new HashMap<>();
    }

    public Flyweight getFlyweight(String state) {
        Flyweight flyweight = flyweights.get(state);
        if (flyweight == null){
            flyweight = new ConcreteFlyweight(state);
            flyweights.put(state,flyweight);
        }
        return flyweight;
    }
}

package FlyweightPattern;

public class Test {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight a = factory.getFlyweight("A");
        a.operate("X");
        Flyweight b = factory.getFlyweight("B");
        b.operate("XX");
        a = factory.getFlyweight("A");
        a.operate("XXX");
    }
}

(2)复合蝇量模式

将一些单纯蝇量使用合成模式加以复合,形成复合蝇量对象。复合蝇量对象本身不能共享,但是它们可以分解成单纯蝇量对象共享。

  • 抽象蝇量:定义蝇量的基本方法
  • 具体蝇量类:实现抽象方法,为内蕴状态提供存储空间
  • 复合蝇量类:多个本身是单纯蝇量对象的组合
  • 蝇量工厂:创建和管理蝇量。检查系统中是否已经有一个符合要求的对象。如果已经有了就提供;否则,创建一个合适的对象。
  • 客户:通过蝇量工厂获取蝇量并使用
package FlyweightPattern.ComplexFlyweight;

/**
 * 抽象蝇量
 */
public interface Flyweight {

    //业务方法
    public void operate(String ExternalState);
}

package FlyweightPattern.ComplexFlyweight;

/**
 * 具体蝇量
 */
public class ConcreteFlyweight implements Flyweight {

    //内蕴状态
    private String internalState;

    public ConcreteFlyweight(String state){
        this.internalState = state;
    }

    //业务方法
    @Override
    public void operate(String externalState) {
        System.out.println("外蕴状态:"+externalState);
        System.out.println("内蕴状态:"+internalState);
    }
}

package FlyweightPattern.ComplexFlyweight;

import java.util.ArrayList;
import java.util.List;

/**
 * 复合蝇量
 */
public class ComplexFlyweight implements Flyweight{

    private List<Flyweight> flyweights;

    public ComplexFlyweight(){
        flyweights = new ArrayList<>();
    }

    //组合单纯蝇量
    public void add(Flyweight flyweight){
        flyweights.add(flyweight);
    }

    //业务方法
    @Override
    public void operate(String ExternalState) {
        for (Flyweight flyweight:
             flyweights) {
            flyweight.operate(ExternalState);
        }
    }
}

package FlyweightPattern.ComplexFlyweight;

import java.util.HashMap;
import java.util.List;

/**
 * 生成工厂
 */
public class FlyweightFactory {
    HashMap<String, Flyweight> flyweights;

    public FlyweightFactory() {
        this.flyweights = new HashMap<>();
    }

    //获取单纯蝇量
    public Flyweight getFlyweight(String state) {
        Flyweight flyweight = flyweights.get(state);
        if (flyweight == null){
            flyweight = new ConcreteFlyweight(state);
            flyweights.put(state,flyweight);
        }
        return flyweight;
    }

    //获取复合蝇量
    public Flyweight getComplexFlyweight(List<String> states){
        ComplexFlyweight complexFlyweight = new ComplexFlyweight();
        for (String state:
             states) {
            Flyweight flyweight = getFlyweight(state);
            complexFlyweight.add(flyweight);
        }
        return complexFlyweight;
    }
}

package FlyweightPattern.ComplexFlyweight;

import java.util.ArrayList;
import java.util.List;

public class Test {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        List<String> states = new ArrayList<>();
        states.add("A");
        states.add("B");
        states.add("C");
        Flyweight complexFlyweight1 = factory.getComplexFlyweight(states);
        Flyweight complexFlyweight2 = factory.getComplexFlyweight(states);
        System.out.println(complexFlyweight1 == complexFlyweight2);
        Flyweight flyweight1 = factory.getFlyweight(states.get(0));
        Flyweight flyweight2 = factory.getFlyweight(states.get(0));
        System.out.println(flyweight1 == flyweight2);
    }
}

3. 特点

  • 节省内存
  • 集中管理多个虚拟对象
  • 逻辑实例无法拥有独立的行为
  • 将蝇量对象的状态外部化,而读取外部状态使得运行时间稍微变长。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值