`
有崖生110
  • 浏览: 55429 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

接口、抽象类和工厂

 
阅读更多

接口:

Java中的接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。 接口的两种含义:一,Java接口,Java语言中存在的结构,有特定的语法和结构;二,一个类所具有的方法的特征集合,是一种逻辑上的抽象。前者叫做“Java接口”,后者叫做“接口”。

Java接口本身没有任何实现,因为Java接口不涉及表象,而只描述public行为,所以Java接口比Java抽象类更抽象化。但是接口不是类,不能使用new 运算符实例化一个接口。如 x=new comparable(......);//这个是错误来的。但是可以声明接口变量Comparable x; //这是允许的。


接口的特征归纳:


1, Java接口中的成员变量默认都是public,static,final类型的(都可省略),必须被显示初始化,即接口中的成员变量为常量(大写,单词之间用"_"分隔)


2, Java接口中的方法默认都是public,abstract类型的(都可省略),没有方法体,不能被实例化 


public interface A  

   {  

    int CONST = 1; //合法,CONST默认为public,static,final类型  

    void method(); //合法,method()默认为public,abstract类型  

    public abstract void method2(); //method2()显示声明为public,abstract类型  

   } 

3, Java接口中只能包含public,static,final类型的成员变量和public,abstract类型的成员方法


public interface A  

  {  

   int var; //错,var是常量,必须显示初始化   

   void method(){...};   //错,接口中只能包含抽象方法  

   protected void method2(); //错,接口中的方法必须是public类型  

   static void method3(){...};   //错,接口中不能包含静态方法  

  } 

4, 接口中没有构造方法,不能被实例化


public interface A  

  {  

   public A(){...}; //错,接口中不能包含构造方法  

   void method();  

  } 

5, 一个接口不能实现(implements)另一个接口,但它可以继承多个其它的接口


public interface A  

 {  

  void methodA();  

 }  

 public interface B  

 {  

  void methodB();  

 }  

 public interface C extends A, B   //C称为复合接口  

 {  

  void methodC();  

 }  

 public interface C implements A{...}   //错 


6, Java接口必须通过类来实现它的抽象方法


public class A implements B{...}


7, 当类实现了某个Java接口时,它必须实现接口中的所有抽象方法,否则这个类必须声明为抽象的


8, 不允许创建接口的实例(实例化),但允许定义接口类型的引用变量,该引用变量引用实现了这个接口的类的实例


public class B implements A{}  

   A a = new B(); //引用变量a被定义为A接口类型,引用了B实例  

   A a = new A(); //错误,接口不允许实例化 

9, 一个类只能继承一个直接的父类,但可以实现多个接口,间接的实现了多继承.


public class A extends B implements C, D{...} //B为class,C,D为interface


接口与抽象类的区别:


Java接口和Java抽象类最大的一个区别,就在于Java抽象类可以提供某些方法的部分实现,而Java接口不可以,这大概就是Java抽象类唯一的优点吧,但这个优点非常有用。如果向一个抽象类里加入一个新的具体方法时,那么它所有的子类都一下子都得到了这个新方法,而Java接口做不到这一点,如果向一个Java接口里加入一个新方法,所有实现这个接口的类就无法成功通过编译了,因为你必须让每一个类都再实现这个方法才行,这显然是Java接口的缺点。

一个抽象类的实现只能由这个抽象类的子类给出,也就是说,这个实现处在抽象类所定义出的继承的等级结构中,而由于Java语言的单继承性,所以抽象类作为类型定义工具的效能大打折扣。在这一点上,Java接口的优势就出来了,任何一个实现了一个Java接口所规定的方法的类都可以具有这个接口的类型,而一个类可以实现任意多个Java接口,从而这个类就有了多种类型。

不难看出,Java接口是定义混合类型的理想工具,混合类表明一个类不仅仅具有某个主类型的行为,而且具有其他的次要行为。

在语法上,抽象类和接口有着以下不同:

1.abstract class在Java语言中表示的是一种继承关系,一个类只能使用一次继承关系。但是,一个类却可以实现多个interface。 继承抽象类使用的是extends关键字,实现接口使用的是implements关键字,继承写在前面,实现接口写在后面。如果实现多个接口,中间用逗号分隔。例:

public class Main extends JApplet

public class Main implements Runnable

public class Main extends JApplet implements ActionListener

public class Main extends JApplet implements ActionListener, Runnable


2.在abstract class中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有静态的不能被修改的数据成员(也就是必须是static final的,不过在 interface中一般不定义数据成员),所有的成员方法都是abstract的。


3.abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系,interface表示的是"like-a"关系。


4.实现抽象类和接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现方法。


5.接口中定义的变量默认是public static final 型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值。


6.抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。


7.接口中的方法默认都是 public,abstract 类型的。



2者设计理念区别---


abstarct class在Java语言中体现了一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is a"关系,即父类和派生类在概念本质上应该是相同的。对于interface 来说则不然,并不要求interface的实现者和interface定义在概念本质上是一致的,仅仅是实现了interface定义的契约而已。为了使论述便于理解,下面将通过一个简单的实例进行说明。 


考虑这样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Door具有执行两个动作open和close,此时我们可以通过abstract class或者interface来定义一个表示该抽象概念的类型,定义方式分别如下所示: 


使用abstract class方式定义Door: 


abstract class Door { 

abstract void open(); 

abstract void close(); 



使用interface方式定义Door: 



interface Door { 

void open(); 

void close(); 



其他具体的Door类型可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看起来好像使用abstract class和interface没有大的区别。 


如果现在要求Door还要具有报警的功能。我们该如何设计针对该例子的类结构呢(在本例中,主要是为了展示abstract class和interface反映在设计理念上的区别,其他方面无关的问题都做了简化或者忽略)?下面将罗列出可能的解决方案,并从设计理念层面对这些不同的方案进行分析。 


解决方案一: 


简单的在Door的定义中增加一个alarm方法,如下: 


abstract class Door { 

abstract void open(); 

abstract void close(); 

abstract void alarm(); 



或者 


interface Door { 

void open(); 

void close(); 

void alarm(); 



那么具有报警功能的AlarmDoor的定义方式如下: 


class AlarmDoor extends Door { 

void open() { … } 

void close() { … } 

void alarm() { … } 



或者 


class AlarmDoor implements Door { 

void open() { … } 

void close() { … } 

void alarm() { … } 

} 


这种方法违反了面向对象设计中的一个核心原则ISP(Interface Segregation Priciple),在Door的定义中把Door概念本身固有的行为方法和另外一个概念"报警器"的行为方法混在了一起。这样引起的一个问题是那些仅仅依赖于Door这个概念的模块会因为"报警器"这个概念的改变(比如:修改alarm方法的参数)而改变,反之依然。 


解决方案二: 


既然open、close和alarm属于两个不同的概念,根据ISP原则应该把它们分别定义在代表这两个概念的抽象类中。定义方式有:这两个概念都使用abstract class方式定义;两个概念都使用interface方式定义;一个概念使用abstract class方式定义,另一个概念使用interface方式定义。 


显然,由于Java语言不支持多重继承,所以两个概念都使用abstract class方式定义是不可行的。后面两种方式都是可行的,但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意图的反映是否正确、合理。我们一一来分析、说明。 


如果两个概念都使用interface方式来定义,那么就反映出两个问题:1、我们可能没有理解清楚问题领域,AlarmDoor在概念本质上到底是Door还是报警器?2、如果我们对于问题领域的理解没有问题,比如:我们通过对于问题领域的分析发现AlarmDoor在概念本质上和Door是一致的,那么我们在实现时就没有能够正确的揭示我们的设计意图,因为在这两个概念的定义上(均使用interface方式定义)反映不出上述含义。 


如果我们对于问题领域的理解是:AlarmDoor在概念本质上是Door,同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢?前面已经说过,abstract class在Java语言中表示一种继承关系,而继承关系在本质上是"is a"关系。所以对于Door这个概念,我们应该使用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行为,所以报警概念可以通过interface方式定义。如下所示: 


abstract class Door { 

abstract void open(); 

abstract void close(); 

interface Alarm { 

void alarm(); 

class AlarmDoor extends Door implements Alarm { 

void open() { … } 

void close() { … } 

void alarm() { … } 



这种实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭示我们的设计意图。其实abstract class表示的是"is a"关系,interface表示的是"like a"关系,大家在选择时可以作为一个依据,当然这是建立在对问题领域的理解上的,比如:如果我们认为AlarmDoor在概念本质上是报警器,同时又具有Door的功能,那么上述的定义方式就要反过来了。



工厂模式---



工厂模式在《Java与模式》中分为三类:

1)简单工厂模式(Simple Factory):不利于产生系列产品;


2)工厂方法模式(Factory Method):又称为多形性工厂;


3)抽象工厂模式(Abstract Factory):又称为工具箱,产生产品族,但不利于产生新的产品;

             这三种模式从上到下逐步抽象,并且更具一般性。

             GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。



二、简单工厂模式


简单工厂模式又称静态工厂方法模式。重命名上就可以看出这个模式一定很简单。它存在的目的很简单:定义一个用于创建对象的接口。


在简单工厂模式中,一个工厂类处于对产品类实例化调用的中心位置上,它决定那一个产品类应当被实例化, 如同一个交通警察站在来往的车辆流中,决定放行那一个方向的车辆向那一个方向流动一样。

        先来看看它的组成:


         1) 工厂类角色:这是本模式的核心,含有一定的商业逻辑和判断逻辑。在java中它往往由一个具体类实现。


         2) 抽象产品角色:它一般是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。


         3) 具体产品角色:工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现。


三、工厂方法模式


工厂方法模式是简单工厂模式的进一步抽象化和推广,工厂方法模式里不再只由一个工厂类决定那一个产品类应当被实例化,这个决定被交给抽象工厂的子类去做。

  来看下它的组成:


       1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。


       2)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。


       3)抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。


       4)具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。

       工厂方法模式使用继承自抽象工厂角色的多个子类来代替简单工厂模式中的“上帝类”。正如上面所说,这样便分担了对象承受的压力;而且这样使得结构变得灵活 起来——当有新的产品(即暴发户的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代 码。可以看出工厂角色的结构也是符合开闭原则的!

那么简单工厂模式怎么用呢?我来举个例子吧,我想这个比讲一大段理论上的文字描述要容易理解的多!下面就来给那个暴发户治病: P 
在使用了简单工厂模式后,现在暴发户只需要坐在车里对司机说句:"开车"就可以了。来看看怎么实现的: 
//抽象产品角色 
public interface Car{ 
public void drive(); 
//具体产品角色 
public class Benz implements Car{ 
public void drive() { 
System.out.println("Driving Benz "); 
public class Bmw implements Car{ 
public void drive() { 
System.out.println("Driving Bmw "); 
。。。(奥迪我就不写了:P) 
//工厂类角色 
public class Driver{ 
//工厂方法 
//注意 返回类型为抽象产品角色 
public static Car driverCar(String s)throws Exception { 
//判断逻辑,返回具体的产品角色给Client 
if(s.equalsIgnoreCase("Benz")) return new Benz(); 
else if(s.equalsIgnoreCase("Bmw")) 
return new Bmw(); 
...... 
else throw new Exception(); 
。。。 
//欢迎暴发户出场...... 
public class Magnate{ 
public static void main(String[] args){ 
try{ 
//告诉司机我今天坐奔驰 
Car car = Driver.driverCar("benz"); 
//下命令:开车 
car.drive(); 
。。。 
如果将所有的类放在一个文件中,请不要忘记只能有一个类被声明为public。 程序中类之间的关系如下: 
这便是简单工厂模式了。下面是其好处: 
首先,使用了简单工厂模式后,我们的程序不在"有病",更加符合现实中的情况;而且客户端免除了直接创建产品对象的责任,而仅仅负责"消费"产品(正如暴发户所为)。 
下面我们从开闭原则上来分析下简单工厂模式。当暴发户增加了一辆车的时候,只要符合抽象产品制定的合同,那么只要通知工厂类知道就可以被客户使用了。那么对于产品部分来说,它是符合开闭原则的--对扩展开放、对修改关闭;但是工厂部分好像不太理想,因为每增加一辆车,都要在工厂类中增加相应的商业逻辑和判断逻辑,这显自然是违背开闭原则的。 
对于这样的工厂类(在我们的例子中是为司机师傅),我们称它为全能类或者上帝类。 
我们举的例子是最简单的情况,而在实际应用中,很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品,所以这可能会把我们的上帝类坏了,进而累坏了我们可爱的程序员:( 
正如我前面提到的简单工厂模式适用于业务将简单的情况下。而对于复杂的业务环境可能不太适应阿。这就应该由工厂方法模式来出场了!! 
四、工厂方法模式 
先来看下它的组成吧: 
1、抽象工厂角色:这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。 
2、具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。 
3、抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。 
4、具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。 
来用类图来清晰的表示下的它们之间的关系: 
我们还是老规矩使用一个完整的例子来看看工厂模式各个角色之间是如何来协调的。话说暴发户生意越做越大,自己的爱车也越来越多。这可苦了那位司机师傅了,什么车它都要记得,维护,都要经过他来使用!于是暴发户同情他说:看你跟我这么多年的份上,以后你不用这么辛苦了,我给你分配几个人手,你只管管好他们就行了!于是,工厂方法模式的管理出现了。代码如下: 
//抽象产品角色,具体产品角色与简单工厂模式类似,只是变得复杂了些,这里略。 
//抽象工厂角色 
public interface Driver{ 
public Car driverCar(); 
public class BenzDriver implements Driver{ 
public Car driverCar(){ 
return new Benz(); 
public class BmwDriver implements Driver{ 
public Car driverCar() { 
return new Bmw(); 
......//应该和具体产品形成对应关系,这里略... 
//有请暴发户先生 
public class Magnate 
public static void main(String[] args) 
try{ 
Driver driver = new BenzDriver(); 
Car car = driver.driverCar(); 
car.drive(); 
}catch(Exception e) 
{ } 
工厂方法使用一个抽象工厂角色作为核心来代替在简单工厂模式中使用具体类作为核心。让我们来看看工厂方法模式给我们带来了什么?使用开闭原则来分析下工厂方法模式。当有新的产品(即暴发户的汽车)产生时,只要按照抽象产品角色、抽象工厂角色提供的合同来生成,那么就可以被客户使用,而不必去修改任何已有的代码。看来,工厂方法模式是完全符合开闭原则的! 
使用工厂方法模式足以应付我们可能遇到的大部分业务需求。但是当产品种类非常多时,就会出现大量的与之对应的工厂类,这不应该是我们所希望的。所以我建议在这种情况下使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类:即对于产品树上类似的种类(一般是树的叶子中互为兄弟的)使用简单工厂模式来实现。 
当然特殊的情况,就要特殊对待了:对于系统中存在不同的产品树,而且产品树上存在产品族,那么这种情况下就可能可以使用抽象工厂模式了。 
五、小结 
让我们来看看简单工厂模式、工厂方法模式给我们的启迪: 
如果不使用工厂模式来实现我们的例子,也许代码会减少很多--只需要实现已有的车,不使用多态。但是在可维护性上,可扩展性上是非常差的(你可以想象一下,添加一辆车后要牵动的类)。因此为了提高扩展性和维护性,多写些代码是值得的。 

回到抽象产品模式的话题上,可以这么说,它和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象。而且使用抽象工厂模式还要满足一下条件: 
1.系统中有多个产品族,而系统一次只可能消费其中一族产品 
2.同属于同一个产品族的产品以其使用。 
来看看抽象工厂模式的各个角色(和工厂方法的如出一辙)~


 

分享到:
评论

相关推荐

    抽象方法简单工厂

    简单工厂模式通常包含三个主要角色:工厂类、产品接口或抽象类以及具体产品类。在这个场景中,我们可以创建一个抽象类,例如"Phone",它定义了所有手机应具有的通用行为,如打电话、发短信等,这些行为以抽象方法的...

    关于C++抽象类代码资源

    - 设计模式:在设计模式中,如工厂模式、策略模式等,抽象类常作为通用接口,定义了一组操作,由具体的子类去实现。 5. 派生类与抽象类的关系: 派生类可以从抽象类继承,并实现其纯虚函数,这样就可以实例化派生...

    c++ 抽象工厂模式

    在C++中,抽象工厂模式通过接口和抽象类来实现,可以有效地隔离了客户端与具体产品的耦合。 首先,我们来看一下抽象工厂模式的主要角色: 1. **抽象工厂(Abstract Factory)**:这是模式的核心,定义了一组创建...

    抽象工厂模式实现

    抽象产品可以是接口或者抽象类。 4. **具体产品(Concrete Product)**:实现了抽象产品接口,代表具体的产品对象。每个具体产品都是抽象产品接口的一个实现。 在描述中的链接中,可能会展示如何在C#中实现抽象工厂...

    JAVA设计模式之抽象工厂模式案例

    在Java中,这通常是一个抽象类或接口。 2. 具体工厂(Concrete Factory):实现了抽象工厂中定义的接口,负责创建具体的产品对象。每个具体工厂对应一个特定的产品族。 3. 抽象产品(Abstract Product):定义了产品...

    C#中的简单工厂和虚方法、抽象类、抽象方法

    简单工厂模式是一种创建型设计模式,而虚方法、抽象类和抽象方法则是面向对象编程的重要概念。接下来,我们将深入探讨这些主题。 首先,简单工厂模式(Simple Factory Pattern)是一种用于创建对象的设计模式。它...

    设计模式-抽象工厂模式javademo

    在Java中,这通常表现为一个抽象类或接口。 2. **具体工厂(Concrete Factory)**:实现了抽象工厂定义的接口,负责具体对象的创建。每个具体工厂对应一个特定的产品族,可以根据不同的条件或配置来创建相应的对象...

    抽象工厂的介绍应用

    这种模式的关键在于"抽象工厂",它是一个接口或者抽象类,定义了创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。这种模式在实际开发中常用于框架构建、组件之间的解耦以及平台相关的对象创建等场景。...

    java设计模式-抽象工厂模式

    1. **抽象工厂(Abstract Factory)**:这是模式的核心,它是一个接口或者抽象类,定义了创建一组相关或相互依赖对象的接口,而不必指定它们的具体类。在Java中,这个接口通常会包含多个方法,每个方法对应一种产品...

    抽象工厂Demo

    通常,抽象工厂是一个接口或抽象类,它规定了需要生产的对象类型,并且不关心具体的实现细节。 2. **具体工厂(Concrete Factories)**:这是抽象工厂的具体实现,每个具体工厂负责生产一类相关的产品。例如,如果...

    设计模式-抽象工厂模式(讲解及其实现代码)

    - 隔离了具体类和抽象类,使得系统对产品族的扩展非常方便。 - 支持多线程环境下的并行操作,因为每个产品族的创建都是独立的。 然而,抽象工厂模式也存在一些局限性: - 如果产品结构过于复杂,可能导致抽象工厂...

    抽象工厂模式Demo

    抽象工厂模式是一种设计模式,属于创建型模式,它提供了一种创建对象集合的接口,而无需指定具体的类。这种模式的主要目的是为了隔离产品对象的创建和使用,使得客户端代码可以独立于具体的产品实现。在软件工程中,...

    设计模式 - 抽象工厂模式

    抽象工厂模式的核心是提供一个抽象的工厂接口,该接口定义了一组用于创建产品的方法,而不需要指定具体的类。具体的工厂类继承该接口,并实现了这些方法以创建具体的产品。 抽象工厂模式的优点包括: * decoupling...

    抽象工厂7层架构(C#源码)

    抽象工厂模式是设计模式中的一个核心概念,它属于创建型模式,主要用来提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们的具体类。在C#中,抽象工厂模式的应用可以使得代码更加灵活,易于扩展,同时降低...

    抽象工厂模式简单小例子

    1. **增加系统复杂度**:由于抽象工厂模式引入了大量的抽象类和接口,可能会使系统变得更加复杂。 2. **增加类的数量**:为了实现抽象工厂模式,需要为每一种产品类型创建对应的抽象类和具体类,这会增加类的数量,...

    工厂接口虚函数抽象函数单例DEMO

    结合这些概念,DEMO可能会展示如何在ASP.NET C#项目中创建一个工厂类来生成产品对象,这些对象可能是基于抽象类的,允许在子类中实现具体逻辑。同时,单例模式可能被用来管理业务逻辑层的服务实例,确保在整个应用...

    从战略角度对Java抽象类与接口的剖析.pdf

    例如,工厂模式、单例模式、策略模式等,这些模式在不同程度上运用了抽象类与接口来实现设计目标。通过运用这些模式,能够帮助开发者在面对具体问题时,快速定位到最适合的解决方案,并指导开发者如何具体实施。 举...

    Java抽象类 一篇文章详解

    6. **设计模式**:在设计模式中,如工厂模式、策略模式等,抽象类经常被用作模板,为子类提供统一的接口和部分实现。 了解了Java抽象类的基本概念后,我们来看看如何在实际编程中使用它们。首先,你需要定义一个...

    工厂方法模式和抽象工厂模式的区别

    与工厂方法模式相比,抽象工厂模式更进一步,它提供了创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类。在抽象工厂模式中,不只一个产品类被创建,而是有一组相关的产品类。这种模式适用于当系统需要...

    抽象工厂模式的C++、Java实现

    在Java中,抽象工厂模式的实现稍微不同,因为Java没有显式的接口关键字,而是通过抽象类或者接口来定义抽象工厂。假设我们有`AbstractFactory`类或接口,其中包含`createProductA()`和`createProductB()`等方法。...

Global site tag (gtag.js) - Google Analytics