Специфікація (шаблон проєктування)

Шаблон проєктування у вигляді UML діаграми

Специфікація — це шаблон проєктування, який представляє бізнес логіку у вигляді ланцюжка об'єктів зв'язних операцій булевої логіки.

Переваги та недоліки

Переваги

  • логіка фільтрації об'єктів винесена в окремі класи-специфікацій, які можна, без втрат в гнучкості системи, об'єднювати між собою

Недоліки

  • важкий в реалізації

Опис мовою C#

Додамо деякі класи, які будуть симулювати реальні об'єкти.

public class User
{
    public string Name { get; set; }
    public bool IsAdmin { get; set; }

    public override string ToString()
    {
        return $"{Name}. Admin = {IsAdmin}";
    }
}

Запишемо стандартну реалізацію, яку згодом покращимо для конкретної мови програмування.

public interface ISpecification<TEntity>
{
    bool IsSatisfiedBy(TEntity entity);

    // об'єднання
    ISpecification<TEntity> And(ISpecification<TEntity> other);
    ISpecification<TEntity> Or(ISpecification<TEntity> other);
    ISpecification<TEntity> Not();
}

Додамо абстрактний клас, який дозволить нам об'єднювати специфікації в ланцюжки за допомогою операторів булевої логіки. У C# цей клас можна замінити на перевантаження операцій чи методами розширень до ISpecification.

public abstract class CompositeSpecification<TEntity> : ISpecification<TEntity>
{
    public abstract bool IsSatisfiedBy(TEntity entity);

    public ISpecification<TEntity> And(ISpecification<TEntity> other)
    {
        return new AndSpecification<TEntity>(this, other);
    }
    
    public ISpecification<TEntity> Or(ISpecification<TEntity> other)
    {
        return new OrSpecification<TEntity>(this, other);
    }
    
    public ISpecification<TEntity> Not()
    {
        return new NotSpecification<TEntity>(this);
    }
}

Реалізацій конкретних декораторів

public class AndSpecification<TEntity> : CompositeSpecification<TEntity>
{
    private readonly ISpecification<TEntity> spec1;
    private readonly ISpecification<TEntity> spec2;    

    public AndSpecification(ISpecification<TEntity> spec1, ISpecification<TEntity> spec2)
    {
        this.spec1 = spec1;
        this.spec2 = spec2;
    }

    public override bool IsSatisfiedBy(TEntity candidate)
    {
        return spec1.IsSatisfiedBy(candidate) && spec2.IsSatisfiedBy(candidate);
    }
}

public class OrSpecification<TEntity> : CompositeSpecification<TEntity>
{
    private readonly ISpecification<TEntity> spec1;
    private readonly ISpecification<TEntity> spec2;

    public OrSpecification(ISpecification<TEntity> spec1, ISpecification<TEntity> spec2)
    {
        this.spec1 = spec1;
        this.spec2 = spec2;
    }

    public override bool IsSatisfiedBy(TEntity candidate)
    {
        return spec1.IsSatisfiedBy(candidate) || spec2.IsSatisfiedBy(candidate);
    }
}

public class NotSpecification<TEntity> : CompositeSpecification<TEntity>
{
    private readonly ISpecification<TEntity> wrapped;

    public NotSpecification(ISpecification<TEntity> spec)
    {
        wrapped = spec;
    }

    public override bool IsSatisfiedBy(TEntity candidate)
    {
        return !wrapped.IsSatisfiedBy(candidate);
    }
}

Припустимо, що виникли наступні задачі:

  • знайти користувачів, за їх статусом
  • знайти користувачів по імені, за введеним значенням

Тоді конкретні специфікації матимуть наступний вигляд

public class RoleSpecification : CompositeSpecification<User>
{
    private readonly bool isUserAdmin;

    public RoleSpecification(bool isUserAdmin)
    {
        this.isUserAdmin = isUserAdmin;
    }

    public override bool IsSatisfiedBy(User entity)
    {
        return entity.IsAdmin == isUserAdmin;
    }
}


public class SearchByNameSpecification : CompositeSpecification<User>
{
    private readonly string searchSubstring;

    public SearchByNameSpecification(string searchSubstring)
    {
        this.searchSubstring = searchSubstring;
    }

    public override bool IsSatisfiedBy(User entity)
    {
        return entity.Name.Contains(searchSubstring);
    }
}

Використання матиме наступний вигляд:

// задана предметна область
User[] users = new User[]
{
    new User { IsAdmin = false, Name = "User 1" },
    new User { IsAdmin = false, Name = "User 2" },
    new User { IsAdmin = true,  Name = "User 3" },
};

           
// конкретні специфікації
ISpecification<User> roleSpecification = new RoleSpecification(isUserAdmin: false);
ISpecification<User> nameSpecification = new SearchByNameSpecification(searchSubstring: "User");

// композиції специфікації
ISpecification<User> andSpecification = nameSpecification.And(roleSpecification);
ISpecification<User> orSpecification = nameSpecification.Or(roleSpecification);
            
// результати вибірки
Console.WriteLine("AND Specification");
foreach (User user in users)
{
    if (andSpecification.IsSatisfiedBy(user))
    {
        Console.WriteLine(user);
    }
}

Console.WriteLine("OR Specification");
foreach (User user in users)
{
    if (orSpecification.IsSatisfiedBy(user))
    {
        Console.WriteLine(user);
    }
}

Покращена версія

При використанні із LINQ специфікації можна обгортати у функції, або ж забезпечити специфікації такою функціональністю:

// інтерфейс
public interface ISpecification<TEntity>
{
    bool IsSatisfiedBy(TEntity entity);

    Func<TEntity, bool> AsExpression();
                   .  .  . 
}

// абстрактний клас
public abstract class CompositeSpecification<TEntity> : ISpecification<TEntity>
{
    public abstract Func<TEntity, bool> AsExpression();
    public bool IsSatisfiedBy(TEntity entity) => AsExpression().Invoke(entity);
    
                   .  .  . 
}

// оператори булевої логіки
public class AndSpecification<TEntity> : CompositeSpecification<TEntity>
{
                   .  .  . 

    public override Func<TEntity, bool> AsExpression()
    {
        return (entity) => spec1.IsSatisfiedBy(entity) && spec2.IsSatisfiedBy(entity);
    }
}

// конкретні специфікації
public class RoleSpecification : CompositeSpecification<User>
{
    private readonly Func<User, bool> isUserAdminPredicate;

    public RoleSpecification(bool isUserAdmin)
    {
        this.isUserAdminPredicate = (user) => user.IsAdmin == isUserAdmin;
    }

    public override Func<User, bool> AsExpression()
    {
        return isUserAdminPredicate;
    }
}

// використання
foreach (User user in users.Where(specification.AsExpression()))
{
    Console.WriteLine(user);
}

Див. також

Джерела

Read other articles:

Daniele Massaro Informasi pribadiNama lengkap Daniele Emilio MassaroTanggal lahir 23 Mei 1961 (umur 62)Tempat lahir Monza, ItaliaTinggi 177 cm (5 ft 10 in)Posisi bermain PenyerangKarier senior*Tahun Tim Tampil (Gol)1979–1981 Monza 60 (10)1981–1986 Fiorentina 140 (11)1986–1995 AC Milan 209 (51)1988–1989 → AS Roma (pinjaman) 30 (5)1995–1996 Shimizu S-Pulse 20 (10)Total 459 (87)Tim nasional1982–1994 Italia 15 (1) * Penampilan dan gol di klub senior hanya dihitu...

 

Lumpy skin disease virus Komposisi genom virus ICTVVirus ADN untai ganda Penyakitpenyakit kulit berbenjol TaksonomiSuperdomainBiotaDomainVirusDuniaVaridnaviriaKerajaanBamfordviraeFilumNucleocytoviricotaKelasPokkesviricetesOrdoChitoviralesFamiliPoxviridaeSubfamiliChordopoxvirinaeGenusCapripoxvirusSpesiesLumpy skin disease virus lbs Lumpy skin disease virus adalah spesies virus dalam genus Capripoxvirus dan famili Poxviridae yang mengakibatkan penyakit kulit berbenjol (LSD) pada sapi dan kerbau...

 

العلاقات البالاوية السلوفاكية بالاو سلوفاكيا   بالاو   سلوفاكيا تعديل مصدري - تعديل   العلاقات البالاوية السلوفاكية هي العلاقات الثنائية التي تجمع بين بالاو وسلوفاكيا.[1][2][3][4][5] مقارنة بين البلدين هذه مقارنة عامة ومرجعية للدولتين: وجه الم...

Untuk singkatan PPP yang lain, lihat PPP. Partai Persatuan Pembangunan Ketua umumMuhamad MardionoSekretaris JenderalMuhamad Arwani ThomafiKetua Fraksi di DPRAmir UskaraDibentuk5 Januari 1973; 51 tahun lalu (1973-01-05)Digabungkan dariPartai Nahdlatul UlamaPartai Islam Persatuan Tarbiyah IslamiyahPartai Syarikat Islam IndonesiaPartai Muslimin IndonesiaKantor pusatJalan Diponegoro 60, Jakarta, IndonesiaSayap pemudaGenerasi Muda Pembangunan Indonesia, Gerakan Pemuda Ka'bah, Angkatan Mu...

 

Railway station in Sydney, New South Wales, Australia This article is about the station in Sydney, Australia. For the former station in Suffolk, England, see Seven Hills Halt railway station. Seven HillsEastbound view from Platform 3 in 2017General informationLocationTerminus Road, Seven Hills, NSWAustraliaCoordinates33°46′28″S 150°56′12″E / 33.77439°S 150.93656°E / -33.77439; 150.93656Elevation40 metres (130 ft)Owned byTransport Asset Holding EntityOp...

 

Cet article est une ébauche concernant une localité luxembourgeoise. Vous pouvez partager vos connaissances en l’améliorant (comment ?) selon les recommandations des projets correspondants. Sandweiler Vue aérienne de Sandweiler et du Findel. Blason Logo Administration Pays Luxembourg Canton Luxembourg Bourgmestre(Buergermeeschter) Mandat Jacqueline Breuer (LSAP) 2023-2029 Codes postaux (liste détaillée) Code UAL 2 LU0000306 Indicatif téléphonique (+352) Démographie Population...

Eberhard KoebelEberhard Koebel circa 1930Born(1907-06-22)22 June 1907Stuttgart, GermanyDied31 August 1955(1955-08-31) (aged 48)Berlin, GermanyOccupation(s)Youth leader, writer, publisher, tent designer and Nazi resister. Eberhard Koebel also Eberhard Köbel, called tusk,[1] i.e., the German in the language of the Sámi people he traveled among,[2][3] (22 June 1907 – 31 August 1955) was a German youth leader, writer, and publisher. Eberhard Koebel was born in St...

 

Европейская сардина Научная классификация Домен:ЭукариотыЦарство:ЖивотныеПодцарство:ЭуметазоиБез ранга:Двусторонне-симметричныеБез ранга:ВторичноротыеТип:ХордовыеПодтип:ПозвоночныеИнфратип:ЧелюстноротыеГруппа:Костные рыбыКласс:Лучепёрые рыбыПодкласс:Новопёры...

 

Persikab BandungNama lengkapPersatuan Sepakbola Indonesia Kabupaten BandungJulukanLaskar Dalem BandungPasukan Dipati UkurGreen WolfBerdiri27 Juli 1963; 60 tahun lalu (1963-07-27)Stadion Stadion Si Jalak Harupat (Kapasitas 38.000) Kabupaten Bandung, Jawa Barat Stadion Gelora Bandung Lautan Api (sementara; Kapasitas 38.000) Kota Bandung, Jawa Barat PemilikPT. Persikab Bandung BedasPresiden Klub Eddy MoelyoSekretaris JaelaniBendahara H. MarlanManajer Nandang SunandarPelatih Putu GedeAsisten...

South African billionaire physician, CEO & philanthropist (b. 1952) Patrick Soon-ShiongSoon-Shiong in 2014Born (1952-07-29) July 29, 1952 (age 71)Port Elizabeth, Union of South AfricaCitizenshipSouth AfricaUnited States[1]Alma materUniversity of the Witwatersrand (MBBCh)University of British Columbia (MS)Occupation(s)Businessman, investor, medical researcher, philanthropist, transplant surgeonKnown forInventor of AbraxaneDeveloper of transplant techniques for pancre...

 

1957 comic book Martin Luther King and the Montgomery StoryCover of Martin Luther King and the Montgomery StoryPublication informationPublisherFellowship of ReconciliationFormatOne-shotGenrenon-fictionPublication dateDecember 1957No. of issues1Main character(s)Martin Luther King Jr.Coretta Scott KingRosa ParksMahatma GandhiCreative teamWritten byAlfred Hassler and Benton ResnikArtist(s)Sy Barry Martin Luther King and the Montgomery Story is a 16-page comic book about Martin Luther King J...

 

Northern Ireland Assembly logo This article is part of a series within thePolitics of the United Kingdom on thePolitics of Northern Ireland Executive Executive Committee First Minister Michelle O'Neill deputya First Minister Emma Little-Pengelly Civil Service Government departments  a Lowercase d per here. Assembly Speaker Edwin Poots MLA Acts Committees Statutory rules Members (MLA) Law Supreme Court (UK) Courts of Northern Ireland Northern Ireland in the UK His Majesty's Government No...

Ne doit pas être confondu avec Assemblée parlementaire du Conseil de l'Europe ou Assemblée de l'Union de l'Europe occidentale. Pour les articles homonymes, voir PE. Parlement européen 9e législature Logo du Parlement européen.Présentation Type Institution de l'Union européenne Création 19521979 (forme actuelle) Lieu Strasbourg (siège) Durée du mandat 5 ans Présidence Présidente Roberta Metsola (PPE) Élection 18 janvier 2022 1er vice-président Othmar Karas (...

 

American baseball player (born 1992) Baseball player Austin VothVoth with the Washington Nationals in 2022Seattle Mariners – No. 30PitcherBorn: (1992-06-26) June 26, 1992 (age 31)Redmond, Washington, U.S.Bats: RightThrows: RightMLB debutJuly 14, 2018, for the Washington NationalsMLB statistics (through June 9, 2024)Win–loss record17–14Earned run average4.78Strikeouts304 Teams Washington Nationals (2018–2022) Baltimore Orioles (2022–2023) Seattle Mariners (2024–...

 

البطولة الوطنية المجرية 2008–09 تفاصيل الموسم البطولة الوطنية المجرية  النسخة 109  البلد المجر  التاريخ بداية:26 يوليو 2008  نهاية:30 مايو 2009  المنظم اتحاد المجر لكرة القدم  البطل نادي دبرتسني  مباريات ملعوبة 240   عدد المشاركين 16   البطولة الوطنية المجرية 2007�...

قصر الصانعمعلومات عامةالمكان مدائن صالح، محافظة العلاالبلد السعوديةتعديل - تعديل مصدري - تعديل ويكي بيانات قصر الصانع، أول القبور في مدائن صالح هو قصر الصانع، وهو بمثابة مقدمة للعناصر الرئيسة للطراز النبطي للقبور في ديار قوم ثمود، والشكلان المكونان من خمس درجات والنقوش ف...

 

1987 studio album by Yolanda AdamsJust as I AmStudio album by Yolanda AdamsReleasedSeptember 22, 1987GenreGospelLength33:55Label Nine Sound of Gospel Producer Thomas Whitfield Lamar Brantley Yolanda Adams chronology Just as I Am(1987) Through the Storm(1991) Professional ratingsReview scoresSourceRatingThe Encyclopedia of Popular Music[1] Just as I Am is the debut studio album by American gospel singer Yolanda Adams. It was released by the Sound of Gospel on September 22, 1987...

 

CSKA MoscaStagione 2018-2019 Sport calcio Squadra CSKA Mosca Allenatore Viktor Goncharenko Prem'er-Liga4º posto Coppa di RussiaSedicesimi di finale Champions LeagueFase a gironi Supercoppa di RussiaVincitore Maggiori presenzeCampionato: Fëdor Čalov e Igor' Akinfeev (30)Totale: Fëdor Čalov (37) Miglior marcatoreCampionato: Fëdor Čalov (15)Totale: Fëdor Čalov (17) 2017-2018 2019-2020 Si invita a seguire il modello di voce Voce principale: Professional'nyj Futbol'nyj Klub Central'n...

CW/MyNetworkTV affiliate in Las Vegas KVCWATSC 3.0 stationLas Vegas, NevadaUnited StatesChannelsDigital: 29 (UHF)Virtual: 33BrandingThe CW Las VegasMy LVTV (DT2)ProgrammingAffiliations33.1: The CW33.2: MyNetworkTVfor others, see § SubchannelsOwnershipOwnerSinclair Broadcast Group(KUPN Licensee, LLC)Sister stationsKSNVHistoryFoundedAugust 26, 1987First air dateJuly 30, 1989(34 years ago) (1989-07-30)Former call signsKFBT (1989–2006)Former channel number(s)Analog: 33 (UHF, 198...

 

У этого термина существуют и другие значения, см. Кичево (значения). ГородКичевомакед. Кичево Флаг Герб 41°30′51″ с. ш. 20°57′47″ в. д.HGЯO Страна  Северная Македония Статистический регион Юго-Западный Община Кичево Глава Фатмир Дехари История и география Прежние н...