Saya telah menggunakan pola ini berkali-kali di berbagai tempat, biasanya di samping pola plugin.
Beberapa contoh cara saya menggunakannya adalah untuk sistem pesan, seperti membuat pelanggan untuk berbagai jenis pesan yang tidak terkait. Saya juga menggunakannya untuk alur kerja integrasi umum yang masing-masing memerlukan objek konteks dengan bentuk berbeda.
Pada dasarnya polanya terdiri dari pendefinisian antarmuka penanda kosong untuk suatu pesan atau konteks. Kemudian mendefinisikan antarmuka alur kerja tingkat tinggi yang berfungsi dengan antarmuka pesan/konteks. Anda kemudian dapat menggunakan pabrik untuk mendapatkan contoh nyata dari alur kerja, dan jika diperlukan, alur kerja juga dapat bertanggung jawab untuk menguraikan pesan/konteksnya dari format data umum.
Selanjutnya, Anda membuat alur kerja dasar generik abstrak yang tanggung jawabnya hanya memetakan panggilan ke metode antarmuka, yang meneruskan antarmuka penanda yang tidak berguna, menjadi panggilan ke metode abstrak yang mengambil versi nyata dari pesan/konteks.
Semoga itu masuk akal. Saya akan memberikan contoh kode di bawah ini. Saya ingin tahu apakah pola ini mempunyai nama karena saya perhatikan saya sudah menggunakannya sekitar 4-5 kali sekarang. Selain itu, saya baru saja menjelaskan cara menjelaskan polanya, jadi jika penjelasan saya ada yang tidak masuk akal, harap beri tahu saya juga.
Poin utamanya adalah Anda dapat memiliki beberapa kelas dengan tanda tangan metode berbeda yang masih dapat dipanggil melalui antarmuka umum:
Hasil Akhir
public class ConcreteA : Base<MessageA>
{
public void Process(MessageA message){...}
public MessageA Parse(IDictionary data){...}
}
public class ConcreteB : Base<MessageB>
{
public void Process(MessageB message){...}
public MessageB Parse(IDictionary data){...}
}
//And both can by called by...
public void Main(){
var data = GetDataFromIntegrationSource(someContext);
IWorkflow impl = Factory.GetConcrete(someContext);
//So in your classes you're able to work with strongly typed parameters,
//But in the consuming code you still can use a common interface
//Consuming code never even knows what the strong type is.
IMessage msg = impl.Parse(data);
impl.Process(msg);
}
CONTOH LENGKAP
Antarmuka Tingkat Tinggi
public interface IGenericeMarkerInterface
{
}
public interface IGenericWorkflow
{
void Process(IGenericeMarkerInterface messageOrContext);
IGenericeMarkerInterface Parse(IDictionary<string, string> commonDataFormat);
}
Dasar Abstrak untuk Pemetaan ke Metode Beton
public abstract class GenericWorkflowBase<T> : IGenericWorkflow where T : IGenericeMarkerInterface
{
public void Process(IGenericeMarkerInterface messageOrContext)
{
Process((T)messageOrContext);
}
public IGenericeMarkerInterface Parse(IDictionary<string, string> commonDataFormat)
{
return DoParse(commonDataFormat);
}
public abstract void Process(T messageOrContext);
public abstract T DoParse(IDictionary<string, string> commonDataFormat);
}
Memetakan Atribut
public class MappingAttributeUsedByFactoryAttribute : Attribute
{
public WorkflowType SomePropertyForMapping { get; set; }
}
Implementasi Beton
public class SomeRandomlyShapedMessageOrContext : IGenericeMarkerInterface
{
public int ID { get; set; }
public string Data { get; set; }
}
[MappingAttributeUsedByFactory(WorkflowType.IntegrationPartnerB)]
public class ConcreteWorkflow : GenericWorkflowBase<SomeRandomlyShapedMessageOrContext>
{
public override void Process(SomeRandomlyShapedMessageOrContext messageOrContext)
{
//TODO: process the strongly typed message
}
public override SomeRandomlyShapedMessageOrContext DoParse(IDictionary<string, string> commonDataFormat)
{
//TODO: parse the common data into the strongly typed message
}
}
Pabrik
public static class WorkflowFactory
{
public static IGenericWorkflow Get(WorkflowType workflow)
{
//TODO: find the concrete workflow by inspecting attributes
}
}
Contoh Penggunaan
public static class Program
{
public static void Main(string[] args)
{
//this could be driven by a UI or some contextual data
var someSortOfWorkflowIdentifier = (WorkflowType)args[0];
var data = GetSomeDictionaryOfData();
var workflow = WorkflowFactory.Get(someSortOfWorkflowIdentifier);
workflow.Process(workflow.Parse(data));
}
}