F uygulama mimarisi/kompozisyon#
KATI C yapıyorum# bir noktada fark ettim de son zamanlarda oldukça aşırı bir düzeye aslında çok fazla bir şey günümüzde işlevleri beste daha yapıyorum. Ve sonra geçenlerde aramaya başladım F# yine düşündüm, o olurdu muhtemelen çok daha uygun bir seçim dili için çok an yapıyorum, çok isterim denemek ve bir bağlantı noktası gerçek dünya C# projesi, F# gibi bir kanıt kavramı. Sanırım elimden çekip gerçek kod (bir çok un-deyimsel moda), ama ben hayal bile edemiyorum ne bir mimari gibi görünecektir. bana işlerinde benzer esnek moda olarak C#.
Bu ne demek, küçük sınıflar, bir sürü ve bir IoC konteyner kullanıyorum oluşturan arayüzleri var ve ben de Dekoratör ve Kompozit gibi desenler çok kullanırım. Bu bana kolayca veya uygulama herhangi bir noktada işlevselliğini değiştirmek genişletmek için izin veren (bence) çok esnek ve evolvable genel bir mimarisi olur. Gerekli değişim şekline bağlı olarak, tek bir arayüz yeni bir uygulama yazmak, IoC kayıt olarak değiştirin ve yapılması gerekebilir. Eğer değişim daha büyük değilse bile, uygulamanın geri kalanı daha önce yaptığı gibi sadece duruyor iken nesne grafiği parçaları değiştirmek istiyorum.
Şimdi F# yok sınıflar ve arayüzler (biliyorum, ancak sanırım ama konumuz o değil ne zaman yapmak istiyorum gerçek fonksiyonel programlama) yok yapıcı enjeksiyon, ve ben yok IoC kaplar. Dekoratör desen yüksek mertebeden fonksiyonlar kullanmak gibi bir şey yapabileceğimi biliyorum, ama bu beni yeterince esneklik ve yapıcı enjeksiyon ile sınıflar olarak idame aynı tür vermek için görünmüyor.
Bu düşünün C# türleri:
public class Dings
{
public string Lol { get; set; }
public string Rofl { get; set; }
}
public interface IGetStuff
{
IEnumerable<Dings> For(Guid id);
}
public class AsdFilteringGetStuff : IGetStuff
{
private readonly IGetStuff _innerGetStuff;
public AsdFilteringGetStuff(IGetStuff innerGetStuff)
{
this._innerGetStuff = innerGetStuff;
}
public IEnumerable<Dings> For(Guid id)
{
return this._innerGetStuff.For(id).Where(d => d.Lol == "asd");
}
}
public class GeneratingGetStuff : IGetStuff
{
public IEnumerable<Dings> For(Guid id)
{
IEnumerable<Dings> dingse;
// somehow knows how to create correct dingse for the ID
return dingse;
}
}
Benim IoC arayüzü ile kendi bağımlılık IGetStuff
GeneratingGetStuff
AsdFilteringGetStuff
gidermek için konteyner söyleyeyim. Şimdi farklı bir filtre ihtiyacım var, yoksa filtreyi Kaldır tamamen, IGetStuff
ilgili uygulanması gereken ve sadece IoC kayıt değiştirin. Arayüzü aynı kaldığı sürece, dokunmam gerek yokiçindeuygulama. OCP ve LSP, DİP tarafından etkin.
Şimdi ben F ne yapıyorsun#?
type Dings (lol, rofl) =
member x.Lol = lol
member x.Rofl = rofl
let GenerateDingse id =
// create list
let AsdFilteredDingse id =
GenerateDingse id |> List.filter (fun x -> x.Lol = "asd")
Bu ne kadar seviyorum, ama esneklik kaybettim. Evet, ben çağrı AsdFilteredDingse
GenerateDingse
aynı yer, çünkü bu tür aynı ama nasıl karar veren bir çağrı olmadan sabit kodlama görüşme sitesi? Bu iki işlevi değiştirilebilir olsa da, artık bu işlevini değiştirmeden AsdFilteredDingse
içinde jeneratör işlevi de yerine geçemez. Bu hiç hoş değil.
Bir sonraki girişimi:
let GenerateDingse id =
// create list
let AsdFilteredDingse (generator : System.Guid -> Dings list) id =
generator id |> List.filter (fun x -> x.Lol = "asd")
Şimdi composability yüksek dereceden bir fonksiyon AsdFilteredDingse yaparak var, ama iki işlevi değiştirilebilir değildir artık. Düşündüm de, onlar zaten olmamalı.
Başka ne yapabilirdim ki? Bu taklit edebilirim "kompozisyon kök" kavramı benim C# F son dosya SAĞLAM# proje. Çoğu dosya sadece koleksiyonları fonksiyonları, o zaman ben bir çeşit "kayıt defteri" hangi değiştirir IoC konteyner, ve nihayet orada bir fonksiyon I aramak için aslında uygulama Çalıştır ve kullanan işlevleri "kayıt defteri". ""Yazın bir fonksiyon ihtiyacım var biliyorum (Guıd ->kayıt defterinde Söylerim Dings listesi), GetDingseForId
Ara. Bu dediğim, asla tek işlevleri daha önce tanımlanmış.
Dekoratör için, tanımı olur
let GetDingseForId id = AsdFilteredDingse GenerateDingse
Filtreyi kaldırmak için, bunu değiştirmek istiyorum
let GetDingseForId id = GenerateDingse
Olumsuz(?) bu diğer fonksiyonlar kullanan tüm işlevleri makul yüksek mertebeden fonksiyonlar olması ve benim "" göster . olurdu defteri ^strong>tümgerçek işlevleri, önceden belirlenmiş herhangi bir fonksiyon daha sonra tanımlanan arayamaz çünkü kullandığım fonksiyonları, özellikle bu"". kayıt değil Ayrıca "kayıt" eşleştirmeleri. döngüsel bağımlılık sorunları ile aday olabileceğini
Bu mantıklı mı? Gerçekten nasıl bir F oluşturursun# ve (bahsetmiyorum bile test edilebilir) sürdürülebilir evolvable? olmak için uygulama
CEVAP
Bu Nesne Yönelimli çok yakından Enjeksiyon karşılık İşlevsel Yapıcı olduğunu fark basittirKısmi Fonksiyon Uygulama.
İlk olarak, bir kayıt türü olarak Dings
yazmak istiyorum:
type Dings = { Lol : string; Rofl : string }
F# IGetStuff
arabirim imza ile tek bir işlev için azaltılabilir
Guid -> seq<Dings>
Biristemcibu fonksiyonu kullanarak bir parametre olarak kabul eder:
let Client getStuff =
getStuff(Guid("055E7FF1-2919-4246-876E-1DA71980BE9C")) |> Seq.toList
Client
işlevin imzası
(Guid -> #seq<'b>) -> 'b list
Gördüğünüz gibi, hedef imza bir fonksiyonu olarak girdi alır ve bir liste verir.
Jeneratör
Jeneratör işlevi yazmak kolay
let GenerateDingse id =
seq {
yield { Lol = "Ha!"; Rofl = "Ha ha ha!" }
yield { Lol = "Ho!"; Rofl = "Ho ho ho!" }
yield { Lol = "asd"; Rofl = "ASD" } }
GenerateDingse
işlevi bu imza vardır:
'a -> seq<Dings>
Bu aslındadaha fazlaGuid -> seq<Dings>
ama bu bir sorun değil daha genel. Eğer sadece GenerateDingse
ile Client
oluşturmak istiyorsanız sadece bu gibi kullanabilirsiniz:
let result = Client GenerateDingse
GenerateDingse
50 *tüm üç değer döndürür.
Dekoratör
Orijinal Dekoratör biraz daha zor, ama çok değil. Yapıcı bir argüman olarak (iç) Dekore edilmiş bu tür eklemek yerine, genel olarak, sadece bir işlev için bir parametre değeri olarak ekleyin:
let AdsFilteredDingse id s = s |> Seq.filter (fun d -> d.Lol = "asd")
Bu işlev, bu imza vardır:
'a -> seq<Dings> -> seq<Dings>
Bizim istediğimiz bu değildi, ama kolay GenerateDingse
ile oluşturmak için:
let composed id = GenerateDingse id |> AdsFilteredDingse id
composed
işlev imzası vardır
'a -> seq<Dings>
Sadece biz arıyoruz!
Şimdi böyle composed
58 *kullanabilirsiniz:
let result = Client composed
sadece [{Lol = "asd"; Rofl = "ASD";}]
dönecektir.
Değilsinvarcomposed
işlev yapmak için; ayrıca bu noktada oluşturabilirsiniz:
let result = Client (fun id -> GenerateDingse id |> AdsFilteredDingse id)
Bu da [{Lol = "asd"; Rofl = "ASD";}]
döndürür.
Alternatif Dekoratör
Önceki örnekte iyi çalışıyor, ama değilgerçektenBenzer bir işlev süsleyin. İşte bir alternatif:
let AdsFilteredDingse id f = f id |> Seq.filter (fun d -> d.Lol = "asd")
Bu işlev imzası vardır:
'a -> ('a -> #seq<Dings>) -> seq<Dings>
Gördüğünüz gibi, f
savı daha yakından Dekoratör desen benzer yani aynı imzaya sahip başka bir işlevdir. Bu şekilde oluşturabilirsiniz:
let composed id = GenerateDingse |> AdsFilteredDingse id
Yine, bu gibi composed
69 *kullanabilirsiniz:
let result = Client composed
ya böyle içi:
let result = Client (fun id -> GenerateDingse |> AdsFilteredDingse id)
F ile tüm uygulamaları oluşturmak için daha fazla örnek ve ilkeleri#, my on-line course on Functional architecture with F# bkz.
Fonksiyonel Programlamaya onlar göster nasıl Nesne Yönelimli İlkeler hakkında daha fazla bilgi için, my blog post on the SOLID principles and how they apply to FP bkz.
Tek sayfa JavaScript web uygulama mima...
uygulama yürütülebilir gerekli mimaris...
Haskell işlevi kompozisyon (.) ve işle...
Bu uygulama Reklam Tanımlayıcısını (ID...
RemotingException önlemek için nasıl?u...