1,简单的工厂模式
简单的说就是通过一个工厂类,对接口和类进行统一的管理。
我们先通过一个例题来说明一问题。
例子:我要买手机。
1,定义接口,用来买手机。
public interface OnPhone {
/**
* 要购买的手机.
*/
void payPhone();
}
2,创建各种品牌的手机,实现上面的接口。
//小米
public class Mi implements OnPhone {
@Override
public void payPhone() {
System.out.println("我是小米,万物基于MIUI,便宜又实惠,买了");
}
}
//华为
public class Huawei implements OnPhone {
@Override
public void payPhone() {
System.out.println("有点贵哈,但是没有啥大问题,买了");
}
}
//苹果
public class Pingguo implements OnPhone {
@Override
public void payPhone() {
System.out.println("这个更贵,不过有钱,任性,买了");
}
}
接着就是我们的测试类
//买了两部手机
public class Text {
public static void main(String[] args) {
OnPhone mi = new Mi();
mi.payPhone();
OnPhone pingguo = new Pingguo();
pingguo.payPhone();
}
}
结果如下,
我是小米,万物基于MIUI,便宜又实惠,买了
这个更贵,不过有钱,任性,买了
我们观察上面的代码,其实是很好的完成了任务,但是我们的实现类和接口紧密的连接在了一起,耦合很高,在想一下,你要买手机,直接去找厂家买吗?,肯定是找一个代理人,或者是一个官方的软件呀,所以就引出了工厂模式。
我门在添加一个类Fragory,用它来管理手机,你要买什么只要找它就行。
public class Fragory {
public static final int TYPE_MI = 1;//小米
public static final int TYPE_HUA= 2;//华为
public static final int TYPE_pingguo = 3;//苹果
public static OnPhone createPhone(int type){
switch(type){
case TYPE_MI:
return new Mi();
case TYPE_HUA:
return new Huawei();
case TYPE_pingguo:
return new Pingguo();
default:
System.out.println("没有这种手机");
return null;
}
}
}
只要调用这个类的静态工厂的方法里传入你需要购买的手机,然后就好了。如下所示:
public class Text {
public static void main(String[] args) {
OnPhone phone = Fragory.createPhone(Fragory.TYPE_MI);
phone.payPhone();
}
}
下面我们看一下这个模式的优点和缺点:
优点:
- 通过一个静态的方法。就可以拿到所需要的东西,降低了耦合度。
- 简单的工厂模式包含必要的判断逻辑,简单工厂实现了对象的创建和使用的分离。
- 在不修改任何客户端代码的情况下更换和怎家新的具体产品类,在一定程度上提高了系统的灵活性。
缺点:
- 扩展性很差,如果有很多部手机的话,就好定义很多的类,每一个类对应着一部手机。而且还要修改静态工厂,这样就违反了封闭原则,而且会变得非常麻烦。
- 工厂类的职责过重,如果静态工厂出现了问题,则整个系统都会出现问题。
- 简单工厂的静态方法,使得工厂角色无法形成基于继承的等级结构。
工厂方法:
工厂方法则避免了 违反开放封闭原则,其实他的实现方法也非常简单,就是每个产品都对应着一个工厂。
如上面简单工厂,简单的说就是多个产品对应着一个静态的工厂方法。而工厂方法则是多个产品对应着多个工厂。下面我们看一下实现;
1,定义产品抽象类:
//产品抽象类
public abstract class Product {
//显示产品
public abstract void show();
}
2,定义产品实现类:
public class ProductMi extends Product{
public void show() {
System.out.println("生产小米手机");
}
}
public class ProdcutHuaWei extends Product{
public void show() {
System.out.println("生产华为手机");
}
}
public class ProductPingGuo extends Product{
public void show() {
System.out.println("生产苹果手机");
}
}
3,定义工厂抽象类。
public abstract class Fractory {
String name;
//工厂名字
public Fractory(String name){
this.name = name;
print();
}
public void print(){
System.out.println(name);
}
//生产东西
public abstract Product setProduct();
}
4,定义工厂的实现类,每个产品对应一个工厂实现类。
public class FractoryMi extends Fractory {
public FractoryMi() {
super("我是小米工厂");
}
@Override
public Product setProduct() {
// TODO Auto-generated method stub
return new ProductMi();
}
}
public class FractoryHuaWei extends Fractory{
public FractoryHuaWei() {
super("我是华为工厂");
}
@Override
public Product setProduct() {
return new ProdcutHuaWei();
}
}
public class FractoryPingguo extends Fractory{
public FractoryPingguo() {
super("我是苹果工厂");
}
@Override
public Product setProduct() {
return new ProductPingGuo();
}
}
每个工厂里面都有自己的名字,并且创建一个对应的产品对象,通过向上转型返回了出去。
5,使用:
public class Go {
public static void main(String[] args) {
FractoryMi mi = new FractoryMi();
mi.setProduct().show();
}
}
结果如下:
我是小米工厂
生产小米手机
通过创建对应的产品工厂,就可以拿到对应的产品对象,然后调用他的shou方法。
优点:
- 通过常见对应的产品工厂,就能拿到对应的产品对象,同时隐藏了产品被实例化的细节。用户只需要关注工厂,就可以了,不需要知道产品实现的细节。
- 在创建新产品的时候,只需要增加工厂和创建的产品分别实现对应的抽象类就好了,完全符合 封闭性原则。
- 创建对象的细节完全封装在具体的工厂内部,而且有了抽象的工厂类,所有的工厂都继承了自己的父类!完美的体现了多态。
缺点;
- 在增加新的产品时,也必须增加细心地工厂类,会造成额外的开销。
- 抽象层的加入使得理解起来变得有点困难。