Bu özel Örneğin " bir şifre sıfırlama ", ben miras üzerinde kompozisyon kullanarak öneriyoruz (bu durumda, bir arayüz / sözleşme miras). Çünkü bunu yaparak:
class Foo : IResetsPassword {
//...
}
Derhal (derleme zamanında) sınıfınızın ' bir şifreyi sıfırlayabileceğini ' belirtiyorsunuz . Ancak, senaryonuzda, kabiliyetin varlığı şartlı ve diğer şeylere bağlıysa, derleme zamanında bir şey belirtemezsiniz. O zaman şunu yapmayı öneriyorum:
class Foo {
PasswordResetter passwordResetter;
}
Şimdi, çalışma zamanında, myFoo.passwordResetter != nullbu işlemi yapmadan önce olup olmadığını kontrol edebilirsiniz . Eşyaları daha da fazla ayırmak istiyorsanız (ve daha fazla özellik eklemeyi planlıyorsanız) şunları yapabilirsiniz:
class Foo {
//... foo stuff
}
class PasswordResetOperation {
bool Execute(Foo foo) { ... }
}
class SendMailOperation {
bool Execute(Foo foo) { ... }
}
//...and you follow this pattern for each new capability...
GÜNCELLEME
OP'den bazı cevaplar ve yorumlar okuduktan sonra, sorunun bileşimsel çözümle ilgili olmadığını anladım. Bu nedenle, sorunun genel olarak aşağıdaki gibi bir senaryoda nesnelerin yeteneklerinin nasıl daha iyi tanımlanabileceğiyle ilgili olduğunu düşünüyorum:
class BaseAccount {
//...
}
class GuestAccount : BaseAccount {
//...
}
class UserAccount : BaseAccount, IMyPasswordReset, IEditPosts {
//...
}
class AdminAccount : BaseAccount, IPasswordReset, IEditPosts, ISendMail {
//...
}
//Capabilities
interface IMyPasswordReset {
bool ResetPassword();
}
interface IPasswordReset {
bool ResetPassword(UserAccount userAcc);
}
interface IEditPosts {
bool EditPost(long postId, ...);
}
interface ISendMail {
bool SendMail(string from, string to, ...);
}
Şimdi, belirtilen tüm seçenekleri analiz etmeye çalışacağım:
OP ikinci örnek:
if (account.CanResetPassword)
((IResetsPassword)account).ResetPassword();
else
Print("Not allowed to reset password with this account type!");
Diyelim ki bu kod bazı temel hesap sınıflarını alıyor (örneğin: BaseAccountbenim örneğimde); Bu kötü bir durumdur çünkü temel sınıfa boole'lar ekler, orada olması hiç mantıklı olmayan bir kodla kirletir.
OP ilk örnek:
if (account is IResetsPassword)
((IResetsPassword)account).ResetPassword();
else
Print("Not allowed to reset password with this account type!");
Soruyu cevaplamak için, bu önceki seçenekten daha uygundur, ancak uygulamaya bağlı olarak, katı L prensibini kıracak ve muhtemelen bu gibi kontroller kod boyunca yayılacak ve daha fazla bakım yapılmasını zorlaştıracaktır.
CandiedOrange'in yanıtı:
account.ResetPassword(authority);
Bu ResetPasswordyöntem BaseAccountsınıfa eklenirse, OP'nin ikinci örneğinde olduğu gibi temel sınıfı da uygunsuz kodla kirletiyor
Snowman'ın cevabı:
AccountManager.resetPassword(otherAccount, adminAccount.getAccessToken());
Bu iyi bir çözüm, ancak yeteneklerin dinamik olduğunu ve zaman içinde değişebileceğini düşünüyor. Bununla birlikte, OP'den birkaç yorum okuduktan sonra, burada konuşmanın polimorfizm ve statik olarak tanımlanmış sınıflarla ilgili olduğunu düşünüyorum (her ne kadar sezgisel hesapların dinamik senaryoya işaret etmesine rağmen). EG: Bu AccountManagerörnekte izin kontrolü DB'ye sorgular olacaktır; OP sorusundaki kontroller, nesneleri atma girişimleridir.
Benden başka bir öneri:
Yüksek düzeyde dallanma için Şablon Yöntemi desenini kullanın. Bahsedilen sınıf hiyerarşisi olduğu gibi tutulur; temel sınıfı kirleten atmalardan ve uygun olmayan özelliklerden / yöntemlerden kaçınmak için yalnızca nesneler için daha uygun işleyiciler yaratırız.
//Template method
class BaseAccountOperation {
BaseAccount account;
void Execute() {
//... some processing
TryResetPassword();
//... some processing
TrySendMail();
//... some processing
}
void TryResetPassword() {
Print("Not allowed to reset password with this account type!");
}
void TrySendMail() {
Print("Not allowed to reset password with this account type!");
}
}
class UserAccountOperation : BaseAccountOperation {
UserAccount userAccount;
void TryResetPassword() {
account.ResetPassword(...);
}
}
class AdminAccountOperation : BaseAccountOperation {
AdminAccount adminAccount;
override void TryResetPassword() {
account.ResetPassword(...);
}
void TrySendMail() {
account.SendMail(...);
}
}
Bir nesneyi / bir karma tablo kullanarak işlemi uygun hesap sınıfına bağlayabilir veya uzantı yöntemlerini kullanarak çalışma zamanı işlemleri gerçekleştirebilir, dynamicanahtar sözcük kullanabilir veya son seçenek olarak , hesap nesnesini işleme iletmek için yalnızca bir döküm kullanabilirsiniz . bu durumda, atma sayısı işlemin başında sadece bir tanedir).