复制生成实例-Prototype模式

153 阅读2分钟

1、引入

prototype,中文译为原型、雏形,在 百度百科 中的解释为原来的类型或模型。

而在设计模式中的Prototype模式,就和上文中的原型释意所言,能够通过原型的实例来复制生成新的实例。一般来说,在以下情况中可以使用Prototype模式:

  • 要处理的对象繁多,难以将它们整理到同一个类中。
  • 对象生成的过程复杂,难以根据类生成实例。
  • 在想解耦框架和生成的实例时,不想通过指定类名来生成实例,可以先"注册"一个"原型",之后通过复制该"原型"生成实例。

2、示例

2.1、复制功能接口

对能够实现复制功能的类提供了统一接口进行规范

public interface Product extends Cloneable{
    public abstract void use(String s);
    public abstract Product createClone();
}

2.2、接口实现

实现1:

public class MessageBox implements Product {
    private char decoChar;

    public MessageBox(char c) {
        decoChar=c;
    }

    @Override
    public void use(String s) {
        int len=s.length();
        for (int i = 0; i < len+4; i++) {
            System.out.print(decoChar);
        }
        System.out.println();
        System.out.println(decoChar+" "+s+" "+decoChar);
        for (int i = 0; i < len+4; i++) {
            System.out.print(decoChar);
        }
        System.out.println();
    }

    @Override
    public Product createClone() {
        Product p=null;
        try {
            p = (Product) clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}

实现2:

public class UnderlinePen implements Product {
    private char ulChar;

    public UnderlinePen(char c) {
        ulChar=c;
    }

    @Override
    public void use(String s) {
        int len=s.length();
        System.out.println("""+s+""");
        System.out.print(" ");
        for (int i = 0; i < len; i++) {
            System.out.print(ulChar);
        }
        System.out.println();
    }

    @Override
    public Product createClone() {
        Product p=null;
        try {
            p=(Product) clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return p;
    }
}

2.3、注册中心

在注册中心中提供对对象的登记注册功能,注册后即可通过对象名从注册中心复制实例。

public class Manager {
    private HashMap<String,Product> showcase=new HashMap<String,Product>();

    public void register(String name, Product proto) {
        showcase.put(name, proto);
    }

    public Product create(String protoName) {
        Product product = showcase.get(protoName);
        return product.createClone();
    }
}

2.4、测试

编写以下测试类:

public class Main {
    public static void main(String[] args) {
        Manager manager = new Manager();
        //创建实例
        UnderlinePen upen = new UnderlinePen('#');
        MessageBox mbox = new MessageBox('*');
        MessageBox sbox = new MessageBox('/');
        //登记注册
        manager.register("upen", upen);
        manager.register("mbox", mbox);
        manager.register("sbox", sbox);
        //复制生成
        Product product1 = manager.create("upen");
        Product product2 = manager.create("mbox");
        Product product3 = manager.create("sbox");
        //测试
        product1.use("Hello World");
        product2.use("Hello World");
        product3.use("Hello World");
    }
}

运行结果:

image.png

3、tips

  • 我们参照示例中的注册中心提供的登记与复制功能,回看1中对Prototype应用场景的阐述,或许能有更深的理解。
  • 如在广泛使用的spring框架中,便提供了根据名称注入。这样做的好处是当我们要更换组件时,不必修改源代码中原来的类,只需要再创建一个新类实现共同接口,在新类上提供权限功能,再向注册中心注册即可,大大减少了代码修改量,降低耦合性。
@Autowired
@Qualifier("targetName")