欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

设计模式之工厂模式

程序员文章站 2024-01-21 14:35:58
...
最近阅读原有的一些代码的时候发现,其实可以用一些设计模式来进行重构它。但是之前自己也没有将设计模式进行好好学习总结。当这次带着目的在进行学习的时候,发现其实设计模式真的很好用。设计模式其实就是将在编写代码中的一些可以扑捉的规律进行抽象出来。类似读书时候的一些概念。比如整数:它就是把1,2,3.。这样的数抽象为整数。而Java的类其实也是这样进行抽象出来的。而设计模式不但要抽象出而且也给出解决的一个大致步骤,而且满足面向对象设计的规则。 废话就不说了。
先来看看工厂模式的。
工厂模式细分为:[color=red]简单工厂模式[/color],工厂模式,抽象工厂模式。
这个工厂模式的关键点在:"工厂"。为什么是工厂呢? 联系下现实世界。工厂是什么:工厂里面用机器,有工厂。这两个要素就能够产出很多产品。
在工厂设计模式也是一样。它要工厂也是来产东西。那它产什么呢?现实世界工厂产的是可以买的产品。而在面向对象设计中工厂模式当然是产对象。
[color=red][b]注意:不管是那种工厂模式:工厂就是为了产生对象。[/b][/color]

下面给出实例来详解工厂模式的每一个步骤:
网上流行的一个实例就是:[color=red]果园里面有很多水果,因此就会要有很多工人去帮忙采集水果[/color]。那么我们也借用这个事情来分析下工厂模式吧!

1.简单工厂模式:
分析: [color=red]这个业务中牵涉抽象概念[/color]:水果。为什么水果是抽象概念呢?因为水果是包含很多具体的水果.比如:苹果,香蕉,李子,葡萄。。。。
[color=red]这个业务要做的动作时[/color]:[b]采集[/b]。
这个时候你是否会将水果这个抽象的事物设计为:接口或者抽象类

public interface 水果{
public void 采集();
}
or
public abstract class 水果{
public abstract void 采集();
}


给出几个具体的水果:苹果,香蕉

public class 苹果 implements 水果{
public void 采集(){
System.out.println("采集苹果");
}
}

public class 香蕉 implements 水果{
public void 采集(){
System.out.println("采集香蕉");
}
}


现在该到设计工厂。这个工厂可以生产苹果对象,香蕉对象
第一种最简单的方式:

public class FriutFactory {

//产生苹果对象
public static Friut getApple(){
return new Apple();
}

//产生香蕉对象
public static Friut getBanana(){
return new Banana();
}
}

第二种方式:

public class FriutFactory {
public static Friut getFriut(String type) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
//------通过判断传入的参数来判断new的对象----------------
if(type.equalsIgnoreCase("apple")){
return Apple.class.newInstance();
}else if (type.equalsIgnoreCase("banana")){
return Banana.class.newInstance();
}else{
System.out.println("Not found Class");
return null;
}

}
}


第三种方式:

public class FriutFactory {
public static Friut getFriut(String type) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
Class friut = Class.forName(type);
return (Friut)friut.newInstance();
}
}

以上三种方式都工厂,用于产生具体水果的对象的。但是通常不用第一种方式。

最后看看客户端的调用:

public class Client{

public static void main(String args[]) throws InstantiationException, IllegalAccessException, ClassNotFoundException{
//直接
// Apple apple = new Apple();
// Banana banana = new Banana();
// apple.get();
// banana.get();

//通过接口
//Friut apple = new Apple();
//Friut banana = new Banana();
//apple.get();
//banana.get();

//
//Friut apple = FriutFactory.getApple();
//Friut banana = FriutFactory.getBanana();
//apple.get();
//banana.get();

//通过传入的参数类判断产生的对象
//Friut apple = FriutFactory.getFriut("apple");
//Friut banana = FriutFactory.getFriut("banana");
//apple.get();
//banana.get();

Friut apple = FriutFactory.getFriut("Apple");
Friut banan = FriutFactory.getFriut("banana");
apple.get();
banan.get();
}
}


[color=red][size=medium]接下来将对这个实例将从简单工厂设计模式过渡到使用工厂设计模式。[/size][/color]

[quote]
[color=red]小知识点[/color]:[b]接口和抽象类的区别[/b]:
abstract class 和 interface 是支持抽象类定义的两种机制。因此如果是用来表示对抽象类定义的话,两者有很大的相似处。但是选择不同,也表现出问题本质领域问题的理解,以及设计的意图。
在面向对象的概念中,所以的对象都是通过类来描绘的,但是反过来则不是。并不是所有的类都是用来描绘对象的。如果一个类中没有包含足够的信息来描绘一个具体的对象,那么这样的类就是抽象类。
在abstract class中,它可以用自己的数据成员,也可以有非abstract的成员方法,而interface中能够有静态的不能被修改的数据成员,所有的成员方法都是abstract的。
abstract class 在java语言表示的是一种继承关系,一个类只能使用一次继承关系。但是一个类却是可以实现多个interface。

给出一个sample来看看怎么使用abstract class 和interface
比如我们知道门有两个基本的功能:打开和关闭

这时候你就可以设计一个

public interface 门{
public void 打开();
pubic void 关闭();
}

或者:

public abstract class 门{
public abstract void 打开();
public abstract void 关闭();
}

这个大家感觉不出来有什么区别。
接着随着现在随着技术的发展,发现出现一种报警门。
这时候大家可以会将上面的接口中增加一个
public void 报警();
在抽象类中就增加
public abstract void 报警();
这时候可能很多人也觉得没有问题。我可以肯定的是,如果你加了之后你也可以通过测试得到你想要的。但是这样做就违背了面向对象设计的一个核心原则ISP(Interface Segregation Principle),在这里门的定义中把门感念的本身固有的行为方法和另外一个概念”报警器“的行为方法混在一起。这样就引起类仅仅依赖门这个概念的模块会因为‘报警器’这个概念的改变而改变。

这里就给出两种理解:
第一种,报警门概念上是门,同时它又具有报警的功能。
设计如下:

public abstract class 门{
public abstract void 打开();
public abstract void 关闭();
}
public interface 报警{
public void 报警();
}

那么报警门实现如下

public 报警门 extends 门 implements 报警{
打开();
关闭();
报警();
}

第二种,如果认为报警门在本质的概念上是”报警器“,同时具有门的功能,则将第一实现的方式反过来就可以啦。

[list]
[*]总结 abstract class 和interface
[*] 1. 抽象类是表示继承关系,在java中只有单继承。
[*] 2. 抽象类可以有自己的数据成员,也可以由非抽象的方法,接口只能有静态的不能被修改的数据成员,所以的成员方法都是抽象的
[*] 3. 抽象类表示"is - a"关系,接口表示"like - a"关系
[*] 4. 实现抽象类和接口必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中不能有实现方法。
[*] 5. 接口中定义的变量默认是 public static final 型,而且必须给初始值,所以实现类中不能重新定义,也不能重新赋值。
[*] 6. 抽象类中的变量默认是friendly型,其值可以在子类中重新定义,也可以重新赋值
[*] 7. 接口中的方法默认是public abstract类型
[/list]
[/quote]