比方说,在代码中,我们有一个IEnemy接口,上面有一个称为Attack()的方法。还要说,我们有五个来自IEnemy界面的敌人。在这三个类中,我们使用Attack方法的完全相同的实现。在其中之一中,我们还使用相同的代码,但在方法中的某处更改了一行或两行代码。并且,在上一类中,我们仍然具有相同的实现,但在方法中的某处添加/删除了一行或两行代码。您有解耦此代码的建议吗?
我尝试覆盖该方法,以防万一我们在方法中间进行某些更改。 我尝试使用委托作为参数,当我们想在方法中的其他地方进行更改时,该参数将不起作用。 我尝试在接口上使用扩展方法来进行默认实现,但是其中两个类仍具有解耦的代码。
interface IEnemy
{
void Attack();
}
class Enemy1 : IEnemy
{
public void Attack()
{
Console.WriteLine("This is an enemy");
Console.WriteLine("Enemy is jumping");
Console.WriteLine("Enemy is attacking");
}
}
class Enemy2 : IEnemy
{
public void Attack()
{
Console.WriteLine("This is an enemy");
Console.WriteLine("Enemy is jumping");
Console.WriteLine("Enemy is attacking");
}
}
class Enemy3 : IEnemy
{
public void Attack()
{
Console.WriteLine("This is an enemy");
Console.WriteLine("Enemy is jumping");
Console.WriteLine("Enemy is attacking");
}
}
//Let's say this enemy is not capable of jumping, so we want to remove the code that says enemy is jumping.
class Enemy4 : IEnemy
{
public void Attack()
{
Console.WriteLine("This is an enemy");
Console.WriteLine("Enemy is attacking");
}
}
//Let's say this is the boss and instead of jumping, it will roar.
//So we want to change the code that says enemy is jumping to enemy is roaring.
class Enemy5 : IEnemy
{
public void Attack()
{
Console.WriteLine("This is an enemy");
Console.WriteLine("Enemy is roaring");
Console.WriteLine("Enemy is attacking");
}
}
答案 0 :(得分:2)
我将使用具有默认实现的抽象基类替换该接口,然后将Attack
方法分解为单独的可覆盖步骤。我将Attack
虚拟化为完全具有自己攻击模式的敌人。
abstract class BaseEnemy {
public virtual void Attack() {
AttackIdentify();
AttackSignal();
AttackAttack();
}
protected virtual void AttackIdentify() {
Console.WriteLine("This is an enemy");
}
protected virtual void AttackSignal() {
Console.WriteLine("Enemy is jumping");
}
protected virtual void AttackAttack() {
Console.WriteLine("Enemy is attacking");
}
}
class Enemy1 : BaseEnemy {
protected override void AttackIdentify() {
Console.WriteLine("This is an enemy 1");
}
}
class Enemy2 : BaseEnemy {
}
class Enemy3 : BaseEnemy {
protected override void AttackIdentify() {
Console.WriteLine("This is an enemy 3");
}
}
//Let's say this enemy is not capable of jumping, so we want to remove the code that says enemy is jumping.
class Enemy4 : BaseEnemy {
protected override void AttackSignal() { }
}
//Let's say this is the boss and instead of jumping, it will roar.
//So we want to change the code that says enemy is jumping to enemy is roaring.
class Enemy5 : BaseEnemy {
protected override void AttackSignal() {
Console.WriteLine("Enemy is roaring");
}
}
如果您仍然需要接口IEnemy
,则可以让BaseEnemy
实现它。
答案 1 :(得分:0)
这是它的抽象类版本的基本示例。
public abstract class Enemy
{
public bool CanJump { get; set; } = false;
public bool CanRoar { get; set; } = false;
public bool CanAttack { get; set; } = false;
public virtual void Attack()
{
Console.WriteLine("This is an enemy");
if (CanJump)
{
Console.WriteLine("Enemy is jumping");
}
if (CanRoar)
{
Console.WriteLine("Enemy is roaring");
}
if (CanAttack)
{
Console.WriteLine("Enemy is attacking");
}
}
}
public class Enemy1 : Enemy
{
public Enemy1()
{
CanJump = true;
CanRoar = true;
}
}
public class Enemy2 : Enemy
{
public Enemy2()
{
CanRoar = true;
CanAttack = true;
}
}
public class Enemy3 : Enemy
{
public Enemy3()
{
CanRoar = true;
CanAttack = true;
}
public override void Attack()
{
base.Attack();
Console.WriteLine("Custom thing");
}
}
您会注意到Enemy1
和Enemy2
的工作方式相同,但是设置了不同的属性,这些属性在您调用Attack
方法时将相应显示。我想让您注意的有趣部分是Enemy3
类,它覆盖了该方法。这可以通过使Virtual
抽象类中的方法Enemy
来实现。
此重写允许仍调用类Attack
中的基类方法Enemy
加上它还会显示一个自定义值。因此它非常灵活。
请注意,这对于所提供的示例非常有效,但是通过按类的名称进行操作,我可以轻松地假设实际项目是什么,而这不是正确的方法。您不应该为每个敌人创建一个不同的类,但这超出了问题的范围。