关于程序一些看发

来源:百度文库 编辑:神马文学网 时间:2024/03/29 21:13:16
 Java与模式(一)探讨设计模式基于Java语言的实现以及Java中一些易混淆的概念

面向对象的设计原则:

  • 开-闭原则(Open-Closed Principle, OCP):一个软件实体应当对扩展开放,对修改关闭。这一原则最早由Bertrand Meyer提出,英文原文为:Software entities should be open for extension, but closed for modification.
  • 里氏代换原则(Liskov Substitution Principle, LSP):任何基类可以出现的地方,子类一定可以出现。
  • 依赖倒转原则(Dependency Inversion Principle, DIP):要依赖于抽象,不要依赖于实现。
  • 接口隔离原则(Interface Segregation Principle, ISP):应当为客户端提供尽可能小的单独的借口,而不要提供大家的总接口。
  • 组合/聚合复用原则(Compostion/Aggregation Principle, CARP):尽量使用组合/聚合,而不是继承关系达到复用的目的。
  • 迪米特法则(Law of Demeter, LoD):一个软件实体应当尽可能少的与其他实体发生相互作用。

--------------------------------------

一个Java接口的方法只能是抽象的和公开的,比Java抽象类更为抽象化,Java接口不能有构造函数。Java接口可以有public、静态的和final的属性。接口与类的最重要区别是,接口仅仅描述方法的特征(Signature),而不给出方法的实现;而类不仅给出方法的特征,而且给出方法的实现。

标识接口是没有任何方法和属性的接口。标识接口不对实现它的类有任何语义上的要求,它仅仅表明实现它的类属于一个特定的类型。如java.io.Serializable和java.rmi.Remote都是标识接口。

package java.io; public interface Serializable {}

package java.rmi; public interface Remote{}

常量接口是指用Java接口来声明一些常量,然后由实现这个接口的类使用这些常量。

抽象类仅提供一个类型的部分实现。抽象类可以有实例变量,以及一个或者多个构造函数。抽象类可以同时有抽象方法和具体方法。一个抽象类不会有实例,这些构造函数不能被客户端调用来创建实例。一个抽象类的构造函数可以被其子类调用,从而使一个抽象类的所有子类都可以有一些共同的实现,而不同的子类可以在此基础上有其自己的实现。Java抽象类与Java接口一样,都用来声明一个新的类型,并且作为一个类型的等级结构的起点。但是,Java接口具有比Java抽象类更好的特性,因此,应当优先使用Java接口声明一个超类型。抽象类一定是用来继承的。Scott Meyers曾经指出,只要有可能,不要从具体类继承。在一个从抽象类到多个具体类的继承关系中,共同的代码应当尽量移动到抽象类里。而数据尽量移动到具体类中。

--------------------------------------

什么时候才应当使用继承复用?

Peter Coad认为,继承代表"一般化/特殊化"关系,其中基类代表一般,而衍生类代表特殊,衍生类将基类特殊化或者扩展化。只有当以下的Coad条件全部被满足时,才应当使用继承关系:

(1)子类是超类的一个特殊种类,而不是超类的一个角色,也就是要区分"Has-A"与"Is-A"两种关系的不同。Has-A关系应当使用聚合关系描述,而只有Is-A关系才符合继承关系。

(2)永远不会出现需要将子类换成另一个类的子类的情况。如果设计师不是很肯定一个类会不会在将来变成另一个类的子类的话,就不应当将这个类设计成当前这个超类的子类。

(3)子类具有扩展超类的责任,而不是具有置换掉(Override)或者注销掉(Nullify)超类的责任。如果子类需要大量的置换掉超类的行为,那么这个子类不应当成为这个超类的子类。

(4)只有在分类学角度上有意义时,才可以使用继承,不要从工具类继承。

--------------------------------------

在面向对象领域中,两个类之间可以发生的三种不同的耦合关系:

(1)零耦合(Nil Coupling)关系:如果两个类没有耦合关系,就称之为零耦合。

(2)具体耦合(Concrete Coupling)关系:具体性耦合发生在两个具体的(可实例化)类之间,经由一个类对另一个具体类的直接引用造成。

(3)抽象耦合(Abstract Coupling)关系:抽象耦合关系发生在一个具体类和一个抽象类(或者Java接口)之间,使两个必须发生关系的类之间存在最大的灵活性。

--------------------------------------

变量被声明时的类型叫做变量的静态类型(Static Type),有些称之为明显类型(Apparent Type),变量所引用的对象的真实类型叫做变量的实际类型(Actual Type)。如

List employees = new Vector();

employees变量的静态类型是List,而它的实际类型是Vector。

--------------------------------------

Java接口与Java抽象类的区别:

(1)这两者最明显的区别,就在于Java抽象类可以提供某些方法的部分实现,而Java接口则不可以。这大概是Java抽象类的唯一优点。如果向一个抽象类加入一个新的具体方法,那么所有的子类型就都得到了这个新的具体方法,而Java接口则做不到这一点。如果向一个Java接口加入一个新的方法的话,所有实现这个接口的类就不能全部成功地通过编译了,因为它们没有实现这个新声明的方法。这是Java接口的一个缺点。

(2)一个抽象类的实现只能由这个抽象类的子类给出,也就是说,这个实现处在抽象类所定义出的继承的等级结构中,而由于Java语言限制一个类只能从最多一个超类继承,因此将抽象类作为类型定义工具的效能大打折扣。而一个类却可以实现多个接口。

(3)从代码的重构的角度上讲,将一个单独的Java具体类重构成一个Java接口的实现是很容易的。只需要声明一个Java接口,并将重要的方法添加到接口声明中,然后在具体类定义语句后面加上一个合适的implements子句就可以了。而为一个已有的具体类添加一个Java抽象类作为抽象类型却不那么容易,因为这个具体类有可能已经有一个超类。这样一来,这个新定义的抽象类只要继续向上移动,变成这个超类的超类,如此循环,最后这个新定义的抽象类必定处于整个类型等级结构的最上端,从而使等级结构中的所有成员都会受到影响。

(4)Java接口是定义混合类型(Mixin Type)的理想工具。所谓混合类型,就是在一个类的主类型之外的次要类型。一个混合类型表明一个类不仅仅具有某个主类型的行为,而且具有其他的次要行为。

--------------------------------------

迪米特法则(LoD)的各种表述:

  • 只与你直接的朋友们通信(Only talk to your immediate friends)
  • 不要与"陌生人"说话(Don‘t talk to strangers)
  • 每一个软件单位对其他的单位都只有最少的知识,而且局限于那些与本单位密切相关的软件单位。

广义迪米特法则在类的设计上的体现:

  • 优先考虑将一个类设置成不变类
  • 尽量降低一个类的访问权限
  • 谨慎使用Serializable。一旦将一个类设置成为Serializable的,就不能再在新版本中修改这个类的内部结构,包括Private的方法和字段。
  • 尽量降低成员的访问权限

--------------------------------------

简单工厂模式(Simple Factory):是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。工厂模式有以下几种形态:

  • 简单工厂(Simple Factory)模式:又称为静态工厂方法(Static Factory Method)模式。
  • 工厂方法(Factory Method)模式:又称多态性工厂(Polymorphic Factory)模式或虚拟构造函数(Virtual Constructor)模式。
  • 抽象工厂(Abstract Factory)模式:又称工具箱模式。

简单工厂模式的结构:

public class Creator

{

      public static Product factory()

      {

            return new ConcreteProduct();

      }

}

 

public interface Product{}

public class ConcreteProduct implements Product

{

       public ConcreteProduct(){}

}

 

 

- 作者: bbhs 2005年04月9日, 星期六 19:04  回复(0) |  引用(0) 加入博采

道法自然-面向对象实践指南
《老子》中说:"人法地,地法天,天法道,道法自然"
  • 在软件开发过程中,当我们没有条件(资源、时间、技术储备等)追求完美的时候,选择简约的方案并容忍一定的缺陷才是最明智的做法
  • 需求分析是一个项目组与其他所有项目干系人共同参与的过程,在这一过程中,有效的交流与沟通最为重要。
  • 任何项目都会发生变化,程序员应当对项目过程中的需求变化做好充分准备。
  • UML语言仅仅是一种能忠实记录分析结果与设计思想的表述工具
  • 用例建模可以在不同的系统边界或不同的用例级别上进行,程序员应根据具体情况谨慎选择
  • 用例图、文字描述、顺序图等都是用例分析的有效工具

     关于面向对象的两种误解:

  • 误解一:与面向过程的设计方法相比,使用面向对象的方法设计出来的软件一定具有更高的质量
  • 误解二:只要学好Visual C++,就能精通面向对象的设计方法。

    面向对象技术鼻祖是挪威人克里斯坦.尼加德(Kristen Nygaard),他在1962年发明了颇具传奇色彩的Simula语言,并在该语言中创造出了许多沿用至今的面向对象概念。1970年前后,阿兰.凯(Alan Kay)与他的同事们在施乐(Xerox)公司发明了优雅的、纯粹的Smalltalk语言。Smalltalk提出了许多新概念,如消息和继承机制等。同样在1970年代,芭芭拉.莉丝柯夫(Barbara Liskov)使抽象数据结构的理论和实现获得了重大进展。她在LISP语言的基础上,通过增加面向对象机制,发明了著名的CLU语言,该语言支持隐藏内部数据的设计方法。此外,1980年代初期诞生的Ada语言也为面向对象技术贡献了泛型和包等重要概念。在Ada语言的基础上,格雷迪.布彻(Grady Booch)还首次提出了"面向对象设计"这一现代软件工程术语。

面向对象的基本原则:

  • 开闭原则:一个模块对扩展应是开放的,对修改应是关闭的
  • 安全替换原则:派生类应该能完全替换基类
  • 依赖倒置原则:依赖于抽象,而不要依赖于具象
  • 非循环依赖原则:包和包之间不能有循环依赖关系
  • 不要重复自己:任何代码都出现一次
  • 保持简化的设计
  • 为人写代码,而不是为机器写代码

框架和类库的区别:框架是一个"半成品"的应用程序,而类库只包含一系列可被应用程序调用的类。

类库给用户提供了一系列可复用的类,这些类的设计都符合面向对象原则和模式。用户使用时,可以创建这些类的实例,或从这些类中继承出新的派生类,然后调用类中相应的功能。在这一过程中,类库总是被动地响应用户的调用请求。

框架则会为某一特定目的实现一个基本的、可执行的架构。框架中已经包含应用了程序从启动到运行的主要流程,流程中那些无法预先确定的步骤留给用户来实现。程序运行时,框架系统自动调用用户实现的功能组件。这时,框架的行为是主动的。

类库是死的,而框架是活的。应用程序通过调用类库来完成特定的功能,而框架则通过调用应用程序来实现整个操作流程。

按照应用范围,框架可以分为以下三类:

  • 系统框架:主要用来封装系统的底层结构(包括操作系统、通信协议、用户界面等等)。降低应用程序的复杂度,提高应用程序的移植性。.Net中的应用框架、MFC框架、Java AWT等都属于系统框架的范畴。
  • 中间件框架:主要用来封装分布式系统中的通信协议、业务规则、事务模型等基本操作。中间件框架允许用户按照组件的形式来组织应用程序,使软件更易于复用和扩展,更易于在分布式环境中发布和配置。CORBA、DCOM、Java RMI、EJB等都是典型的中间件框架。
  • 企业应用框架:企业应用框架主要是为不同行业(如通信/制造/金融等)的应用开发服务的专用框架系统。开发企业应用框架的目的是封装不同行业的特殊应用逻辑,以简化企业应用程序的开发工作。

 

  • 设计模式最根本的意图是适应需求变化
  • 针对接口编程,而不要针对实现编程
  • 优先使用聚合,而不是继承

实体类(Entity Class)是应用领域中的核心类,一般是从现实世界中的实体对象归纳和抽象出来的,用于长期保存系统中的信息,以及提供针对这些信息的相关处理行为。一般情况下,实体类的对象实例和应用系统本身有着相同的生命周期。

边界类(Boundary Class)是从那些系统和外界进行交互的对象中归纳和抽象出来的,也就是说,边界类是系统内的对象和系统外的参与者的联系媒介,外界的信息只有通过边界类的对象实例才能发送给系统。

控制类(Control Class)是实体类和边界类之间的润滑剂,是从控制对象中归纳和抽象出来的,用于协调系统内边界类和实体类之间的交互。

弗兰克.布什曼(Frank Buschmann)在《面向模式的软件架构-模式系统》一书中,将架构模式定义为:架构模式描述了软件系统基本的结构组织策略。它提供了一系列预定义的职责明确的子系统,以及组织这些子系统的关系的规则和指南。

典型的架构模式:

系统软件:

  • 分层(Layer):从不同的层次来观察系统,处理不同层次问题的对象被封装到不同的层中
  • 管道和过滤器(Pipes and Filters):用数据流的观点来观察系统。整个系统由一些管道和过滤器组成,需要处理的数据通过管道传送给每一个过滤器,每个过滤器就是一个处理步骤。当数据通过了所有的过滤器后,就完成了所有的处理操作,得到了最终的处理结果。
  • 黑板(Blackboard):在这种架构中,有两种不同的构件:一种表示当前状态的中心数据结构;另一种是一组相互独立的构建,这些构件对中心数据进行操作。这种构架主要用于数据库和人工智能系统的开发。

分布式软件:

  • 经纪人(Broker):在这种架构中,客户和服务器通过一个经纪人部件进行通信,经纪人负责协调客户和服务器之间的操作,并且为客户和服务器发送请求和结果信息。CORBA就是经纪人模式的典型应用。
  • 客户/服务器(Client/Server):系统分为客户和服务器,服务器一直处于侦听的状态,客户主动连接服务器,每个服务器可以为多个客户服务
  • 点对点(Peer to Peer):系统中的节点都处于平等的地位,每个节点都可以连接其他节点。在这种架构中,一般需要由一个中心服务器完成发现和管理节点的操作。ICQ以及Web Service技术的大多数应用,都是典型的点对点结构。

交互软件:

  • 模型-视图-控制器(Model-View-Controller):当应用程序的用户界面非常复杂,且关于用户界面的需求很容易变化时,我们可以把交互类型的软件抽象成模型、视图和控制器这三类组件单元,这种抽象可以很好地分离用户界面和业务逻辑,适应变化的需求。大多数现代交互软件都在一定程度上符合这一架构模型的特点。
  • 显示-抽象-控制(Presentation-Abstraction-COntrol):这是MVC的另一种变形。

子系统和包的区别:

  • 子系统通过接口清晰的定义自己的行为,而包一般不会这样
  • 子系统完全封装了它的内部数据和操作,普通的包只是部分封装
  • 子系统很容易被替换,普通的包不太容易被替换
  • 子系统清晰地定义了接口,外部客户通过接口来访问子系统,而包一般不定义接口,外部客户可以通过一个或多个公共类来访问包。

类之间的关系:

  • 依赖关系(Dependency Relationship):依赖是一种比较弱的关系,这种使用方式可能只是以参数可见性或局部声明可见性的方式使用。在Java语言中,依赖关系可以通过import语句来指明。在UML中,用虚线箭头表示。
  • 关联关系(Association Relationship):表示在一个类ClassA的对象实例中,某个数据成员指向另一个类ClassB的对象实例,通过该数据成员,ClassA在自己的生命周期中,可以随时向ClassB的对象实例发送消息。在UML中,用实线箭头表示。在Java中,可以用如下代码实现:

        import ClassB;

        Class ClassA

       {

             public ClassB b;

       }

  • 聚合关系(Aggregation Relationship):是一种特殊的关联关系,表达的是整体和部分之间的关联。如果ClassA的对象包含一个或多个ClassB的对象,这表明ClassA和ClassB之间是聚合关系,在UML中用空心菱形加上实线箭头表示。如果ClassA的对象除了包含ClassB的对象外,还需要负责ClassB的对象的创建、维护、释放等工作-在UML语言里,这种由一个类包含另一个类的对象实例,并全面管理后者的生命周期的聚合关系也被称为组合关系(Composition Relationship),UML语言中用实心菱形加上实线箭头表示。
  • 双向关系:关联关系和聚合关系都有可能发展成双向关系,双向的关联关系既可以画成一条没有箭头的连接线,也可以画成两条表示关联关系的带箭头连接线。

设计模式的应用:

外观模式(Facade Pattern):

设计意图:外观模式可以为一个子系统中的多个类提供统一的接口。外观模式定义了一个更高层次的接口,并使一个子系统更易于使用。

观察着模式(Observer Pattern):

设计意图:

  • 定义对象之间多对一的依赖关系,也即多个对象依赖于一个对象的关系,同时保证,当被依赖的对象状态发生变化时,所有的依赖者会被自动地通知。观察着模式的另一个名称"发布-订阅模式"很好的说明了这个设计意图:被依赖的对象向外发布自己的状态,而此前订阅了该状态的所有对象都会得到通知。
  • 当一个对象需要通知另外一些对象,而你无法预知哪些对象将被通知时,通过观察者模式就可以减弱通知对象和被通知对象之间的耦合关系。
  • 当一个模块(模块A)的变化需要另一个模块(模块B)做出相应的修改,而你不知道有多少个类会被修改时,使用观察者模式就可以切断这种依赖关系,即模块A的变化不再影响模块B,模块B也无需做任何修改。换句话说,这时,模块B对模块A的依赖关系由直接依赖转变为间接依赖,具体的依赖关系是由模块A动态设定的。

实现方法实例:

import java.util.*;

Class param

{

      private int page;

      private int paragraph;

      public param(int page, int paragraph)

     {

           this.page = page;

           this.paragraph = paragraph;

      }

      public int getPage() {return page;}

      public int getParagraph() {return paragraph;}

}

Class Teacher extends Obervable

{

      public void beginRead(int page, int paragraph)

      {

           param p = new param(page, pargraph);

           notifyObervers(p);

      }

      public void notifyObervers(Object b)

      {

            setChanged();

            super.notifyObservers(b);

       }

}

Class Student implements Observer

{

      public Student (Teacher t)

      {

           t.addObserver(this);

      }

      public void read (int page, int paragraph)

      {

           //begin read

      }

      pubic void update(Observable o, Object arg)

      {

            param p = (param)arg;

            read(arg.getPage(), arg.getParagraph());

       }

}

public class Classroom

{

      public static void main(String[] args)

      {

           Teacher t = new Teacher();

           Student s[20];

           for (int i=0; i<20; i++)

                Student[i] = new Student(t);

           t.beginRead(5,2);

        }

}