根据单例设计模式使用服务加载器创建可扩展应用程序 [英] Creating Extensible Applications using service-loaders according to a singleton design pattern

查看:84
本文介绍了根据单例设计模式使用服务加载器创建可扩展应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 IntelliJ IDEA 上的项目,并且想在Java应用程序中为可扩展应用程序添加支持。

I'm working on project on IntelliJ IDEA and I want to add support to Extensible Applications in my java application.

方法是,在这个jar文件中创建一个jar文件,应该在该目录中有一个META-INF / services目录,我需要添加一个文件名,该文件名应与全名相同。提供服务的接口的标准名称,并且在该文件中,它应该具有该接口的实现的标准名称。

The way to do it is, creating a jar file in this jar file there should be a META-INF/services directory, inside this directory, I need to add a file whose name contains the same name as the fully-qualified name of the interface which provides the service, and in that file it should have the fully-qualified name of the implementations of that interface.

这是加密和解密在我的项目中服务。

This is the encrypt and decrypt service in my project .

这两个是我程序中提供服务的文件。

These two are the files in my program which provides the service.

这是声明服务方法的接口。

This is the interface which declares the service methods.

package serviceLoader;

public interface Cipher {

     byte[] encrypt(byte[] source, byte[] key);
     byte[] decrypt(byte[] source, byte[] key);
     int strength();

}

这是这些服务的实现类。

This is the implementation class for those services.

package serviceLoader.impl;

import serviceLoader.Cipher;

public class CaesarCipher implements Cipher {

  public byte[] encrypt(byte[] source, byte[] key)   {

    var result = new byte[source.length];
    for (int i = 0; i < source.length; i++)
      result[i] = (byte)(source[i] + key[0]);
    return result;

  }

  public byte[] decrypt(byte[] source, byte[] key)   {

    return encrypt(source, new byte[] { (byte) -key[0] });

  }

  public int strength() {

    return 1;

  }

}

我想知道如何根据单例设计模式创建该程序,我是否需要任何其他Java文件来实现单例设计模式?

I want to know how to create this program according to a singleton-design pattern, and do I need any additional java files to to achieve singleton-design pattern?

推荐答案

您需要一个用于定位,加载和实例化服务提供商(Cipher的特定实现)并捕获它们的类。

You need a class that locates, loads and instantiates service providers (specific implementations of Cipher) and catch them.

有一些实现单例的方法。最常见的方法之一是基于保持构造函数私有并导出公共静态成员以提供对唯一实例的访问。此公共静态成员可以是静态字段或静态方法工厂(在我们的示例代码中为 getInstance()):

There are some approach to implementing singletons. One of the most common way is based on keeping the constructor private and exporting a public static member to provide access to the sole instance. This public static member can be a static field or a static method factory (getInstance() in our sample code):

import serviceLoader.Cipher;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;

public final class CipherManager {
  private final static ArrayList<Cipher> ciphers = new ArrayList<>();
  private final static CipherManager INSTANCE = new CipherManager();

  private CipherManager() {
    load();
  }

  private static void load() {
    ServiceLoader<Cipher> cipherLoader = ServiceLoader.load(Cipher.class);
    Iterator<Cipher> ciphersIterator = cipherLoader.iterator();
    List<Cipher> cipherProviders = new ArrayList<>();
    ciphersIterator.forEachRemaining(cipherProviders::add);
    updateCiphers(cipherProviders);
  }

  static synchronized void updateCiphers(List<Cipher> cipherProviders) {
    ciphers.clear();
    ciphers.addAll(cipherProviders);
  }

  public static CipherManager getInstance() {
    return INSTANCE;
  }

  public void reload() {
    load();
  }

  public Cipher getCipher() {
    if (!ciphers.isEmpty()) {
      return ciphers.get(0);
    }
    return null;
  }
}

getCipher()方法应根据需要实现。也许您想通过类名或服务的任何唯一属性(例如提供商ID,名称等)来获得特权。考虑到这些,我更喜欢使用HashMap来捕获服务提供者(而不是ArrayList)。

The getCipher() method should be implemented as you need. Maybe you want to get a privoder by the class name or any unique property of your service (e.g. provider id, name, etc). With these in mind, I prefer to use a HashMap in order to catch the service providers (instead of ArrayList).

private final static HashMap<String, Cipher> ciphers = new HashMap<>();

实现单例的另一种方法是声明一个单元素枚举:

Another way to implement a singleton is to declare a single-element enum:

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.ServiceLoader;

public enum CipherManager {
  INSTANCE;

  private final static HashMap<String, Cipher> ciphers = new HashMap<>();

  static {
    load();
  }

  public static CipherManager getInstance() {
    return INSTANCE;
  }

  public void reload() {
    load();
  }

  private static void load() {
    ServiceLoader<Cipher> cipherLoader = ServiceLoader.load(Cipher.class);
    Iterator<Cipher> ciphersIterator = cipherLoader.iterator();
    HashMap<String, Cipher> cipherProviders = new HashMap<>();
    ciphersIterator.forEachRemaining(cipher -> cipherProviders.put(cipher.getClass().getName(), cipher));
    updateCiphers(cipherProviders);
  }

  static synchronized void updateCiphers(Map<String, Cipher> cipherProviders) {
    ciphers.clear();
    ciphers.putAll(cipherProviders);
  }

  public Cipher getCipher(String className) {
    return ciphers.get(className);
  }
}

在这种方法中, getInstance ()方法被添加来表示CipherManager遵循单例模式。因此,可以从代码中删除 getInstance()方法,我们可以直接使用 INSTANCE 字段。

In this approach, getInstance() method is added to denote the CipherManager follows singleton pattern. So, getInstance() method can be removed from the code and we can use the INSTANCE field directly .

这篇关于根据单例设计模式使用服务加载器创建可扩展应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆