软件构造(4-8讲,下半)

软件构造(4-8讲,下半)

6. Object-Oriented Programming (OOP)
Interface接口
  • 接口可以实现静态方法,使用 static 关键字。通过static关键字可以实现静态工厂方法,从而将接口的实现类封装,实现对外信息隐藏。
  • 接口中也允许使用 default 关键字来定义并实现实例方法,这个应用有点类似于抽象类的功能。
  • 通过default方法,在接口中统一实现某些功能,无需在各个类中重复实现它。
继承和重写
  • **严格继承:**子类只能添加新方法,无法重写超类中的方法。原因:父类中的方法使用了final关键字限定。

  • **重写:**子类的方法覆盖了父类的方法。重写的方法应该与父类方法有相同的签名,只有这样编译器才会判定为重写的方法。使用@Override annotation强制检查是否重写了超类中的方法。

  • 在子类中如果想调用被重写的父类的方法,可以使用super.method()。

  • 如果是在构造方法中调用父类的构造方法,则必须在构造方法的第一行调用super()。

多态
  • 多态是继封装、继承之后,面向对象的第三大特性。

  • Java作为面向对象的语言,可以描述一个事物的多种形态。如Student类继承了Person类,那么一个Student的对象便既是Student,又是Person。多态体现为父类引用变量可以指向子类对象。前提条件:必须有子父类关系。

  • 定义格式:父类类型 变量名=new 子类类型();

  • 三种多态:特殊多态、参数化多态、子类型多态

    3.多态体现为父类引用变量可以指向子类对象

    4.前提条件:必须有子父类关系。

特殊多态:功能重载

重载:多个方法具有同样的名字,但有不同的参数列表或返回值类型。参数列表必须不同,返回值类型、可见性、异常均为可以相同也可不同。重载不仅可以发生在类内,也可发生在父类与子类之间。

父类与子类之间发生重载的例子如下。这两个情况都不能编译成功,以为无论是a还是h,他们的运行时类型都是Animal,而不是通过new创建的具体类型。

class Animal{
    public void eat(){...}
}
class Horse{
    public void eat(){...}
    public void eat(String food){...}
}
//两种不能通过编译的情况
Animal a = new Animal();
a.eat("Apple");
Animal h = new Horse();
h.eat("Apple");

参数化多态:泛型

使用泛型参数代替具体的类型。作为一个泛型接口,当实现的时候可以实现一个具有具体类型的子类型,也可以实现一个具有泛型接口的实现类。泛型是jdk5才引进的,泛型其实指得就是参数化类型,使得代码可以适应多种类型。像容器,List< T >,大量使用了泛型,它的主要目的之一就是用来指定容器要持有什么类型的对象。

通配符?,只在使用泛型的时候出现,不能在定义中出现。

子类型多态

终极目的:不同类型的对象可以统一处理而无需区分。

遵循的设计原则:LSP

LSP:子类可以扩展父类的功能,但不能改变父类原有的功能;子类可以实现父的抽象方法,但不能覆盖父类的非抽象方法。(下文还有)

理解:只要父类能出现的地方,子类就可以出现,并且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但反之,未要求。

7. 等价性equals()==

等价性是基于等价关系的,满足自反、对称、传递三个性质,它的空间意义是:如果R中的多个值都对应于A中的同一个值,那么这些R值都应该是等价的。

  • 引用等价性:使用==判断地址是否相同作为判断是否等价的依据。对基本数据类型,必须使用这种办法判断是否相等。

  • 对象等价性:使用equals()方法判断两个对象是否相同法作为判断是否等价的依据,对于对象类型,使用这种办法来判断对象是否等价,如果只用==则是在判断两个对象的ID(内存里的同一空间)是否相等。

8.LSP

子类重写父类的方法应该满足的条件:

编译器在静态类型检查时强制满足的条件

子类型可以增加方法,但不可删除
子类型需要实现抽象类型中的所有未实现方法
子类型中重写的方法返回值必须与父类相同或符合co-variance(协变)
子类型中重写的方法必须使用同样类型的参数或者符合contra-variance(逆变)的参数
子类型中重写的方法不能抛出额外的异常

还应该满足的条件

更强的不变量 (RI)
更弱的前置条件
更强的后置条件

9.协变

关于返回值的类型,应该保持不变或者变得更具体,也就是与派生的方向一致。

所抛出的异常的类型也是如此。

class T {
	Object a() {}
    void b() throws Throwable {}
}
class S extends T {
	@Override //返回值从Object协变成了String,这是符合重写的语法的
	String a() {}
    @Override //抛出的异常从Throwable协变成了IOException,这也是符合重写的语法的
	void b() throws IOException {}	
}

10. 逆变

关于参数的类型,应该保持不变或者变得更抽象,也就是与派生的方向相反。

class T {
	void c(String s) {}
}
class S extends T {
	@Override //虽然按照LSP这是合法的,但是在java语法中,不当作override,而是overload
	void c(Object s) {}
}

11. 委派

1.Dependency:依赖关系,临时性的delegation。把被delegation的对象以参数方式传入。只有在需要的时候才建立与被委派类的联系,而当方法结束的时候这种关系也就随之断开了。

//如果要让鸭子用其他方式叫(或飞)只需更换new的q(f)的类型即可
Flyable f = new FlyWithWings();	//使用翅膀飞行的飞行方式
Quackable q = new Quack();	//鸭叫声的叫声
Duck d = new Duck(); //一只鸭子
d.fly(f); //让鸭子飞
d.quack(q);	//让鸭子叫

class Duck {
	//no field to keep Flyable object
	public void fly(Flyable f) { f.fly(); } //让这个鸭子以f的方式飞
   public void quack(Quackable q) { q.quack() }; //让鸭子以q的方式叫
}

2.Association:关联关系,永久性的delegation。被delegation的对象保存在rep中,该对象的类型被永久的与此ADT绑定在了一起。

//法一:在构造方法中传入参数绑定
Flyable f = new FlyWithWings();
Duck d = new Duck(f);
d.fly();
class Duck {
	Flyable f; //这个必须由构造方法传入参数绑定
	public Duck(Flyable f) { this.f = f; }
   public void fly(){ f.fly(); }
}
//法二:在rep或构造方法中直接写死
Duck d = new Duck();
d.fly();
class Duck {
   //这两种实现方式的效果是相同的
	Flyable f = new FlyWithWings(); //写死在rep中
	public Duck() { f = new FlyWithWings(); } //写死在构造方法中
	public void fly(){ f.fly(); }
}

3.Composition: 更强的association,但难以变化。也就是Association中的法二。

4.Aggregation: 更弱的association,可动态变化。也就是Association中的法一。

12.框架
  • 黑盒框架:通过实现特定接口进行框架扩展,采用的是delegation机制达到这种目的,通常采用的设计模式是策略模式(Strategy)和观察者模式(Observer)
  • 白盒框架:通过继承和重写实现功能的扩展,通常的设计模式是模板模式(Template Method)。

白盒框架所执行的是框架所写好的代码,只有通过override其方法来实现新的功能,客户端启动的的是第三方开发者派生的子类型。黑盒框架并不是这样,黑盒所预留的是一个接口,在框架中只调用接口中的方法,而接口中方法的实现就依据派生出的子类型的不同而不同,它的客户端启动的就是框架本身。

白盒:

public abstract class Application extends JFrame {
    //这些抽象方法就是为了实现不同的部分而设计的
	abstract protected String getApplicationTitle();
	abstract protected String getButtonText();
	abstract protected String getInitialText();
	abstract protected void buttonclicked();
	private JTextField textField;
	public Application() {
		JPanel contentPane = new JPanel(new borderLayout());
		contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED))
		JButton button = new JButton();
        button.setText(getButtonText());
        contentPane.add(button, borderLayout.EAST);
        textField = new JTextField("");
        textField.setText(getInitialText());
        textField.setPreferredsize(new Dimension(200, 20));
        contentPane.add(textField, BorderLayout.WEST);
        button.addActionListener((e)->{ buttonclicked(); });
        this.setContentPane(contentPane);
        this.pack();
        this.setTitle(getApplicationTitle());
        ...
    }
}
//使用
public class Calculator extends Application {
    //重写了框架中的四个抽象方法
	protected String getApplicationTitle() { return "My Great Calculator"; }
    protected String getButtonText() { return "calculate"; }
    protected String getInititalText() { return "(10-3)*6"; }
    protected void buttonClicked() {
        JOptionPane.showMessageDialog(this, "the result of " + getInput() + "is" + calculate(getInput()));
    }
	private String calculate(String text) {...}
}

黑盒:

public class Application extends JFrame {
	private JTextField textField;
	private Plugin plugin;
	public Application() { }
	protected void init(Plugin p) {
		p.setApplication(this);
		this.plugin = p;
		JPanel contentPane = new JPanel(new BorderLayout());
        contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED));
        JButton button = new JButton();
        button.setText(plugin != null ? plugin.getButtonText() : "ok");
        contentPane.add(button, BorderLayout.EAST);
        textField = new JTextField("");
        if (plugin != null) textField.setText(plugin.getInititalText());
        textField.setPreferredSize(new Dimension(200, 20));
        contentPane.add(textField, BorderLayout.WEST);
        if (plugin != null) button.addActionListener((e) -> { plugin.buttonClicked(); });
        this.setContentPane(contentPane);
        ...
    }
    public String getInput() { return textField.getText(); }
}
public interface Plugin {
    public String getApplicationTitle();
    public String getButtonText();
    public String getInititalText();
    public void buttonClicked();
    public void setApplication(Application app);
}
//使用,实现Plugin接口
public class CalcPlugin implements Plugin {
    private Application app;
    public void setApplication(Application app) { this.app = app; }
    public String getButtonText() { return "calculate"; }
    public String getInititalText() { return "10/2+6"; }
    public void buttonClicked() {
        JOptionPane.showMessageDiaLog(null, "The result of" + application.getInput() + "is" + calculate(application.getInput()));
    }
    public String getApplicationTitle() { return "My Great Calculator"; }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基本信息 原书名: Design Patterns:Elements of Reusable Object-Oriented software 原出版社: Addison Wesley/Pearson 作者: (美)Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides [作译者介绍] 译者: 李英军 马晓星 蔡敏 刘建中 丛书名: 计算机科学丛书 出版社:机械工业出版社 ISBN:7111075757 上架时间:2005-7-19 出版日期:2004 年9月 开本:16开 页码:254 版次:1-11 内容简介   本书结合设计实例从面向对象的设计中精选出23个设计模式,总结了面向对象设计中最有价值的经验,并且用简洁可复用的形式表达出来。本书分类描述了一组设计良好、表达清楚的软件设计模式,这些模式在实用环境下特别有用。本书适合大学计算机专业的学生、研究生及相关人员参考。       [strong][font color="#ff0000"]书评[/font][/strong][font color="#ff0000"]       “这本众人期待的确达到了预期的全部效果。该书云集了经过时间考验的可用设计。作者从多年的面向对象设计经验中精选了23个模式,这构成了该书的精华部份,每一个精益求精的优秀程序员都应拥有这本《设计模式》。”--larry o'brien, software development       “[设计模式]在实用环境下特别有用,因为它分类描述了一组设计良好,表达清楚的面向对象软件设计模式。整个设计模式领域还很新,本书的四位作者也许已占据了这个领域造诣最深的专家中的半数,因而他们定义模式的方法可以作为后来者的榜样。如果要知道怎样恰当定义和描述设计模式,我们应该可以从他们那儿获得启发”--steve billow, journal of object-oriented programming       “总的来,这本书表达了一种极有价值的东西。对软件设计领域有着独特的贡献,因为它捕获了面向对象设计的有价值的经验,并且用简洁可复用的形式表达出来。它将成为我在寻找面向对象设计思想过程中经常翻阅的一本书﹕这正是复用的真实含义所在,不是吗﹖”--sanjiv gossain, journal of object-oriented programming [/font] 目 录 序言 前言 读者指南 第1章 引言 1 1.1 什么是设计模式 2 1.2 smalltalk mvc中的设计模式 3 1.3 描述设计模式 4 1.4 设计模式的编目 5 1.5 组织编目 7 1.6 设计模式怎样解决设计问题 8 1.6.1 寻找合适的对象 8 1.6.2 决定对象的粒度 9 1.6.3 指定对象接口 9 1.6.4 描述对象的实现 10 1.6.5 运用复用机制 13 1.6.6 关联运行时刻和编译时刻的 结构 15 1.6.7 设计应支持变化 16 1.7 怎样选择设计模式 19 .1.8 怎样使用设计模式 20 第2章 实例研究:设计一个文档编 辑器 22 2.1 设计问题 23 2.2 文档结构 23 2.2.1 递归组合 24 2.2.2 图元 25 2.2.3 组合模式 27 2.3 格式化 27 2.3.1 封装格式化算法 27 2.3.2 compositor和composition 27 2.3.3 策略模式 29 2.4 修饰用户界面 29 2.4.1 透明围栏 29 2.4.2 monoglyph 30 2.4.3 decorator 模式 32 2.5 支持多种视感标准 32 2.5.1 对象创建的抽象 32 2.5.2 工厂类和产品类 33 2.5.3 abstract factory模式 35 2.6 支持多种窗口系统 35 2.6.1 我们是否可以使用abstract factory 模式 35 2.6.2 封装实现依赖关系 35 2.6.3 window和windowimp 37 2.6.4 bridge 模式 40 2.7 用户操作 40 2.7.1 封装一个请求 41 2.7.2 command 类及其子类 41 2.7.3 撤消和重做 42 2.7.4 命令历史记录 42 2.7.5 command 模式 44 2.8 拼写检查和断字处理 44 2.8.1 访问分散的信息 44 2.8.2 封装访问和遍历 45 2.8.3 iterator类及其子类 46 2.8.4 iterator模式 48 2.8.5 遍历和遍历过程中的动作 48 2.8.6 封装分析 48 2.8.7 visitor 类及其子类 51 2.8.8 visitor 模式 52 2.9 小结 53 第3章 创建型模式 54 3.1 abstract factory(抽象工厂)— 对象创建型模式 57 3.2 builder(生成器)—对象创建型 模式 63 3.3 factory method(工厂方法)— 对象创建型模式 70 3.4 prototype(原型)—对象创建型 模式 87 3.5 singleton(单件)—对象创建型 模式 84 3.6 创建型模式的讨论 89 第4章 结构型模式 91 4.1 adapter(适配器)—类对象结构型 模式 92 4.2 bridge(桥接)—对象结构型 模式 100 4.3 composite(组成)—对象结构型 模式 107 4.4 decorator(装饰)—对象结构型 模式 115 4.5 facade(外观)—对象结构型 模式 121 4.6 flyweight(享元)—对象结构型 模式 128 4.7 proxy(代理)—对象结构型 模式 137 4.8 结构型模式的讨论 144 4.8.1 adapter与bridge 144 4.8.2 composite、decorator与proxy 145 第5章 行为模式 147 5.1 chain of responsibil ity(职责链) —对象行为型模式 147 5.2 command(命令)—对象行为型 模式 154 5.3 interpreter(解释器)—类行为型 模式 162 5.4 iterator(迭代器)—对象行为型 模式 171 5.5 mediator(中介者)—对象行为型 模式 181 5.6 memento(备忘录)—对象行为型 模式 188 5.7 observer(观察者)—对象行为型 模式 194 5.8 state(状态)—对象行为型模式 201 5.9 strategy(策略)—对象行为型 模式 208 5.10 template method(模板方法) —类行为型模式 214 5.11 visitor(访问者)—对象行为型 模式 218 5.12 行为模式的讨论 228 5.12 1 封装变化 228 5.12.2 对象作为参数 228 5.12.3 通信应该被封装还是被分布 229 5.12.4 对发送者和接收者解耦 229 5.12.5 总结 231 第6章 结论 232 6.1 设计模式将带来什么 232 6.2 一套通用的设计词汇 232 6.3 书写文档和学习的辅助手段 232 6.4 现有方法的一种补充 233 6.5 重构的目标 233 6.6 本书简史 234 6.7 模式界 235 6.8 alexander 的模式语言 235 6.9 软件中的模式 236 6.10 邀请参与 237 6.11 临别感想 237 附录a 词汇表 238 附录b 图示符号指南 241 附录c 基本类 244 参考文献 249   前 言      本书并不是一本介绍面向对象技术或设计的书,目前已有不少好书介绍面向对象技术或设计。本书假设你至少已经比较熟悉一种面向对象编程语言,并且有一定的面向对象设计经验。当我们提及“类型”和“多态”,或“接口”继承与“实现”继承的关系时,你应该对这些概念了然于胸,而不必迫不及待地翻阅手头的字典。      另外,这也不是一篇高级专题技术论文,而是一本关于设计模式的书,它描述了在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。设计模式捕获了随时间进化与发展的问题的求解方法,因此它们并不是人们从一开始就采用的设计方案。它们反映了不为人知的重新设计和重新编码的成果,而这些都来自软件开发者为了设计出灵活可复用的软件而长时间进行的艰苦努力。设计模式捕获了这些解决方案,并用简洁易用的方式表达出来。      设计模式并不要求使用独特的语言特性,也不采用那些足以使你的朋友或老板大吃一惊的神奇的编程技巧。所有的模式均可以用标准的面向对象语言实现,这也许有时会比特殊的解法多费一些功夫,但是为了增加软件的灵活性和可复用性,多做些工作是值得的。      一旦你理解了设计模式并且有了一种“Aha!”(而不是“Huh?”)的应用经验和体验后,你将用一种非同寻常的方式思考面向对象设计。你将拥有一种深刻的洞察力,以帮助你设计出更加灵活的、模块化的、可复用的和易理解的软件—这也是你为何着迷于面向对象技术的源动力,不是吗?      当然还有一些提示和鼓励:第一次阅读此书时你可能不会完全理解它,但不必着急,我们在起初编写这本书时也没有完全理解它们!请记住,这不是一本读完一遍就可以束之高阁的书。我们希望你在软件设计过程中反复参阅此书,以获取设计灵感。      我们并不认为这组设计模式是完整的和一成不变的,它只是我们目前对设计的思考的记录。因此我们欢迎广大读者的批评与指正,无论从书中采用的实例、参考,还是我们遗漏的已知应用,或应该包含的设计模式等方面。你可以通过Addison-Wesley写信给我们,或发送电子邮件到:[email protected]。你还可以发送邮件“send design pattern source”到[email protected]获取书中的示例代码部分的源代码。      另外我们有一个专门的网页报道最新的消息与更新:      http://st-www.cs.uiuc.edu/users/patterns/DPBook/DPBook.html.      E.G. 于加州Mountain View    .  R.H. 于蒙特利尔      R.J. 于伊利诺Urbana      J.V. 于纽约 Hawthorne      1994年8月    序言    所有结构良好的面向对象软件体系结构中都包含了许多模式。实际上,当我评估一个面向对象系统的质量时,所使用的方法之一就是要判断系统的设计者是否强调了对象之间的公共协同关系。在系统开发阶段强调这种机制的优势在于,它能使所生成的系统体系结构更加精巧、简洁和易于理解,其程度远远超过了未使用模式的体系结构。    模式在构造复杂系统时的重要性早已在其他领域中被认可。特别地,Christopher Alexander和他的同事们可能最先将模式语言(pattern language)应用于城市建筑领域,他的思想和其他人的贡献已经根植于面向对象软件界。简而言之,软件领域中的设计模式为开发人员提供了一种使用专家设计经验的有效途径。    在本书中,Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides介绍了设计模式的原理,并且对这些设计模式进行了分类描述。因此,该书做出了两个重要的贡献:首先,它展示了模式在建造复杂系统过程中所处的角色;其次,它为如何引用一组精心设计的模式提供了一个实用方法,以帮助实际开发者针对特定应用问题使用适当的模式进行设计。    我曾荣幸地有机会与本书的部分作者一同进行体系结构设计工作,从他们身上我学到了许多东西,并相信通过阅读该书你同样也会受益匪浅。    Rational 软件公司首席科学家 Grady Booch

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值