工厂方法模式
工厂方法模式是一种创建型设计模式,定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。让类把实例化推迟到子类。
模型说明
- Product:
- 将会对接口进行声明。对于所有由创建者及其子类构件的对象,这些接口都是通用的。
- ConcreteProductA,ConcreteProductB:
- 具体产品是产品接口的不同实现。
- Creator:
- 声明返回产品对象的工厂方法。该方法的返回类型必须与产品接口相匹配。
- 可以将工厂方法声明为抽象方法,强制要求每个子类以不同方式实现该方法。或者可以在基础工厂方法中返回默认产品类型。
- ConcreteCreatorA,ConcreteCreatorB:将会重写基础工厂方法,使其返回不同类型的产品。
优缺点
1.优点
- 你可以避免创建者和具体产品之间的紧密耦合。
- 单一职责原则:你可以将产品创建代码放在程序的单一位置, 从而使得代码更容易维护。
- 开闭原则:无需更改现有客户端代码, 你就可以在程序中引入新的产品类型。
2.缺点
- 应用工厂方法模式需要引入许多新的子类, 代码可能会因此变得更复杂。 最好的情况是将该模式引入创建者类的现有层次结构中。
使用场景
- 当你在编写代码的过程中, 如果无法预知对象确切类别及其依赖关系时, 可使用工厂方法。
- 如果你希望用户能扩展你软件库或框架的内部组件, 可使用工厂方法。
- 如果你希望复用现有对象来节省系统资源, 而不是每次都重新创建对象, 可使用工厂方法。
参考代码
假设我们需要生产不同的手机
// 产品接口 type IPhone interface { setName(name string) setPrice(price float64) getName() string getPrice() float64 } // 具体产品 type Phone struct { name string price float64 } func (g *Phone) setName(name string) { g.name = name } func (g *Phone) getName() string { return g.name } func (g *Phone) setPrice(price float64) { g.price = price } func (g *Phone) getPrice() float64 { return g.price } type Xiaomi struct { Phone } func NewXiaomi() IPhone { return &Phone{ name: "xiaomi", price: 1999, } } type Huawei struct { Phone } func NewHuawei() IPhone { return &Phone{ name: "huawei", price: 4999, } } // 工厂方法 func getPhone(phoneType string) (IPhone, error) { if phoneType == "xiaomi" { return NewXiaomi(), nil } if phoneType == "huawei" { return NewHuawei(), nil } return nil, fmt.Errorf("wrong phone type passed") } // 客户端执行 func main() { xiaomi, err := getPhone("xiaomi") if err != nil { panic(err) } huawei, err := getPhone("huawei") if err != nil { panic(err) } printDetails(xiaomi) printDetails(huawei) } func printDetails(p IPhone) { fmt.Printf("Phone: %s", p.getName()) fmt.Println() fmt.Printf("Price: %.2f", p.getPrice()) fmt.Println() fmt.Println("---------------------------") }
输出:
Phone: xiaomi Price: 1999.00 --------------------------- Phone: huawei Price: 4999.00 ---------------------------