代码之家  ›  专栏  ›  技术社区  ›  Peter

Ruby中的工厂方法

  •  19
  • Peter  · 技术社区  · 16 年前

    更具体地说,这里有一个虚拟示例:假设我有两个类 Bike Car Vehicle 。我想要这个:

    Vehicle.new('mountain bike')  # returns Bike.new('mountain bike')
    Vehicle.new('ferrari')        # returns Car.new('ferrari')
    

    allocate

    6 回复  |  直到 16 年前
        1
  •  20
  •   Community Mohan Dere    9 年前

    如果我创建了一个未被调用的工厂方法 new initialize ,我想这并不能真正回答“我如何制作一个…构造函数…”的问题,但我认为我会这样做。。。

    class Vehicle
      def Vehicle.factory vt
        { :Bike => Bike, :Car => Car }[vt].new
      end
    end
    
    class Bike < Vehicle
    end
    
    class Car < Vehicle
    end
    

    c = Vehicle.factory :Car
    c.class.factory :Bike
    

    工厂 在这个教学示例中效果很好,但您可能需要考虑IRL @AlexChaffee 评论中的建议。

        2
  •  17
  •   clacke    12 年前

    class Vehicle
      VEHICLES = {}
    
      def self.register_vehicle name
        VEHICLES[name] = self
      end
    
      def self.vehicle_from_name name
        VEHICLES[name].new
      end
    end
    
    class Bike < Vehicle
      register_vehicle 'mountain bike'
    end
    
    class Car < Vehicle
      register_vehicle 'ferrari'
    end
    

    我喜欢类的标签与类本身一起保存,而不是将关于子类的信息与超类一起存储。未调用构造函数 new

    > Vehicle.vehicle_from_name 'ferrari'
    => #<Car:0x7f5780840448>
    > Vehicle.vehicle_from_name 'mountain bike'
    => #<Bike:0x7f5780839198>
    

    请注意 某物 需要确保在运行vehicle_from_name之前加载了这些子类(可能这三个类位于不同的源文件中),否则超类将无法知道存在哪些子类,也就是说,在运行构造函数时,您不能依赖自动加载来拉入这些类。

    我通过将所有子类放入例如a中来解决这个问题 vehicles 子目录并将其添加到末尾 vehicle.rb :

    require 'require_all'
    require_rel 'vehicles'
    

    使用 require_all https://rubygems.org/gems/require_all https://github.com/jarmo/require_all )

        3
  •  6
  •   Peter    16 年前

    改编自 here ,我有

    class Vehicle
      def self.new(model_name)
        if model_name == 'mountain bike'  # etc.
          object = Bike.allocate
        else
          object = Car.allocate
        end
        object.send :initialize, model_name
        object
      end
    end
    
    class Bike < Vehicle
      def initialize(model_name)
      end
    end
    
    class Car < Vehicle
      def initialize(model_name)
      end
    end
    
        4
  •  4
  •   James A. Rosen    16 年前

    那么,包含一个模块而不是一个超类呢?这样,你仍然可以 #kind_of? 工作,没有违约 new

    module Vehicle
      def self.new(name)
        when 'mountain bike'
          Bike.new(name)
        when 'Ferrari'
          Car.new(name)
        ...
        end
      end
    end
    
    class Bike
      include Vehicle
    end
    
    class Car
      include Vehicle
    end
    
        5
  •  2
  •   Rory O'Kane Erce    14 年前
    class VehicleFactory
      def new() 
        if (wife_allows?)
           return Motorcycle.new
        else
           return Bicycle.new
        end
      end
    end
    
    class vehicleUser 
      def doSomething(factory)
        a_vehicle = factory.new()
      end
    end
    

    client.doSomething(Factory.new)
    client.doSomething(Bicycle)    
    client.doSomething(Motorcycle)
    

    ( Amazon link

        6
  •  1
  •   Peter Wagenet    16 年前

    你可以通过改变来清理一些东西 Vehicle#new 致:

    class Vehicle
      def self.new(model_name = nil)
        klass = case model_name
          when 'mountain bike' then Bike
          # and so on
          else                      Car
        end
        klass == self ? super() : klass.new(model_name)
      end
    end
    
    class Bike < Vehicle
      def self.new(model_name)
        puts "New Bike: #{model_name}"
        super
      end
    end
    
    class Car < Vehicle
      def self.new(model_name)
        puts "New Car: #{model_name || 'unknown'}"
        super
      end
    end
    

    最后一行 Vehicle.new klass == self super 带括号。否则,我们最终会用争论来称呼它 没想到。

    > Vehicle.new
    New Car: unknown # from puts
    # => #<Car:0x0000010106a480>
    
    > Vehicle.new('mountain bike')
    New Bike: mountain bike # from puts
    # => #<Bike:0x00000101064300>
    
    > Vehicle.new('ferrari')
    New Car: ferrari # from puts
    # => #<Car:0x00000101060688>
    
    推荐文章