Liekam pinktu uz “I” no apvienības S.O.L.I.D.

Oriģinālliteratūra: “The Interface Segregation Principle (ISP) states that clients should not be forced to depend on methods they do not use.

 

Šo principu ir pavisam vienkārši interpretēt un viegli ievērot: klientam, kas lieto komponenti, kuras autori esam mēs, nedrīkstam jeb nebūtu vēlams “uzspiest” vairāk informācijas nekā viņam (komponentes klientam) tas būtu nepieciešams.

Šī principa kontekstā – interfeiss nav domāts tikai klašu interfeiss (keyword interface), ko kāds implementē vai realizē. Šajā principā runa ir arī par klasēm, kurām ir klienti jeb lietotāji.

Uzskatāmākais piemērs nāk no “System” vārdu telpas – System.Web.Security.MembershipProvider.

 

namespace System.Web.Security
{
    public abstract class MembershipProvider : ProviderBase
    {
        public abstract bool EnablePasswordRetrieval { get; }
        public abstract bool EnablePasswordReset { get; }
        public abstract bool RequiresQuestionAndAnswer { get; }
        public abstract string ApplicationName { get; set; }
        public abstract int MaxInvalidPasswordAttempts { get; }
        public abstract int PasswordAttemptWindow { get; }
        public abstract bool RequiresUniqueEmail { get; }
        public abstract MembershipPasswordFormat PasswordFormat { get; }
        public abstract int MinRequiredPasswordLength { get; }
        public abstract int MinRequiredNonAlphanumericCharacters { get; }
        public abstract string PasswordStrengthRegularExpression { get; }
        public abstract bool ChangePassword(string username, string oldPassword, string newPassword);
 
        public abstract bool ChangePasswordQuestionAndAnswer(string username,
                                                             string password,
                                                             string newPasswordQuestion,
                                                             string newPasswordAnswer);
 
        public abstract MembershipUser CreateUser(string username,
                                                  string password,
                                                  string email,
                                                  string passwordQuestion,
                                                  string passwordAnswer,
                                                  bool isApproved,
                                                  object providerUserKey,
                                                  out MembershipCreateStatus status);
 
        public abstract bool DeleteUser(string username, bool deleteAllRelatedData);
 
        public abstract MembershipUserCollection FindUsersByEmail(string emailToMatch,
                                                                  int pageIndex,
                                                                  int pageSize,
                                                                  out int totalRecords);
 
        public abstract MembershipUserCollection FindUsersByName(string usernameToMatch,
                                                                 int pageIndex,
                                                                 int pageSize,
                                                                 out int totalRecords);
 
        public abstract MembershipUserCollection GetAllUsers(int pageIndex,
                                                             int pageSize,
                                                             out int totalRecords);
 
        public abstract int GetNumberOfUsersOnline();
        public abstract string GetPassword(string username, string answer);
        public abstract MembershipUser GetUser(object providerUserKey, bool userIsOnline);
        public abstract MembershipUser GetUser(string username, bool userIsOnline);
        public abstract string GetUserNameByEmail(string email);
        public abstract string ResetPassword(string username, string answer);
        public abstract bool UnlockUser(string userName);
        public abstract void UpdateUser(MembershipUser user);
        public abstract bool ValidateUser(string username, string password);
        protected virtual byte[] DecryptPassword(byte[] encodedPassword);
        protected virtual byte[] EncryptPassword(byte[] password);
 
        protected virtual byte[] EncryptPassword(byte[] password,
                                                 MembershipPasswordCompatibilityMode legacyPasswordCompatibilityMode);
 
        protected virtual void OnValidatingPassword(ValidatePasswordEventArgs e);
 
        public event MembershipValidatePasswordEventHandler ValidatingPassword;
    }
}
 

 

Jau aplūkojot šo abstraktās klases saturu un nosaukumu, skaidrs, ka šis interfeiss ir nedaudz pa “resnu” un prasās uz dizaina sesiju, kurā visticamāk, ka tiktu radīti citi – mazāki interfeisi, kas piedāvātu konkrētu funkcionalitāti, kas fokusēts un kādu konkrētu problēmu domeinu. Piemēram, vai paroles kriptēšana un atkriptēšana tiešām ir MembershipProvider atbildība?

 

Vēl pēc kā var mēģināt identificēt ISP pārkāpumu ir #region apgabali kodā. Princips ir: ja kodā tiek pielietots reģions, tas visticamāk nozīmē, ka konkrētais koda fragments visticamāk, ka jāpārbīda uz kādu citu vietu (parasti tā ir jauna metode vai pat jauna komponente).

Pāris ieteikumi, kā var mēģināt ievērot ISP ikdienas API dizainēšanas darba procesā:

  1. veidojiet mazus interfeisus, paturiet tikai nepieciešamo
  2. ļaujiet savas komponentes klientiem nodefinēt vēlamo un nepieciešamo interfeisu
  3. pārveidojiet lielus interfeisus mazākos interfeisos, no kuriem katrs piedāvā kādu šauru fokusētu funkcionalitāti.

 

Internetā uzgāju interesantu bildi, kas ļoti precīzi raksturo ISP pārkāpumu:

 

 

Cerams, ka noderēs!

Pārējie raksti SOLID sērijā:

Published Sunday, July 10, 2011 12:18 AM by valdis.iljuconoks

Comments

# IoKKIpNewgHrmqb

OXcwdA Thanks-a-mundo for the article.Really thank you! Fantastic.

Friday, March 23, 2012 2:25 AM by google plus hangouts

Leave a Comment

(obligāts) 
(obligāts) 
(brīvizvēles)
(obligāts)