Một điều xuất hiện khá nhiều trong công việc hiện tại của tôi là có một quy trình tổng quát cần phải xảy ra, nhưng sau đó phần lẻ của quy trình đó cần xảy ra hơi khác nhau tùy thuộc vào giá trị của một biến nhất định, và tôi thì không khá chắc chắn những gì thanh lịch nhất để xử lý này.
Tôi sẽ sử dụng ví dụ mà chúng ta thường có, đang làm những việc hơi khác nhau tùy thuộc vào quốc gia chúng ta đang làm việc.
Vì vậy, tôi có một lớp học, hãy gọi nó là Processor
:
public class Processor
{
public string Process(string country, string text)
{
text.Capitalise();
text.RemovePunctuation();
text.Replace("é", "e");
var split = text.Split(",");
string.Join("|", split);
}
}
Ngoại trừ việc chỉ một số trong những hành động đó cần phải xảy ra đối với một số quốc gia nhất định. Ví dụ, chỉ có 6 quốc gia yêu cầu bước viết hoa. Ký tự để phân chia có thể thay đổi tùy thuộc vào quốc gia. Thay thế dấu 'e'
chỉ có thể được yêu cầu tùy thuộc vào quốc gia.
Rõ ràng bạn có thể giải quyết nó bằng cách làm một cái gì đó như thế này:
public string Process(string country, string text)
{
if (country == "USA" || country == "GBR")
{
text.Capitalise();
}
if (country == "DEU")
{
text.RemovePunctuation();
}
if (country != "FRA")
{
text.Replace("é", "e");
}
var separator = DetermineSeparator(country);
var split = text.Split(separator);
string.Join("|", split);
}
Nhưng khi bạn giao dịch với tất cả các quốc gia có thể trên thế giới, điều đó sẽ trở nên rất cồng kềnh. Và bất kể, các if
câu lệnh làm cho logic khó đọc hơn (ít nhất, nếu bạn tưởng tượng ra một phương thức phức tạp hơn ví dụ), và độ phức tạp chu kỳ bắt đầu tăng lên khá nhanh.
Vì vậy, hiện tại tôi đang làm một cái gì đó như thế này:
public class Processor
{
CountrySpecificHandlerFactory handlerFactory;
public Processor(CountrySpecificHandlerFactory handlerFactory)
{
this.handlerFactory = handlerFactory;
}
public string Process(string country, string text)
{
var handlers = this.handlerFactory.CreateHandlers(country);
handlers.Capitalier.Capitalise(text);
handlers.PunctuationHandler.RemovePunctuation(text);
handlers.SpecialCharacterHandler.ReplaceSpecialCharacters(text);
var separator = handlers.SeparatorHandler.DetermineSeparator();
var split = text.Split(separator);
string.Join("|", split);
}
}
Xử lý:
public class CountrySpecificHandlerFactory
{
private static IDictionary<string, ICapitaliser> capitaliserDictionary
= new Dictionary<string, ICapitaliser>
{
{ "USA", new Capitaliser() },
{ "GBR", new Capitaliser() },
{ "FRA", new ThingThatDoesNotCapitaliseButImplementsICapitaliser() },
{ "DEU", new ThingThatDoesNotCapitaliseButImplementsICapitaliser() },
};
// Imagine the other dictionaries like this...
public CreateHandlers(string country)
{
return new CountrySpecificHandlers
{
Capitaliser = capitaliserDictionary[country],
PunctuationHanlder = punctuationDictionary[country],
// etc...
};
}
}
public class CountrySpecificHandlers
{
public ICapitaliser Capitaliser { get; private set; }
public IPunctuationHanlder PunctuationHanlder { get; private set; }
public ISpecialCharacterHandler SpecialCharacterHandler { get; private set; }
public ISeparatorHandler SeparatorHandler { get; private set; }
}
Mà tôi cũng không chắc là mình thích. Logic vẫn còn bị che khuất bởi tất cả các sáng tạo của nhà máy và bạn không thể chỉ nhìn vào phương thức ban đầu và xem điều gì sẽ xảy ra khi quá trình "GBR" được thực thi. Bạn cũng có kết thúc việc tạo nhiều lớp (trong ví dụ phức tạp hơn này) theo phong cách GbrPunctuationHandler
, UsaPunctuationHandler
, vv ... mà có nghĩa là bạn phải nhìn vào các lớp học khác nhau để tìm ra tất cả các hành động có thể có thể xảy ra trong quá trình chấm câu sự điều khiển. Rõ ràng tôi không muốn một lớp khổng lồ với một tỷ if
câu lệnh, nhưng cũng có 20 lớp với logic hơi khác nhau cũng cảm thấy lộn xộn.
Về cơ bản, tôi nghĩ rằng tôi đã tham gia vào một loại nút OOP nào đó và hoàn toàn không biết cách tháo gỡ nó. Tôi đã tự hỏi nếu có một mô hình ngoài đó sẽ giúp với loại quy trình này?
if (country == "DEU")
bạn kiểm tra if (config.ShouldRemovePunctuation)
.
country
một chuỗi chứ không phải là một thể hiện của một lớp mô hình hóa các tùy chọn đó?
PreProcess
chức năng, có thể được triển khai khác nhau dựa trên một số quốc gia,DetermineSeparator
có thể có ở đó cho tất cả các quốc gia đó và aPostProcess
. Tất cả chúng đều có thể đượcprotected virtual void
triển khai mặc định và sau đó bạn có thể có cụ thểProcessors
theo từng quốc gia