软件构造笔记四:考前学习(预习)设计模式

缘起

出现各种各样设计模式的原因,还是为了达到软件系统的质量要求。

软件系统的外部质量因素包括:

External 1: Correctness(正确性),正确就是满足spec,这是软件开发最重要的因素,一个可用的软件一定是正确的,所以首要保证软件的正确性,其他的都可以做妥协、让步,但只有这一项不可妥协。

External 2: Robustness(健壮性),通过抛出异常然后处理异常等方式让出错的程序恢复到正常的执行流程上。

External 3: Extendibility(易扩展性),要便于软件功能的增加/扩展(ADT、OOP、留下一个Visitor),降低未来修改软件时的成本。

External 4: Reusability(复用性),在异性之间尽可能地寻找共性,以便于未来可以直接使用现在写的这段代码。这样可以降低软件地开发成本。

External 5: Compatibility(兼容性),在不同的环境下都是可用的,不同的软件系统之间相互可容易的集成。

External 6: Efficiency(效率),不要过早的优化,性能在没有正确性保障的条件下是没有意义的。

External 7: Portability(可移植性),软件可方便的在不同的技术环境之间移植。

External 8: Ease of use(易用性),学习成本低,结构简单、清晰,易于使用。

External 9: Functionality(功能性),功能过多会导致易用性的降低。主要功能要首要提升质量。

External 10: Timeliness(时效性),软件要能够在交付时间之前完成开发交给使用者。

External 10++: Other qualities,Verifiability (可验证性),Integrity (完整性),Repairability (可修复性),Economy (经济性)。

针对这些外部质量因素就会有相应的设计模式出现。

面向复用性

继承与LSP

对子类型的要求:
Preconditions cannot be strengthened in a subtype. 前置条件不能强化
Postconditions cannot be weakened in a subtype. 后置条件不能弱化
Invariants of the supertype must be preserved in a subtype. 不变量要保持
Contravariance of method arguments in a subtype 子类型方法参数:逆变
Covariance of return types in a subtype. 子类型方法的返回值:协变
No new exceptions should be thrown by methods of the subtype, except where those exceptions are themselves subtypes of exceptions thrown by the methods of the supertype. 异常类型:协变

关键字 extends

class T {
void b( ) throws Throwable {}
}
class S extends T {
@Override 
void b( ) throws IOException {}
}
class U extends S {
@Override 
void b( ) {}
} 

委托

发生在对象层次,一个对象向另一个对象请求方法。

class RealPrinter {
void print() {
System.out.println("The Delegate");
}
}
class Printer {
RealPrinter p = new RealPrinter();
void print() {
p.print();
}
}
Printer printer = new Printer();
printer.print();

Dependency:临时性的delegation,通过方法的参数或者在方法的局部中使用发生
联系。
Association:永久性的delegation,将被委托的对象绑定在委托者类内部,在类内创建,但不定义。
Composition:更强的association,但难以变化,直接在委托者类内部定义被委托者。
Aggregation:更弱的association,可动态变化,对象存在于另一个对象之外,是在另一个对象之外创建的,所以它作为一个参数传递给构造器。

组合

继承和委托组合起来。

面向可维护性

SOLID:
▪ 抽象(abstraction):模块之间通过抽象隔离开来,将稳定部分和容易
变化部分分开
– LSP:对外界看来,父类和子类是“一样”的;
– DIP:对接口编程,而不是对实现编程,通过抽象接口隔离变化;
– OCP:当需要变化时,通过扩展隐藏在接口之后的子类加以完成,而不要修
改接口本身。
▪ 分离(Separation): Keep It Simple, Stupid (KISS)
– SRP:按责任将大类拆分为多个小类,每个类完成单一职责,规避变化,提
高复用度;
– ISP:将接口拆分为多个小接口,规避不必要的耦合。

面向可复用性和可维护性的设计模式

工厂方法模式

当client不知道/不确定要创建哪个具体类的实例,或者不想在client代码中指明要具体创建的实例时,用工厂方法。定义一个用于创建对象的接口,让该接口的子类型来决定实例化哪一个类,从而使一个类的实例化延迟到其子类。
将构造器设为接口,用接口实现类中的工厂方法构造对象。使用时不会一次性完成对象的构造,而是一条一条调用工厂方法构造对象。

适配器模式

通过增加一个接口,将已存在的子类封装起来,client面向接口编程,从而隐藏了具体子类。

interface Shape {
void display(int x1, int y1, int x2, int y2);
}
class Rectangle implements Shape {
void display(int x1, int y1, int x2, int y2) {
new LegacyRectangle().display(x1, y1, x2-x1, y2-y1); 
}
}
class LegacyRectangle {
void display(int x1, int y1, int w, int h) {...}
}
class Client {
Shape shape = new Rectangle();
public display() {
shape.display(x1, y1, x2, y2);
}
}

装饰器模式

为对象增加不同侧面的特性,对每一个特性构造子类,通过委派机制增加到对象上。自身委派自身。

interface Stack {
void push(Item e);
Item pop();
}
public abstract class StackDecorator implements Stack {
protected final Stack stack;
public StackDecorator(Stack stack) {
this.stack = stack;
}
public void push(Item e) {
stack.push(e);
}
public Item pop() {
return stack.pop();
}
...
}
public class UndoStack extends StackDecorator {
private final UndoLog log = new UndoLog();
public UndoStack(Stack stack) { 
super(stack); 
}
public void push(Item e) {
super.push(e);
log.append(UndoLog.PUSH, e);
}
public void undo() {
//implement decorator behaviors on stack
}
...
}

构造对象时,

To construct a plain stack:
– Stack s = new ArrayStack();
▪ To construct an undo stack:
– Stack t = new UndoStack(new ArrayStack());
▪ To construct a secure synchronized undo stack:
– Stack t = new SecureStack(
new SynchronizedStack(
new UndoStack(s))
t.push(e);

又一个例子:

public class Client {
public static void main(String[] args) {
IceCream a = new PlainIceCream(); 
IceCream b = new CandyTopping(a); 
IceCream c = new PeanutTopping(b); 
IceCream d = new NutsTopping(c); 
d.AddTopping();
//or
IceCream toppingIceCream = 
new NutsTopping(
new PeanutTopping(
new CandyTopping(
new PlainIceCream()
)
)
);
toppingIceCream.AddTopping();
}

策略模式

为不同的实现算法构造抽象接口,利用delegation,运行时动态传入client倾向的算法类实例。

public interface PaymentStrategy {
public void pay(int amount);
}
public class CreditCardStrategy implements PaymentStrategy {
private String name;
private String cardNumber;
private String cvv;
private String dateOfExpiry;
public CreditCardStrategy(String nm, String ccNum, 
String cvv, String expiryDate){
this.name=nm;
this.cardNumber=ccNum;
this.cvv=cvv;
this.dateOfExpiry=expiryDate;
}
@Override
public void pay(int amount) {
System.out.println(amount +" paid with credit card");
}
}
public class PaypalStrategy implements PaymentStrategy {
private String emailId;
private String password;
public PaypalStrategy(String email, String pwd){
this.emailId=email;
this.password=pwd;
}
@Override
public void pay(int amount) {
System.out.println(amount + " paid using Paypal.");
}
}
public class ShoppingCart {
...
public void pay(PaymentStrategy paymentMethod){
int amount = calculateTotal();
paymentMethod.pay(amount);
}
}

模板模式

共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现。模板方法定义了一个算法的步骤,并允许子类为一个或多个步骤提供实现。使用继承和重写实现模板模式。
在使用方法时换引用,调整引用顺序,调用不同方法。
抽象类+具体实现子类

迭代模式

让自己的集合类实现Iterable接口,并实现自己的独特Iterator迭代器(hasNext, next, remove),允许客户端利用这个迭代器进行显式或隐式的迭代遍历。

Visitor

对特定类型object的特定操作(visit),在运行时将二者动态绑定到一起,该操作可以灵活更改,无需更改被visit的类。

public interface ItemElement {
public int accept(ShoppingCartVisitor visitor);
}
/* Concrete element */
public class Book implements ItemElement{
private double price;
...
int accept(ShoppingCartVisitor visitor) {
visitor.visit(this);
}
}
public class Fruit implements ItemElement{
private double weight;
...
int accept(ShoppingCartVisitor visitor) {
visitor.visit(this);
}
}

定义接收方法,与访问方法相对应。

总结

迭代器理解得最差,觉得设计模式选好能解决很大的问题。不同情况使用不同的设计模式,能省去很多不必要的空间、时间、删改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值