【问题标题】:How to get a list of all implemented classes in Strategy Pattern?如何获取策略模式中所有已实现类的列表?
【发布时间】:2016-12-14 13:50:07
【问题描述】:

我想设计一个系统,允许用户从文件类型列表中选择将文件另存为。我有一个名为 Word 的类和一个名为 SaveFileType 的接口。每个文件类型都实现了具有 saveFile() 方法的 SaveFileType。这个想法是,当“程序员”想要添加新的文件类型时,应用程序中的任何代码都不必更改。

这是我制作的UML图:

我面临的问题是 Word 类没有我需要向用户显示的所有可用文件类型的列表。

下面的一些示例代码:

词类:

public class Word {
    SaveFileAs saveFileAs;
    Document currentDocument;

    public Word(Document currentDocument) {
        this.currentDocument = currentDocument;
    }

    public void saveFile() {
        // Print all available filetypes
        // No actual file-saving logic is needed.
    }
}

Word97 类:

public class Word97 implements  SaveFileAs {
    @Override
    public void saveFile(Document currentDocument) {
        // Do some Java wizardry here.
        System.out.println("Document named '" + currentDocument.getTitle() + "' has been saved as filetype 'Word97' " );
    }
}

主类:

public class Main {
    public static void main(String[] args) {
        Document notes = new Document("Notes", "This is a note.");
        Word wordProgram = new Word(notes);

        // saveFile should print out a list of all possible filetypes.
        wordProgram.saveFile();
    }
}

【问题讨论】:

  • @fabian 感谢您回答我的问题。那里有点苛刻,我对这一切都很陌生。我已根据您的反馈更改了 UML。 'FileType' 是一个更好的名字吗?如果没有,您有什么建议吗?
  • 这是一个 UML 还是一个实现问题,因为我只看到实现答案?

标签: java uml strategy-pattern


【解决方案1】:

策略是在运行时改变实现,你不可能得到所有的实现。这将是另一个班级的任务。您还需要在Word 类中以某种方式使用setStrategy(Strategy) 之类的方法,这就是您选择该模式的原因吗?

要获取所有实现,您可以使用ServiceLoader。我会在图片中添加一个枚举。

所以示例代码如下所示:

Word 类中的方法:

void setSaveFileStrategy(AvailableStrategy strategy){
    this.saveFileAs = strategy.strategy();
}

枚举:

enum AvailableStrategy{
        Word97( Word97.class),
        //.... once new strategy was introduced, you need add an entry here.
        WordXml( WordXml.class);

        private Class<saveFileAs> strategyClass;

        AvailableStrategies(Class<saveFileAs> strategyClass) {
            this.strategyClass = strategyClass;
        }

        saveFileAs strategy() throws IllegalAccessException, InstantiationException {
           return strategyClass.newInstance() ;
        }

    }

我想你知道如何获取所有枚举实例(可用策略)。

请注意,代码没有经过编译和测试,只是为了展示想法。异常处理被忽略了。

【讨论】:

  • 感谢您抽出宝贵时间回复。这似乎是此处发布的最优雅的解决方案。但是,我必须能够在不更改系统中任何代码的情况下添加其他文件类型。也许策略模式不是这里的解决方案?
  • 为什么“不更改任何代码”?无论如何你必须重新编译。
【解决方案2】:

如果Word 类知道所有类型,那就太糟糕了。这是另一个班级的工作,即使 word 使用它。一种解决方案是创建一个将字符串扩展映射到策略的新类。并且可以列举这些策略:

public final class DocumentTypeMap implements Iterable<SaveFileAs> {
    private final Map<String, SaveFileAs> docTypes = new HashMap<>;

    public void register(String extension, SaveFileAs saveFileAs) {
        docTypes.put(extension, saveFileAs);
    }

    public Iterator<SaveFileAs> iterator() {
        return docTypes.values().iterator();
    }
}

用法:

DocumentTypeMap map = new DocumentTypeMap();
map.register(".doc", new Word97()); //etc.
Word word = new Word(map); //inject the dependency of a pre-configured map into the word class.

那么当Word类在保存过程中需要正确的策略时,可以使用DocumentTypeMap上的方法(这里没有提供)来获取正确的策略。我认为这可能是扩展。

【讨论】:

  • @cake 这对您有帮助吗?请点赞或接受有用的建议。
【解决方案3】:

如果您希望能够在不更改任何代码的情况下添加文档类型,这意味着必须在代码之外定义文档类型列表,在文件中定义为属性文件,并且您的代码必须读取属性文件以知道所有可用的类型。

然后您需要在此属性文件中添加哪个类实现如何保存特定文档类型,并实现一个工厂,该工厂实例化一个给定名称的类,以及一个根据所选类型关联正确实例的类。

对于属性文件,您可以有如下条目:

ext_1=.doc

ext_2=.xml

ext_3=.rtf

class_1=Word97

class_2=WordXML

class_3=RTF ...

这样的文件很容易解析以了解类型列表以及必须使用哪个类来保存文档。 要了解如何根据其名称实例化一个类,请参阅类 Class 和方法 newInstance

这是一种“老办法”,也许注入是最新的解决方案。

在您的 UML 模型中,我将添加读取属性文件的类、根据名称实例化类的类以及将正确实例关联到 Word 的类。为了对属性文件建模,也许可以使用实例对象,因为属性文件是 ResourceBundle 的一个实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-07-25
    • 1970-01-01
    • 1970-01-01
    • 2017-07-29
    • 1970-01-01
    • 2019-02-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多