这是Java中的一个设计模式问题。
我正在设计一个java .jar文件,作为管理和处理某种形式数据的框架。我希望最终用户能够在一定的约束范围内,以某种方式指定“管道”配置。这些部件是生产者和/或消费者,我知道如何实现它们,但是连接让我感到困惑.下面是一个与我的应用程序类似的无稽之谈。
假设我已经实现了以下元素:
AppleTree =>生产苹果ApplePieMaker =>吃苹果,生产苹果派ApplePress =>吃苹果,生产苹果酒AppleSave =>将苹果、苹果派或苹果苹果酒存储在一个文件中。AppleLoad =>从AppleSave制作的文件中“重组”苹果、苹果派或苹果苹果酒。ApplePieMonitor =>在屏幕上以图形用户界面格式显示苹果派现在,我希望用户能够指定如下内容:
AppleTree | ApplePress | AppleSave cider1.sav (生产苹果,制作苹果酒,保存到文件中)AppleTree | AppleSave apple1.sav (生产苹果,保存到文件中)AppleLoad apple1.sav | ApplePieMaker | ApplePieMonitor (把保存下来的苹果做成馅饼,在图形用户界面上显示结果)(生产苹果,将它们制成馅饼和苹果酒,将苹果、馅饼和苹果酒保存到单独的文件中,派在运行时由用户选择的文件,其他的将预先确定文件,并在一个GUI中显示屏幕上的馅饼)
因此,我对如何构建配置文件有一个粗略的想法:即将事物构造为最多有一个输入和最多一个输出的元素,然后对每个实例化的元素命名它,如果它有一个输入,则指定提供输入的元素的名称。
我不清楚的是,如何在程序运行时耦合程序的元素。可能的方法是拥有许多接口,比如AppleConsumer、ApplePieConsumer等等,这样ApplePieMaker就可以实现AppleConsumer接口(包括AppleConsumer接口)。方法( consumeApple()),AppleTree将实现一个AppleProducer接口,该接口可以在启动时注册消费者,这样,每当AppleTree生产苹果时,它都有其消费者列表并在每个用户上调用consumeApple(),这样做是正确的,而AppleTree不必知道他们对苹果做了什么.
有什么建议吗?这类东西有名字吗?我对设计模式并不是很有经验。
编辑:我的最终用户不知道也不关心Java。他们只需要能够设置一个配置文件(我正在尽量简化,这样我就可以给他们提供一些好的例子)并运行我的程序,它将读取配置文件,构造元素,将它们连接在一起,然后继续运行。所有的元素都在我的控制之下,我不需要支持插件,所以我不需要成为超级通用的。
发布于 2009-02-18 19:32:58
不久前,我遇到了这个问题,在Java中很难清晰地指定,因为我的输入和输出可以是复数的。但是,当您确保有一个输入和输出时(因为一个文件是一种特定的输出,对吗?),您可以尝试使用选中的泛型。
处理步骤实现(我将调用过滤器)有两个检查过的类型参数:输入和输出(例如,假设它们都扩展了一个公共接口,对于您在系统中注入的每一个新类型,您将对该接口进行子类)。
public interface Filter<Input extends Type, Output extends Type> {
public Class<Input> getInputType();
public Class<Output> getOutputType();
public void process(Input in, Output out);
}然后,过滤器链只是一个(兼容)Filter的数组。通过兼容,我打算让每个过滤器的输出与它的跟随器输入相同类型,第一个过滤器有一个与您的总体输入类型匹配的输入,最后一个过滤器具有一个与预期结果类型匹配的输出。这在实践中很容易验证,因为我们使用的是已检查的泛型。
因此,过滤器链是另一个(复合)过滤器。复合过滤器的兼容性应该在构造函数中检查,而复合过滤器的数组应该是最终的。没有准确的方法来用泛型来表示该构造函数的参数的“链接”属性(兼容性),所以您必须使用裸类型,这是有点不干净的。
另一种克服这一限制的方法是修改过滤器的定义,而代价是编写起来更加繁琐:
public interface Filter<Input extends Type, Output extends Type> {
public Class<Input> getInputType();
public Class<Output> getOutputType();
public Output out process(Input in);
}然后,我们必须将复合过滤器定义为过滤对的嵌入,从而定义:
public class CompoundFilter<Input extends Type, Output extends Type>
implements Filter<Input extends Type, Output extends Type> {
private final Filter<Input extends Type, ? extends Type> l;
private final Filter<Input extends Type, ? extends Type> r;
public <Median extends Type> CompoundFilter(
Filter<Input, Median> r,
Filter<Median, Output> l
) {
this.l = l;
this.r = r;
}
@SuppressWarnings("unchecked")
public Output out process(Input in) {
// Compute l(r(in)) = (l o r) (in)
return ((Output<Input,Type>) l).process(r.process(in));
}
}因此,组合过滤器只是一个写作问题:
Filter<A,B> f1 = new FilterImpl<A,B>;;
Filter<B,C> f2 = new FilterImpl<B,C>;
// this is mathematically f2 o f1
Filter<A,C> comp = new CompoundFilter<A,C>(f1,f2);发布于 2009-02-18 23:25:13
我情不自禁,我得为此做点什么。
所以就是这样了。
你已经有了苹果生产商/消费者的想法,所以我会这样做。
创建三个接口并按以下方式实现:
其想法是拥有一种通用产品,由非专利生产者生产,并由普通消费者消费。
一旦有了它,您就可以按照描述它的方式创建配置文件,并解析它来为每个元素创建一个新的实例。
element1 | element2 | element3 <parameters> | element 4在映射中,创建元素名并将其映射到将创建新实例的类。
比方说
map.put( "AppleTree", YouAppleTreeClass.class );因此,每次在配置中读取元素时,都会创建实例:
for( String item: line ) {
Object o = map.get( item ).newInstance();
}最后,您必须验证配置的结构,但基本上可以如下所示:
一旦创建并链接了所有对象,就会开始生成。
有些东西你必须锻炼,但它们很容易:
最后注意:下面的代码,只是一个划痕,您可能真的会考虑使用依赖注入器来完成这项工作,但是当然需要花一些时间来学习它。
配置解析应该手工完成,因为您所使用的格式对于最终用户来说是唯一的,并且应该非常简单。尽管如此,您仍然可以在jar中交付您想要的复杂程度(使用您需要的任意数量的框架)。
您还可以查看以下设计模式:
下面的实现是一种怪物--这三个(我没有编译它,只是抛出一些代码来展示这个想法是什么样子的)
我希望这能帮到你。
/**
* Anything. An apple, cider, pie, whatever.
*/
interface Product{}
// The kinds of products.
class Apple implements Product{}
class ApplePies implements Product{}
class AppleCider implements Product{}
/**
* This indicates the class will do something.
**/
interface Producer {
// adds a consumer to the list.
public void addConsumer( Consumer c );
// removes the consumer from the list.
public void removeConsumer( Consumer c );
// let know eveytone a product has been created.
public void notifyProductCreation( Product someProduct );
// You're producer? Produce then...
public void startProduction();
}
// To avoid copy/paste all around
class AbstractProducer implements Producer {
private List<Consumer> consumers = new ArrayList<Consumer>();
// adds a consumer to the list.
public void addConsumer( Consumer c ) {
consumers.add( c );
}
// removes the consumer from the list.
public void removeConsumer( Consumer c ) {
consumers.remove( c );
}
public void notifyProductCreation( Product someProduct ) {
for( Consumer c : list ) {
c.productCreated( someProduct );
}
}
}
interface Consumer {
// Callback to know a product was created
public void productCreated( Product p );
}
class AppleTree extends AbstractProducer {
public void startProduction() {
// do something with earh, sun, water..
// and from time to time:
Product ofThisNewApple = new Apple();
notifyProductCreation( ofThisNewApple );
}
}
class ApplePieMaker extends AbstractProducer implements Consumer {
// Ok, a product was created, but
// is it the product I care?
// check first and consume after.
public void productCreated( Product p ){
// Is this the kind of product I can handle..
// well do handle
if( p instanceof Apple ) {
/// start producing pies..
}
}
public void startProduction() {
// collect the needed number of apples and then...
Product ofPie = new ApplePie();
notifyProductCreation( ofPie );
}
}
class ApplePress extends AbstractProducer implements Consumer {
// Yeap, something gots produced.
// Just handle if it is an apple
public void productCreated( Product p ) {
if( p instanceof Apple ) {
// start producing cider
}
}
public void startProduction() {
// collect the needed number of apples and then...
Product ofCiderBottle = new AppleCider();
notifyProductCreation( ofCiderBottle );
}
}
class AppleSave implements Consumer {
public void productCreated( Product p ) {
file.append( p );// any one will do.
}
}
class AppleLoad extends AbstractProducer {
public void startProduction() {
readFromFile();
}
private readFromFile() {
for( Product p : file ) {
notifyProductCreation( p );
}
}
}
class Main {
public static void main( String [] args ) {
Configuration conf = new Configuration();
List<Producer> producers conf.read();
for( Producer p : producers ) {
// fasten your seat belts....
p.startProduction();
}
}
}
/// Ahhh, pretty ugly code below this line.
// the idea is:
// Read the configuration file
// for each line split in the "|"
// for each element create a new instance
// and chain it with the next.
// producer | consumer | etc...
// Becomes....
// new Producer().addConsumer( new Consumer() );
// Return the list of create producers.
class Configuration {
List<Producer> producers
// read the file
// create the instances
// let them run.
public List<Producer> read() {
File file = new File(....
// The format is:
// producer | consumer-producer <params> | consumer
String line = uniqueLineFrom( file );
String [] parts = line.split("|");
if( parts.length == 1 ) {
System.err.println("Invalid configuration. use element | element | etc. Only one element was....");
System.exit( 1 );
}
int length = parts.length;
for( int i = 0 ; i < parts.length ; i++ ) {
Object theInstance = implementationMap.get( parts[i] ).newInstance();
validatePosition( i, length, theInstance , parts[i] );
}
List<Producer> producers = new ArrayList<Producer>();
for( int i = 0 ; i < parts.length ; i++ ) {
Object theInstance = getInstance( parts[i] );
if( not( isLast( i, length ) && isProducer( theInstance ) ) {
// the next is its consumer
Producer producer = ( Producer ) theInstance;
producer.addConsumer( ( Consumer ) getInstance( parts[i+1] ));
producers.add( producer );
}
}
return producers;
}
// creates a new instance from the implementation map.
private Object getInstance( String key ) {
return implementationMap.get( part[i] ).newInstance();
}
// validates if an element at the given position is valid or not.
// if not, prints the message and exit.
// the first element most be a producer
// the last one a consumer
// all the middle elements producer-consumer
//
private void validatePosition( int i, int length, Object theInstance, String element ) {
if( isFirst( i ) && not(isProducer(( theInstance ) ))) {
System.err.println( "Invalid configuration: " + element + " most be a producer ( either Ap...");
System.exit( 2 );
} else if ( isLast( i, length ) && not( isConsumer( theInstance ))) {
System.err.println( "Invalid configuration: " + element + " most be a consumer ( either Ap...");
System.exit( 3 );
} else if ( isMiddleAndInvalid( i, length , instance ) ) {
System.err.println( "Invalid configuration: " + element + " most be a producer-consumer ( either Ap...");
System.exit( 4 );
}
}
private static Map<String,Class> implementationMap = new HashMap<String,Class>() static {
implementationMap.put( "AppleTree", AppleTree.class );
implementationMap.put( "ApplePieMaker ", ApplePieMaker .class );
implementationMap.put( "ApplePress", ApplePress.class );
implementationMap.put( "AppleSave", AppleSave.class );
implementationMap.put( "AppleLoad", AppleLoad.class );
implementationMap.put( "ApplePieMonitor", ApplePieMonitor.class );
};
// Utility methods to read better ( hopefully ) the statements
// If you could read the validations above you may ignore these functions.
private boolean not( boolean value ) {
return !value;
}
private boolean isFirst( int i ) {
return i == 0;
}
private boolean isLast( int i, int l ) {
return i == l -1 ;
}
private boolean isProducer( Object o ) {
return o instanceof Producer;
}
private boolean isConsumer( Object o ) {
return o instanceof Consumer;
}
private boolean isMiddleAndInvalid( int index, int length, Object instance ) {
return not( isFirst( index ) ) && not( isLast( index, length ) ) && not( isProducer( instance ) && isConsumer( instance ));
}
}发布于 2009-02-18 19:15:51
我相信您想要做的事情可以在Spring框架内完成。它使用依赖注入来表示“为了创建X,我需要Y,所以找到产生Y的东西,看看您需要什么来创建它”。
我可能错了,但我建议你看看。
https://stackoverflow.com/questions/562404
复制相似问题