2016-12-14 12 views
1

Я хочу создать систему, которая позволяет пользователю выбирать из списка типов файлов, чтобы сохранить файл как. У меня есть класс с именем Word и интерфейс с именем SaveFileType. Каждый тип файла реализует SaveFileType, который имеет метод saveFile(). Идея заключается в том, что когда «программист» хочет добавить новый тип файла, ни один из кода в приложении не должен быть изменен.Как получить список всех реализованных классов в шаблоне стратегии?

Это диаграмма UML я сделал: UML Diagram

Проблема, с которой я столкнулся класс Слово не имеет список всех доступных типов файлов, что мне нужно, чтобы отобразить пользователю.

Некоторые примеры кода ниже:

класс Слово:

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(); 
    } 
} 
+0

@fabian спасибо, что ответили на мой вопрос. Там немного суровое, я совершенно новый для всего этого. Я изменил UML в соответствии с вашими отзывами. Является ли «FileType» лучшим именем? Если нет, у вас есть предложение? – Cake

+0

Является ли это вопросом UML или реализацией, так как я вижу ответы только на реализацию? –

ответ

0

Было бы плохо, еслиКласс 210 знал обо всех типах. Это работа другого класса, даже если слово использует его. Одним из решений было бы иметь новый класс, который отображает расширение строки в стратегию. И можно перечислить те стратегии:

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 (не приводится здесь), чтобы получить правильный один. Я думаю, что это возможно.

+0

@cake Была ли эта помощь вам? Пожалуйста, поддержите или примите полезные предложения. – weston

0

Стратегия предназначена для изменения реализации во время выполнения, вы не можете получить все реализации. Это будет задача другого класса. Также вам нужен метод setStrategy(Strategy) в вашем классе Word, поэтому вы выбрали шаблон правильно?

Для получения всех реализаций вы можете использовать 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() ; 
     } 

    } 

Я думаю, что вы знаете, как получить все экземпляры перечислений (доступные стратегии).

Обратите внимание, что коды не были скомпилированы и протестированы, просто для демонстрации идеи. Обработки исключений были проигнорированы.

+0

спасибо, что нашли время, чтобы ответить. Это похоже на самое элегантное решение, размещенное здесь. Однако я должен иметь возможность добавлять дополнительные типы файлов без изменения какого-либо кода в системе. Может быть, стратегия не является решением? – Cake

+0

Почему «без изменения каких-либо кодов»? вы все равно должны перекомпилировать. – Kent

0

Если вы хотите иметь возможность добавлять тип документа без изменения какого-либо кода, это означает, что список типов документов должен быть определен вне вашего кода, в файле, таком как файл свойств, и ваш код должен прочитать файл свойств знать все доступные типы.

Затем вам нужно добавить в этот файл свойств класс, в котором реализуется способ сохранения определенного типа документа, и вы реализуете фабрику, которая создает экземпляр класса с его именем, и класс, который связывает правильный экземпляр в соответствии с выбранным типом.

Для файлов свойств, вы можете иметь записи, как:

ext_1 = .doc

ext_2 = .xml

ext_3 = .rtf

class_1 = Word97

class_2 = WordXML

класс_3 = RTF ...

Такой файл легко анализировать, чтобы узнать список типов и какой класс должен использоваться для сохранения документа. Чтобы узнать, как создать экземпляр класса из его имени, см. Класс Class и метод newInstance.

Это «старый способ», возможно, с инъекцией есть самое современное решение.

В вашей модели UML я бы добавил класс, который читает файл свойств, класс, который создает экземпляр класса из его имени, и класс, который связывает правильный экземпляр с Word. Чтобы смоделировать файл свойств, возможно, экземпляр objet может использоваться, поскольку файл свойств является экземпляром ResourceBundle.