编程旅途是漫长遥远的,在不同时刻有不同的感悟,本文会一直更新下去。
由于 Go 中缺少类和继承等 OOP 特性, 所以无法使用 Go 来实现经典的工厂方法模式。 不过, 我们仍然能实现模式的基础版本, 即简单工厂。案例中使用工厂结构体来构建多种类型的武器。因此工厂方法模式代码使用 C# 表示。
Gun: AK47 gun
Power: 4
Gun: Musket gun
Power: 1
首先, 创建一个名为 iGun的接口, 其中将定义一支枪所需具备的所有方法。 然后是实现了 iGun 接口的 gun枪支结构体类型。 两种具体的枪支——ak47与 musket火枪 ——两者都嵌入了枪支结构体, 且间接实现了所有的 iGun方法。
gunFactory枪支工厂结构体将发挥工厂的作用, 即通过传入参数构建所需类型的枪支。 main.go 则扮演着客户端的角色。 其不会直接与 ak47或 musket进行互动, 而是依靠 gunFactory来创建多种枪支的实例, 仅使用字符参数来控制生产。
package main
type IGun interface {
setName(name string)
setPower(power int)
getName() string
getPower() int
}
package main
type Gun struct {
name string
power int
}
func (g *Gun) setName(name string) {
g.name = name
}
func (g *Gun) getName() string {
return g.name
}
func (g *Gun) setPower(power int) {
g.power = power
}
func (g *Gun) getPower() int {
return g.power
}
package main
type Ak47 struct {
Gun
}
func newAk47() IGun {
return &Ak47{
Gun: Gun{
name: "AK47 gun",
power: 4,
},
}
}
package main
type musket struct {
Gun
}
func newMusket() IGun {
return &musket{
Gun: Gun{
name: "Musket gun",
power: 1,
},
}
}
package main
import "fmt"
func getGun(gunType string) (IGun, error) {
if gunType == "ak47" {
return newAk47(), nil
}
if gunType == "musket" {
return newMusket(), nil
}
return nil, fmt.Errorf("Wrong gun type passed")
}
package main
import "fmt"
func main() {
ak47, _ := getGun("ak47")
musket, _ := getGun("musket")
printDetails(ak47)
printDetails(musket)
}
func printDetails(g IGun) {
fmt.Printf("Gun: %s", g.getName())
fmt.Println()
fmt.Printf("Power: %d", g.getPower())
fmt.Println()
}
Gun: AK47 gun
Power: 4
Gun: Musket gun
Power: 1

程序功能和简单工厂相同,用工厂方法模式实现。
namespace 工厂方法;
public abstract class Gun
{
protected Gun(string name, int power)
{
Name = name;
Power = power;
}
public string Name { get; private set; }
public int Power { get; private set; }
public void setName(string name)
{
Name = name;
}
public void setPower(int power)
{
Power = power;
}
}
public class AK47 : Gun
{
public AK47() : base("ak47", 10)
{
}
}
public class Musket : Gun
{
public Musket() : base("musket", 5)
{
}
}
namespace 工厂方法;
public interface GunFactory
{
Gun createGun();
}
public class AK47Factory : GunFactory
{
public Gun createGun()
{
Console.WriteLine("正在生产AK47");
return new AK47();
}
}
public class MusketFactory : GunFactory
{
public Gun createGun()
{
Console.WriteLine("正在生产Musket");
return new Musket();
}
}
using 工厂方法;
GunFactory gunFactory = new AK47Factory();
Gun ak47_1 = gunFactory.createGun();
Gun ak47_2 = gunFactory.createGun();
gunFactory = new MusketFactory();
Gun Musket_1 = gunFactory.createGun();
List<Gun> guns = new List<Gun>() { ak47_1, ak47_2, Musket_1 };
foreach (Gun gun in guns)
{
Console.WriteLine($"武器名字:{gun.Name}");
Console.WriteLine($"武器伤害:{gun.Power}");
}
正在生产AK47
正在生产AK47
正在生产Musket
武器名字:ak47
武器伤害:10
武器名字:ak47
武器伤害:10
武器名字:musket
武器伤害:5
简单工厂模式也是工厂模式的一种,但不属于23种设计模式。
目的使客户端与产品解耦。将产品创建实例过程从客户端代码中独立出去。生成具体对象的逻辑判断也从客户端分离至简单工厂类中。
简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。
但简单工厂违背了开放-封闭原则,导致每次添加新类别的时候,都需要去修改工厂类的分支case判断,可以用反射动态生成实例解决。
简单工厂反射案例:我的设计模式之旅、01 策略模式、简单工厂、反射 - 小能日记
工厂方法是一种创建型设计模式, 其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。
工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到子类。
工厂方法类 (创建者类):主要职责并非是创建产品。其中通常会包含一些核心业务逻辑,这些逻辑依赖于由工厂方法返回的产品对象。子类可通过重写工厂方法并使其返回不同类型的产品来间接修改业务逻辑。
主要解决:主要解决接口选择的问题。客户端将所有产品视为抽象的接口,客户端知道所有产品都提供该接口要求的方法,并不关心其具体实现方式。
何时使用:
如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。使用特殊的工厂方法代替对于对象构造函数new的直接调用。
实现步骤:
关键代码:创建过程在其子类执行。
应用实例:
优点:
缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。
使用场景:
注意事项:
作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。
创建对象的逻辑判断依旧在客户端中实现。
与其他模式的关系:
首先,你需要创建存储空间来存放所有已经创建的对象。
当他人请求一个对象时,程序将在对象池中搜索可用对象。
然后将其返回给客户端代码。
如果没有可用对象,程序则创建一个新对象(并将其添加到对象池中)。
四个步骤的代码必须位于同一处,确保重复代码不会污染程序!
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
在railstutorial中,作者为什么选择使用这个(代码list10.25):http://ruby.railstutorial.org/chapters/updating-showing-and-deleting-usersnamespace:dbdodesc"Filldatabasewithsampledata"task:populate=>:environmentdoRake::Task['db:reset'].invokeUser.create!(:name=>"ExampleUser",:email=>"example@railstutorial.org",:passwo
我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案