Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用什么设计模式或体系结构来覆盖默认的类实例化或创建_Java_Design Patterns - Fatal编程技术网

Java 使用什么设计模式或体系结构来覆盖默认的类实例化或创建

Java 使用什么设计模式或体系结构来覆盖默认的类实例化或创建,java,design-patterns,Java,Design Patterns,我有一个我正在编写的平台,它为开发人员提供了一组默认的模块,我希望通过它可以扩展这些模块,以便在运行时提供更多的自定义功能。以下代码段是默认的模块层次结构: package com.test.core; public abstract class Module { public abstract void performAction(); } package com.test.fun; public class AModule extends Module { @Overri

我有一个我正在编写的平台,它为开发人员提供了一组默认的模块,我希望通过它可以扩展这些模块,以便在运行时提供更多的自定义功能。以下代码段是默认的模块层次结构:

package com.test.core;
public abstract class Module {
    public abstract void performAction();
}

package com.test.fun;
public class AModule extends Module {

    @Override
    public void performAction() {
        // Perform action A
    }
}

package com.test.fun;
public class BModule extends Module {

    @Override
    public void performAction() {
        // Perform action B
    }
}

package com.test.fun;
public class CModule extends Module {

    @Override
    public void performAction() {
        // Perform action C
    }
}
有一个模块引擎,它将在应用程序实例的开头创建模块,并将这些模块存储在HashMap中,其中[key=name;value=module]。由于我的后端和应用程序的性质,我必须使用名称作为键并标识模块

public Module createModule(String name) throws Exception {
    Module module = null;
    Class moduleClass = null;

    // Find class by name, default to using <name>Module as the class name
    // might throw exception
    String className = name = "com.test.fun." + name + "Module";
    moduleClass = Class.forName(className);

    if (moduleClass == null) {
        // quit, nothing to do
    } else {
        // create the module
        module = (QPComponent) moduleClass.getConstructor().newInstance();
    }

    return module;
}
我必须如何修改体系结构,使开发人员能够为密钥“a”注册其自定义模块实现,以便在应用程序启动时,应用程序将获取自定义ExtendedModuleA版本,而不是默认的AModule版本

我的一个想法是,这看起来不太好,如下所示:

public class ModuleRegistry {

    // Assume singleton
    HashMap<String, Class<Module>> registry;

    public ModuleRegistry() {

    }

    private void init() {
        registry = new HashMap<String, Class<Module>>();

        registry.put("A", ExtendedModuleA.class);
        // no extension for B
        registry.put("C", CModuleExtra.class);

        // developers add more entries to "register" more extended modules here for the future
    }



    public Class<Module> getExtendedModuleClass(String name) {
        return registry.get(name);  
    }
}
公共类模块注册表{
//假设单身
HashMap注册表;
公共模块注册表(){
}
私有void init(){
registry=newhashmap();
registry.put(“A”,ExtendedModuleA.class);
//B没有分机
registry.put(“C”,CModuleExtra.class);
//开发人员在此处添加更多条目以“注册”更多扩展模块,以备将来使用
}
公共类getExtendedModuleClass(字符串名称){
返回registry.get(名称);
}
}
有没有设计模式或工具库可以帮助我解决此类问题?我现在只想到这个解决方案,因为我记得像Spring、Dagger或Android的清单之类的东西,你必须注册你的类,以便系统使用或获取它们。 我已经在我的应用程序中使用了Dagger,但是我的模块本身需要ObjectGraphs,所以可能会出现鸡和蛋的第22条军规

您需要检查,这允许您在运行时为类添加动态行为。这更适合于组合而不是继承,比如为类创建包装器。下面是一个开始示例,旨在了解主要思想:

abstract class Beverage {
    protected final BigDecimal price;
    public Beverage(BigDecimal price) {
        this.price = price;
    }
    public BigDecimal getPrice() {
        return this.price;
    }
}

class Coffee extends Beverage {
    public Coffee(BigDecimal price) {
        super(price);
    }
}

class BeverageWithSugar extends Beverage {
    private Beverage beverage;
    private static final BigDecimal sugarPrice = new BigDecimal("0.15");
    public BeverageWithSugar(Beverage beverage) {
        super(sugarPrice);
        this.beverage = beverage;
    }
    @Override
    public BigDecimal getPrice() {
        //here we add the behavior dynamically
        return this.beverage.getPrice().add(sugarPrice);
    }
}

class BeverageWithChocolate extends Beverage {
    private Beverage beverage;
    private static final BigDecimal chocolatePrice = new BigDecimal("1.25");
    public BeverageWithChocolate(Beverage beverage) {
        super(chocolatePrice);
        this.beverage = beverage;
    }
    @Override
    public BigDecimal getPrice() {
        //here we add the behavior dynamically
        return this.beverage.getPrice().add(chocolatePrice);
    }
}

public class BeverageStore {
    public static void main(String[] args) {
        Coffee coffee = new Coffee(new BigDecimal("0.5"));
        //adding chocolate to our coffee
        Beverage coffeeWithChocolate = new BeverageWithChocolate(coffee);
        //adding sugar to our coffee
        Beverage coffeeWithSugar = new BeverageWithSugar(coffee);
        //adding both chocolate and sugar to our coffee
        Beverage greatCoffee = new BeverageWithChocolate(new BeverageWithSugar(coffee));
        System.out.println("Coffee price: " + coffee.getPrice());
        System.out.println("Coffee with chocolate price: " + coffeeWithChocolate.getPrice());
        System.out.println("Coffee with sugar price: " + coffeeWithSugar.getPrice());
        System.out.println("Coffee with chocolate and sugar price: " + greatCoffee.getPrice());
    }
}
印刷品:

Coffee price: 0.5
Coffee with chocolate price: 1.75
Coffee with sugar price: 0.65
Coffee with chocolate and sugar price: 1.90

要检查装饰器模式和其他模式在Java框架中的使用方式,请参阅您可能希望动态加载模块(而不是在init函数中)

您可以在AModule类中提供最后一个方法

public final String getRegistryKey() {
    return "A";
}
并在ModuleRegistry中实现一个register方法(我假设它是一个单例,其他开发人员可以在运行时访问它)。


因此,使用过您的类的用户可以在需要时在运行时注册或删除他们的模块。

您的回答似乎表明开发人员将显式创建对象,然后在代码中注册它,这将起作用。但是,在我的例子中,开发人员不会手动创建对象,而是根据服务器的设置动态创建对象。在您的回答中,对象注册到名称,以便后续使用将使用该对象。在我的场景中,将根据名称创建一个新对象。因此,我需要根据名称而不是相反的方式来确定要创建哪个对象。你有什么建议?
public final String getRegistryKey() {
    return "A";
}
public void register(Module m) {
    // check key exist and throw exception if you need.
    registry.put(m.getRegistryKey(), m.getClass());
}

public void remove(Module m) {
    hashMap.remove(m.getRegistryKey());
}