이 구체적인 예를 들어, " 암호를 재설정 할 수 있습니다 " 내가 상속을 통해 구성 사용하는 것이 좋습니다 것 (이 경우, 인터페이스 / 계약의 상속). 왜냐하면 이렇게함으로써 :
class Foo : IResetsPassword {
//...
}
'클래스' 에서 비밀번호를 재설정 할 수 있도록 즉시 (컴파일 타임에) 지정 합니다 . 그러나 시나리오에서 기능의 존재가 조건 적이며 다른 것에 의존하는 경우 더 이상 컴파일 타임에 항목을 지정할 수 없습니다. 그런 다음이 작업을 수행하는 것이 좋습니다.
class Foo {
PasswordResetter passwordResetter;
}
이제 런타임시이 myFoo.passwordResetter != null
작업을 수행하기 전에 확인할 수 있습니다 . 더 많은 것을 분리하고 더 많은 기능을 추가하려는 경우 다음을 수행 할 수 있습니다.
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...
최신 정보
OP의 다른 답변과 의견을 읽은 후 질문이 구성 솔루션에 관한 것이 아니라는 것을 이해했습니다. 따라서 다음과 같은 시나리오에서 일반적인 객체 기능을 더 잘 식별하는 방법에 대한 질문입니다.
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, ...);
}
이제 언급 된 모든 옵션을 분석하려고합니다.
OP 두 번째 예 :
if (account.CanResetPassword)
((IResetsPassword)account).ResetPassword();
else
Print("Not allowed to reset password with this account type!");
이 코드가 기본 계정 클래스를 받고 있다고 가정합니다 (예 : BaseAccount
내 예). 기본 클래스에 부울을 삽입하여 전혀 의미가없는 코드로 부울을 삽입하기 때문에 이것은 좋지 않습니다.
OP 첫 번째 예 :
if (account is IResetsPassword)
((IResetsPassword)account).ResetPassword();
else
Print("Not allowed to reset password with this account type!");
질문에 대답하기 위해 이것은 이전 옵션보다 더 적합하지만 구현에 따라 L 원칙을 깨뜨릴 수 있으며 아마도 코드를 통해 확산되고 추가 유지 관리가 더 어려워 질 것입니다.
설탕에 절인 오렌지의 anser :
account.ResetPassword(authority);
이 ResetPassword
메소드가 BaseAccount
클래스에 삽입되면 OP의 두 번째 예제와 같이 부적절한 클래스 코드로 기본 클래스를 오염시킵니다.
눈사람의 답변 :
AccountManager.resetPassword(otherAccount, adminAccount.getAccessToken());
이것은 좋은 솔루션이지만 기능이 동적이며 시간이 지남에 따라 변경 될 수 있음을 고려합니다. 그러나 OP에서 여러 의견을 읽은 후에는 여기서 이야기가 다형성 및 정적으로 정의 된 클래스에 관한 것이라고 생각합니다 (계정의 예는 동적 시나리오를 직관적으로 지적하지만). EG :이 AccountManager
예에서 권한 확인은 DB에 대한 쿼리입니다. OP 질문에서 검사는 객체를 캐스팅하려는 시도입니다.
나에게서 또 다른 제안 :
높은 수준의 분기에 템플릿 방법 패턴을 사용하십시오. 언급 된 클래스 계층은 그대로 유지됩니다. 캐스트 및 기본 클래스를 오염시키는 부적절한 속성 / 메소드를 피하기 위해 객체에 대해 더 적절한 처리기를 만듭니다.
//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(...);
}
}
사전 / 해시 테이블을 사용하여 작업을 적절한 계정 클래스에 바인딩하거나 확장 메서드를 사용하여 런타임 작업을 수행하거나 dynamic
키워드를 사용 하거나 마지막 옵션으로 계정 개체를 작업에 전달하기 위해 하나의 캐스트 만 사용할 수 있습니다 . 이 경우 캐스트 수는 작업 시작시 단 하나입니다).