문제

C#에서는 다음을 수행 할 수 있습니다.

class Program
{
    static void Main(string[] args)
    {
        List<Animal> animals = new List<Animal>();

        animals.Add(new Dog());
        animals.Add(new Cat());

        foreach (Animal a in animals)
        {
            Console.WriteLine(a.MakeNoise());
            a.Sleep();
        }
    }
}

public class Animal
{
    public virtual string MakeNoise() { return String.Empty; }
    public void Sleep()
    {
        Console.Writeline(this.GetType().ToString() + " is sleeping.");
    }
}

public class Dog : Animal
{
    public override string MakeNoise()
    {
        return "Woof!";
    }
}

public class Cat : Animal
{
    public override string MakeNoise()
    {
        return "Meow!";
    }
}

분명히 출력은 (약간의 역사적)입니다.

  • 개가 자고 있습니다
  • 야옹
  • 고양이가 자고 있습니다

C#은 종종 장황 유형 구문을 위해 조롱되므로 Ruby와 같은 오리 유형 언어에서 다형성/가상 방법을 어떻게 처리합니까?

도움이 되었습니까?

해결책

편집 : 업데이트 된 질문에 대한 더 많은 코드가 추가되었습니다

면책 조항 : 1 년 정도 루비를 사용하지 않았 으며이 컴퓨터에 설치하지 않았으므로 구문이 완전히 잘못 될 수 있습니다. 그러나 개념은 정확합니다.


수업과 무시 된 방법과 똑같은 방법 :

class Animal
    def MakeNoise
        return ""
    end
    def Sleep
        print self.class.name + " is sleeping.\n"
    end
end

class Dog < Animal
    def MakeNoise
        return "Woof!"
    end
end

class Cat < Animal
    def MakeNoise
        return "Meow!"
    end
end

animals = [Dog.new, Cat.new]
animals.each {|a|
    print a.MakeNoise + "\n"
    a.Sleep
}

다른 팁

지금까지 모든 답변은 나에게 꽤 좋아 보인다. 나는 전체 상속이 완전히 필요하지 않다고 언급 할 것이라고 생각했다. 잠시 동안 "수면"행동을 제외하고, 우리는 오리 타자핑을 사용하여 원하는 전체 결과를 달성하고 동물 기본 수업을 전혀 만들 필요를 생략 할 수 있습니다. "Duck-Typing"에 대한 인터넷 검색은 여러 가지 설명을 산출해야합니다. 따라서 "오리처럼 걸어 오리처럼 걸어 다니면 ..."라고 말합시다.

"수면"동작은 배열, 해시 및 기타 Ruby 내장 클래스와 같은 Mixin 모듈을 사용하여 제공 할 수 있습니다. 나는 그것이 반드시 더 나아 졌다고 제안하는 것은 아니며, 단지 다르고 더 관용적으로 루비를하는 방법입니다.

module Animal
  def sleep
    puts self.class.name + " sleeps"
  end
end

class Dog
  include Animal
  def make_noise
    puts "Woof"
  end
end

class Cat
  include Animal
  def make_noise
    puts "Meow"
  end
end

당신은 나머지를 알고 있습니다 ...

관용적 인 루비 사용

class Animal
  def sleep
    puts "#{self.class} is sleeping"
  end
end

class Dog < Animal
  def make_noise
    "Woof!"
  end
end

class Cat < Animal
  def make_noise
    "Meow!"
  end
end

[Dog, Cat].each do |clazz|
  animal = clazz.new
  puts animal.make_noise
  animal.sleep
end

이전 답변을 바탕으로 이것이 어떻게 할 수 있습니까?


설명 후 두 번째 절단 :

class Animal
    def MakeNoise
        raise NotImplementedError # I don't remember the exact error class
    end
    def Sleep
        puts self.class.to_s + " is sleeping."
    end
end

class Dog < Animal
    def MakeNoise
        return "Woof!"
    end
end

class Cat < Animal
    def MakeNoise
        return "Meow!"
    end
end

animals = [Dog.new, Cat.new]
animals.each {|a|
    puts a.MakeNoise
    a.Sleep
}

(나는 이것을 그대로 두지 만 "self.class.name".to_s ")))).

오리 타이핑의 원리는 객체가 호출 된 방법에 응답해야한다는 것입니다. 그래서 그런 일이 트릭도 할 수 있습니다.

module Sleeping
  def sleep; puts "#{self} sleeps"
end

dog = "Dog"
dog.extend Sleeping
class << dog
  def make_noise; puts "Woof!" end
end

class Cat
  include Sleeping
  def to_s; "Cat" end
  def make_noise; puts "Meow!" end
end

[dog, Cat.new].each do |a|
  a.sleep
  a.make_noise
end

동적 인 Manveru 솔루션의 작은 변형은 클래스 유형 배열을 기반으로 다른 종류의 객체를 생성합니다. 실제로 다르지 않고 조금 더 명확합니다.

Species = [Dog, Cat]

Species.each do |specie|
  animal = specie.new   # this will create a different specie on each call of new
  print animal.MakeNoise + "\n"
  animal.Sleep
end

이것이 내가 쓸 방법입니다.

class Animal
  def make_noise; '' end
  def sleep; puts "#{self.class.name} is sleeping." end
end

class Dog < Animal; def make_noise; 'Woof!' end end
class Cat < Animal; def make_noise; 'Meow!' end end

[Dog.new, Cat.new].each do |animal|
  puts animal.make_noise
  animal.sleep
end

그렇지 않습니다 진짜 다른 솔루션과는 다르지만 이것은 내가 선호하는 스타일입니다.

원래 C# 예제에서 41 줄 대 (실제로는 컬렉션 이니셜 라이저를 사용하여 3 줄을 면도 할 수 있음)입니다. 나쁘지 않다!

방법이 있습니다 becomes 다형성을 구현합니다 (주어진 클래스에서 새로운 클래스로 모든 인스턴스 변수를 대처하여)

class Animal
  attr_reader :name

  def initialize(name = nil)
    @name = name
  end

  def make_noise
    ''
  end

  def becomes(klass)
    became = klass.new
    became.instance_variables.each do |instance_variable|
      value = self.instance_variable_get(instance_variable)
      became.instance_variable_set(instance_variable, value)
    end

    became
  end
end

class Dog < Animal
  def make_noise
    'Woof'
  end
end

class Cat < Animal
  def make_noise
    'Meow'
  end
end

animals = [Dog.new('Spot'), Cat.new('Tom')]

animals.each do |animal|
  new_animal = animal.becomes(Cat)
  puts "#{animal.class} with name #{animal.name} becomes #{new_animal.class}"
  puts "and makes a noise: #{new_animal.make_noise}"
  puts '----'
end

결과는 다음과 같습니다.

Dog with name Spot becomes Cat
and makes a noise: Meow
----
Cat with name Tom becomes Cat
and makes a noise: Meow
----
  • 다형성은 피하는 데 유용 할 수 있습니다 if 성명 (antiifcampaign.com)

  • 사용하는 경우 RubyOnRails becomes 메소드는 이미 구현되었습니다. becomes

  • Quicktip : 다형성을 혼합하면 스티 코드를 리팩터링하기 위해 가장 효율적인 콤보를 제공합니다.

도움이 되었으면 좋겠어요

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top