我正在寻找一个类似于以下问题的优雅设计:
故事可以具有灵活的层次结构。它可能包括几本书,每本书都有章节,每章都有章节,每章都包含文字。或者,它可能只有部分(例如一个简短的故事)。或者它可能只包含有章节的章节。在任何情况下,你都不能混合使用风格(因此你不能根据书籍为故事添加章节,你必须将章节添加到书本身中。)
我已经为这类问题提出了几个设计解决方案,但它们变得混乱。是否有一种干净的方式来表示这一点,以便在参考Story类时,我可以以清晰,系统的方式访问内容?
答案 0 :(得分:2)
良好的OO设计始于考虑用例而不是类层次结构。这是一个常见的错误,往往会产生过于复杂的设计。
首先考虑一下您正在构建的内容,并使用英语散文以问题域的语言描述您正在解决的问题。
如果产品是UI,则考虑制作模型。
然后你就可以开始写出用例并开始考虑对象如何相互作用。
它被称为面向对象的编程,而不是面向类的编程。类是管理/创建/运行系统中所有对象的代码规范。我会考虑对象和他们正在做的事情。类只是一个实现细节。
如果您的目标是对层次结构执行操作,则可能需要考虑使用Composite模式。您可以执行类似Story对象的操作,该对象可以包含Story对象列表。每个Story对象也有它自己的类型(书籍集,书,章,子章,段落,论文),它自己的属性和方法(取决于你的用例)。
答案 1 :(得分:1)
这种棘手的情况,因为像“书籍”,“章节”,“部分”这样的概念可能有一些共同的元素,提出了类层次结构或通用接口实现。
与此同时,作为不同的类/对象,完全不同,因为要求“所以你不能根据书籍添加章节”。
在处理与分层对象的概念时,有几种方法可以将它们转换为代码,每种方法都适合特定情况。
<强> 1。班级构成
每个概念都有一个类或原型,它们可能通过继承或接口相关或不相关。 这些元素有内部集合,可以限制它们的操作, 通过方法。
// this one can be optional, not required,
// replaced by several parent classes,
// or replaced by interfaces
public class LibraryRootClassMaybe {
// members here
}
public class BookText extends LibraryRootClassMaybe {
// members here
} // class BookText
public class BookSection extends LibraryRootClassMaybe {
// element collection should not be public
List BookTexts;
public Book() {
this.BookTexts = new ArrayList();
}
public void addBookTest(BookText Item) {
// validation and casting from object to BookText
}
// members here
} // class BookSection
public class BookChapter extends LibraryRootClassMaybe {
// element collection should not be public
List BookSections;
public Book() {
this.BookSections = new ArrayList();
}
public void addBookTest(BookSection Item) {
// validation and casting from object to BookSection
}
// members here
} // class BookChapter
public class Book extends LibraryRootClassMaybe {
// element collection should not be public
List BookChapters;
public Book() {
this.BookChapters = new ArrayList();
}
public void addBookTest(BookText Item) {
// validation and casting from object to BookText
}
// members here
} // class Book
当没有很多不同的类时,这些方法很好,可能是5。
<强> 2。树设计模式。
当所有元素相等(如果不相似)时,这些适用 通常是相同的类或接口,通常是很多项目。
这些不适用于您的情况,但是, 我不得不提一下,要更好地应用。
通常,使用树/层次集合类。 它可以是通用/模板树集合的子类, 或者基础tre集合的子类, 这个目的是由具有特定成员的子类替换。
public class FileSystemRootClass {
public bool AmISystemRoot() {
// more
}
public bool AmIAFolder() {
// more
}
public bool AmIAFile() {
// more
}
public void addSystemRoot(string FileSystemName) {
// more
}
public void addFolder(string FileSystemName) {
// more
}
public void addFile(string FileSystemName) {
// more
}
// members here
}
第3。混合动力。
这两个是前两个的组合, 当有很多相关物品时使用它, 它更复杂,可能使用或不使用工厂&amp;抽象工厂模式, 其更常见的例子是视觉控制和小部件库。
import java.util.*;
public class WidgetsExample {
public static void main(String[] args) {
TreeSet <Widget> FormControls = new TreeSet<Widget>();
TextBoxWidget TextBox = new TextBoxWidget();
FormControls.add(TextBoxWidget);
ListBoxWidget ListBox = new ListBoxWidget();
FormControls.add(TextBoxWidget);
ButtonWidget Button = new ButtonWidget();
FormControls.add(Button);
} // class WidgetsExample
您可能会注意到我没有使用“工厂模式”&amp; “抽象工厂”, 由于需要更多代码。
祝你好运。
答案 2 :(得分:0)
我会尝试这样的事情:
interface StoryElement<SE extends SubElements>{
List<SE> getContents()
}
class Story<T extends StoryElement>
class Book implements StoryElement<Chapter> ...
class Chapter implements StoryElement<Section> ...
class Section implements StoryElement<Text>
class Text implements StoryElement<Text> {... // ugly hack, don't know of a clean way to end the recursion with Java Generics
现在你可以拥有书籍故事或文字故事。
警告:在尝试复杂的事情时,Java Generics往往会黯然失色。如有疑问,请忘记泛型和演员。
答案 3 :(得分:0)
感谢所有的海报。这是我正在进行中的解决方案:
public abstract class Element
{
public ElementSet getContent() { return content; }
// Overrides of setContent() check to see if the content type is appropriate
// using instanceof.
public void setContent( ElementSet content )
{
this.content = content;
}
private ElementSet content;
}
public abstract class ElementSet
{
protected final void addElement( Element e )
{
elements.add(e);
}
private final List<Element> elements = new ArrayList<Element>();
}
public class BookSet extends ElementSet
{
// Typesafe interface.
public void addBook( Book book ) { super.addElement( book ); }
}
public class ChapterSet extends ElementSet { /* similar to BookSet */ }
public class SectionSet extends ElementSet { /* similar to BookSet */ }
public class Book extends Element
{
@Override
public void setContent( ElementSet content )
{
if ( !(content instanceof ChapterSet) && !(content instanceof SectionSet) )
{
throw new RuntimeException();
}
super.setContent( content );
}
public boolean addChapter( Chapter chapter )
{
ElementSet content = getContent();
if ( content == null )
{
content = new ChapterSet();
setContent( content );
}
else if ( !(content instanceof ChapterSet) )
{
// Structure is wrong.
return false;
}
ChapterSet chapters = (ChapterSet)content;
chapters.addChapter( chapter);
return true;
}
public boolean addSection( Section section )
{
ElementSet content = getContent();
if ( content == null )
{
content = new SectionSet();
super.setContent( content );
}
else if ( !(content instanceof SectionSet) )
{
// Structure is wrong.
return false;
}
SectionSet sections = (SectionSet)content;
sections.addSection( section );
return true;
}
}
public class Chapter extends Element
{
@Override
public void setContent( ElementSet content )
{
if ( !(content instanceof SectionSet) )
{
throw new RuntimeException();
}
super.setContent( content );
}
public boolean addSection( Section section )
{
ElementSet content = getContent();
if ( content == null )
{
content = new SectionSet();
super.setContent( content );
}
else if ( !(content instanceof SectionSet) )
{
// Structure is wrong.
return false;
}
SectionSet sections = (SectionSet)content;
sections.addSection( section );
return true;
}
}
我尝试使用泛型来实现相同目的,但由于需要反映容器的参数化类型,它看起来相当丑陋。