工厂模式

        工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

        在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

意图:
        定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

主要解决:
        主要解决接口选择的问题。

何时使用:
        我们明确地计划不同条件下创建不同实例时。

如何解决:
        让其子类实现工厂接口,返回的也是一个抽象的产品。

关键代码:
        创建过程在其子类执行。
    
应用实例: 
        1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。 
        2、Hibernate 换数据库只需换方言和驱动就可以。

优点: 
        1、一个调用者想创建一个对象,只要知道其名称就可以了。 
        2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
        3、屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:
        每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

使用场景: 
        1、日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。 
        2、数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。 
        3、设计一个连接服务器的框架,需要三个协议,"POP3"、"IMAP"、"HTTP",可以把这三个作为产品类,共同实现一个接口。

注意事项:
        作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
interface  Fruit {
     public  void  eat();
}
 
class  Apple  implements  Fruit {
     public  void  eat() {
         System.out.println( "xx吃苹果。" );
     }
}
 
class  Orange  implements  Fruit{
     public  void  eat(){
         System.out.println( "xx吃橘子。" );
     }
}

public  class  InterFaceCaseDemo {
     public  static  void  main(String[] args) {
         Fruit f =  new  Apple();
         f.eat();
     }
}
程序运行结果:  xx吃苹果
        
        以上程序很容易看明白,主方法实际上就相当于是一个客户端,如果此时需要更换一个子类,则必须要修改主方法!

我们可以使用工厂模式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
interface  Fruit {
     public  void  eat();
}
 
class  Apple  implements  Fruit {
     public  void  eat() {
         System.out.println( "xx吃苹果。" );
     }
}
 
class  Orange  implements  Fruit{
     public  void  eat(){
         System.out.println( "xx吃橘子。" );
     }
}

//定义工厂类
class  Factory{
     public  static  Fruit getInstance(String className){
         Fruit f =  null ;
         if ( "apple" .equals(className)){
             f =  new  Apple();
         }
         if ( "orange" .equals(className)){
             f =  new  Orange();
         }
         return  f;
     }
}
 
public  class  InterFaceCaseDemo {
     public  static  void  main(String[] args) {
         Fruit f =  null ;
         f = Factory.getInstance( "apple" );
         f.eat();
     }
}
或使用工厂方法形式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 2. 或可以使用方法的形式
interface  Fruit {
     public  void  eat();
}
 
class  Apple  implements  Fruit {
     public  void  eat() {
         System.out.println( "xx吃苹果。" );
     }
}
 
class  Orange  implements  Fruit {
     public  void  eat() {
         System.out.println( "xx吃橘子。" );
     }
}
 
// 定义工厂类
class  Factory {
     public  Fruit appleFruit() {
         return  new  Apple();
     }
 
     public  Fruit orangeFruit() {
         return  new  Orange();
     }
}
 
public  class  Test {
     public  static  void  main(String[] args) {
         Factory factory =  new  Factory();
         Fruit fruit = factory.appleFruit();
         fruit.eat();
         
         fruit = factory.orangeFruit();
         fruit.eat();
         
     }
}

或静态工厂方法模式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 3. 或静态工厂方法模式(不需要实例化工厂类),首选
interface  Fruit {
     public  void  eat();
}
 
class  Apple  implements  Fruit {
     public  void  eat() {
         System.out.println( "xx吃苹果。" );
     }
}
 
class  Orange  implements  Fruit {
     public  void  eat() {
         System.out.println( "xx吃橘子。" );
     }
}
 
// 定义工厂类
class  Factory {
     public  static  Fruit appleFruit() {
         return  new  Apple();
     }
 
     public  static  Fruit orangeFruit() {
         return  new  Orange();
     }
}
 
public  class  Test {
     public  static  void  main(String[] args) {
         Fruit fruit = Factory.appleFruit();
         fruit.eat();
         
         fruit = Factory.orangeFruit();
         fruit.eat();
     }
}

        程序的运行结果与之前一样,但是取得实例的过程却不太一样,因为接口对象的实例是通过工厂取得的,这样以后如果再有子类扩充,直接修改工厂类客户端就可以根据标记得到相应的实例,灵活性较高。

优点:在简单工厂模式中,客户端不再负责对象的创建,而是把这个责任丢给了工厂类,客户端只负责对象的调用,从而明确了各个类的职责(单一职责)。

缺点:由于这个工厂类负责所有对象的创建,那么当子类不断增多的时候,我们就需要去修改工厂的代码,这样就违反了一个原则:开闭原则。那么我们可以采用另外一中模式改进:工厂方法。

工厂方法模式

        由于简单工厂是把所有对象的创建都放在了一个工厂类里面,假如要创建的对象特别的多,这个工厂类就非常的复杂,不利于后期的维护。

        我们想了另外的一种方式:把每一个对象的创建,都有一个对应的工厂去做。这样的话,每一个工厂只需要负责自己对象的创建即可。这就叫工厂方式模式。

        首先:定义一个工厂,在这个工厂里面定义了规范 , 定义一个Factory接口, 接着,我们定义具体的工厂类,来创建每一个具体的对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
interface  Fruit {
     public  void  eat();
}
 
class  Apple  implements  Fruit {
     public  void  eat() {
         System.out.println( "xx吃苹果。" );
     }
}
 
class  Orange  implements  Fruit {
     public  void  eat() {
         System.out.println( "xx吃橘子。" );
     }
}
 
interface  FruitFactory {
     abstract  Fruit createFruit();
}
 
class  AppleFactory  implements  FruitFactory {
     @Override
     public  Fruit createFruit() {
         return  new  Apple();
     }
}
 
class  OrangeFactory  implements  FruitFactory {
     @Override
     public  Fruit createFruit() {
         return  new  Orange();
     }
}
 
public  class  Test {
     public  static  void  main(String[] args) {
         FruitFactory factory =  new  AppleFactory();
         Fruit a = factory.createFruit();
         a.eat();
     }
}
输入:xx吃苹果。
优点:在工厂方法模式中,客户端不再负责对象的创建,而是把对象的创建交给了工厂类。并且当有新的子类添加的时候,只需要添加一个子类和一个子类的工厂类即可,不需要修改以前的结构,后期更容易维护,增强了系统的扩展性。
缺点:使用该模式需要额外的编写代码,增加了工作量。

其他

        使用反射应用工厂设计模式 , 之前的工厂设计模式增加一个子类时都要修改工厂类,这样肯定会非常麻烦。可以通过反射机制来改善工厂类,让其在增加子类时可以不用做任何的修改,就可以达到功能的扩展。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class  Factory {
     public  static  Fruit getInstance(String className) {
         Fruit fruit =  null ;
         try  {
             fruit = (Fruuit) Class.forName(className).newInstance();
         catch  (Exception e) {
             e.printStackTrace();
         }
         return  fruit;
     }
}
// 调用
public  static  void  main(String[] args) {
     // 通过工厂类取得接口实例,传入完整的包.类名称
     Fruit f = Factory.getInstance( "com.hqu.domian.Apple" );
     if  (f !=  null ) {
         f.eat();
     }
}
        以上的工厂操作类中使用了反射操作取得Fruit实例,这样无论增加多少个子类,工厂类都不用做任何的修改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值