哈工大软件构造课程知识点总结(六)

系列文章目录

哈工大软件构造课程知识点总结(一)
哈工大软件构造课程知识点总结(二)
哈工大软件构造课程知识点总结(三)
哈工大软件构造课程知识点总结(四)
哈工大软件构造课程知识点总结(五)
哈工大软件构造课程知识点总结(六)



简介

此文章是2021春哈工大软件构造课程Chapter 11、Chapter 12的知识点总结。

Chapter 11:Design Patterns for Reuse and Maintainability

设计模式的划分

除了类本身,设计模式更强调多个类/对象之间的关系和交互过程,比接口/类复用的粒度更大。

  • 创建型模式(Creational patterns)
    • 工厂方法模式(Factory method pattern):在不指定具体类的情况下创建对象。
  • 结构型模式(Structural patterns)
    • 适配器模式(Adapter):允许具有不兼容接口的类通过将自己的接口包装在已经存在的类的接口上来实现协同工作。
    • 装饰模式(Decorator):动态添加/重写对象中方法的行为
  • 行为类模式(Behavioral patterns)
    • 策略模式(Strategy):允许在运行时选择一系列算法中的一个
    • 模板模式(Template method):在抽象类中定义一个算法的框架,允许它的子类提供具体行为实现
    • 迭代器模式(Iterator):顺序地访问一个对象中的元素同时避免泄露其内部表示
    • 访问者模式(Visitor):通过将方法的层次结构移动到一个对象中,将算法(具体实现)与对象结构分开

创建型模式

工厂方法模式

工厂方法也称为虚拟构造器,当客户端不知道要创建哪个具体类的实例,或者不想在客户端代码中指明要具体创建的实例时使用。通过定义一个用于创建对象的接口,让其子类来决定实例化哪一个类,从而使一个类的实例化延迟到其子类。

示意图:
工厂方法模式
代码示例:

/* Abstract product 具体类的接口 */
public interface Trace {
	// turn on and off debugging
	public void setDebug( boolean debug );
	// write out a debug message
	public void debug( String message );
	// write out an error message
	public void error( String message );
}

/* Concrete product 1 具体类1 */
public class FileTrace implements Trace { 
	private PrintWriter pw;
	private boolean debug;
	public FileTrace() throws IOException {
		pw = new PrintWriter( new FileWriter( "t.log" ) );
	}
	public void setDebug( boolean debug ) {
		this.debug = debug;
	}
	public void debug( String message ) {
		if( debug ) {
			pw.println( "DEBUG: " + message );
			pw.flush();
		}
	}
	public void error( String message ) {
		pw.println( "ERROR: " + message );
		pw.flush();
	}
}

/* Concrete product 2 具体类2 */
public class SystemTrace implements Trace {
	private boolean debug;
	public void setDebug( boolean debug ) {
		this.debug = debug;
	}
	public void debug( String message ) {
		if( debug ) 
		System.out.println( "DEBUG: " + message );
	}
	public void error( String message ) {
		System.out.println( "ERROR: " + message );
	}
}

/* 工厂创建对象接口 */
interface TraceFactory {
	public Trace getTrace();
	public Trace getTrace(String type);
	void otherOperation() {}; // 不仅可以包含工厂方法,还可以实现其他功能
}

/* 工厂类1 */
public class Factory1 implements TraceFactory {
	public Trace getTrace() { // 创建SystemTrace类
		return new SystemTrace();
	}
}

/* 工厂类2 */
public class Factory2 implements TraceFactory {
	public getTrace(String type) { // 根据类型决定创建哪个具体产品
		if(type.equals(“file”)
			return new FileTrace();
		else if (type.equals(“system”)
			return new SystemTrace();
	}
}

/* 客户端代码 */
// 客户端使用“工厂方法”来创建实例
Trace log1 = new Factory1().getTrace();
log1.setDebug(true);
log1.debug( "entering log" );
Trace log2 = new Factory2().getTrace("system");
log2.setDebug(false);
log2.debug("...");

除此之外还有静态工厂方法,既可以在ADT内部实现,也可以构造单独的工厂类。

优点:

  • 消除在代码中绑定应用特定类的需求
  • 代码仅关注接口类(如例中的Trace),所以它可以与任何用户定义的具体类(如例中的FileTrace、SystemTrace)协同工作

潜在缺点:

  • 客户端可能不得不创建一个Creator的子类以创建具体类对象
  • 面对软件演化问题(OCP原则——对扩展开放,对修改已有代码封闭 ?)

结构型模式

适配器模式

适配器模式的目的是将某个类/接口转换为客户端期望的其他形式。通过增加一个接口,将已存在的子类封装起来,客户端面向接口编程,从而隐藏了具体子类。

示意图:
适配器模式
示例代码:

/* 原方法实现 */
class LegacyRectangle {
	// 参数为左下角坐标、宽、高
	void display(int x1, int y1, int w, int h) {...}
}

/* Adapter类实现抽象接口 */
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 Client {
	// 对抽象接口编程,与LegacyRectangle隔离
	Shape shape = new Rectangle();
	public display() {
		shape.display(x1, y1, x2, y2);
	}
}

装饰器模式

装饰器模式通过继承委托实现特性的任意组合,避免组合爆炸和大量重复。对每一个特性构造子类,通过委派机制增加到对象上。

示例代码:

interface Stack {
	void push(Item e);
	Item pop();
}

/* 实现最基础的stack功能 */
public class ArrayStack implements Stack {
	... //rep
	public ArrayStack() {...}
	public void push(Item e) {
		...
	}
	public 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
		implements Stack {
	private final UndoLog log = new UndoLog();
	public UndoStack(Stack stack) { 
		super(stack); 
	}
	public void push(Item e) {
		log.append(UndoLog.PUSH, e); // 增加新特性
		super.push(e); // 基础功能通过委托实现
	}
	public void undo() {
		//implement decorator behaviors on stack
	}
	...
}

/* 具体使用 */
// 创建一个stack
Stack s = new ArrayStack();
// 创建一个undo stack
Stack t = new UndoStack(new ArrayStack());
// 继续装饰,得到secure synchronized undo stack
Stack u = new SecureStack(new SynchronizedStack(new UndoStack(s)));

装饰器在运行时组合功能特性,包含多个协作的对象且能够混合和匹配多层装饰。这些都是使用继承难以做到的。

Java Collections提供的unmodifiableList等是通过装饰器模式实现的。

行为类模式

策略模式

策略模式通过为不同的实现算法构造抽象接口,利用delegation,运行时动态传入client倾向的算法类实例来实现动态切换算法,而不是写死在代码里。

示意图:
策略模式
代码示例:

/* 抽象接口 */
public interface PaymentStrategy {
	public void pay(int amount);
}

/* 具体实现1 */
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");
	}
}

/* 具体实现2 */
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);
	}
}

/* 客户端代码 */
ShoppingCart cart = new ShoppingCart();
Item item1 = new Item("1234",10);
Item item2 = new Item("5678",40);
cart.addItem(item1);
cart.addItem(item2);
//pay by paypal
cart.pay(new PaypalStrategy("myemail@exp.com", "mypwd"));
//pay by credit card
cart.pay(new CreditCardStrategy(“Alice", "1234", "786", "12/18"));

模板模式

模板模式使用继承重写实现。做事情的步骤一样,但具体方法不同,共性的步骤在抽象类内公共实现,差异化的步骤在各个子类中实现。

代码示例:

/* 模板类 */
public abstract class OrderProcessTemplate {
	public boolean isGift;
	public abstract void doSelect(); // 差异化步骤
	public abstract void doPayment(); // 差异化步骤
	public final void giftWrap() {
		System.out.println("Gift wrap done.");
	}
	public abstract void doDelivery(); // 差异化步骤
	public final void processOrder() {
		doSelect();
		doPayment();
		if (isGift)
			giftWrap();
		doDelivery();
	}
}

/* 具体类 */
public class NetOrder
		extends OrderProcessTemplate {
	@Override
	public void doSelect() {}
	@Override
	public void doPayment() {}
	@Override
	public void doDelivery() {}
}

/* 客户端代码 */
OrderProcessTemplate netOrder = new NetOrder();
netOrder.processOrder();
OrderProcessTemplate storeOrder = new StoreOrder();
storeOrder.processOrder();

迭代器模式

迭代器模式针对的是客户端遍历被放入容器/集合类的一组ADT对象,同时无需关心容器的具体类型的需求。通过让自己的集合类实现Iterable接口,并实现自己的独特Iterator迭代器(hasNext, next, remove),允许客户端利用这个迭代器进行显式或隐式的迭代遍历。

示意图:
迭代器模式

示例代码:

public class Pair<E> implements Iterable<E> {
	private final E first, second;
	public Pair(E f, E s) { first = f; second = s; }
	public Iterator<E> iterator() {
		return new PairIterator();
	}

	private class PairIterator implements Iterator<E> {
		private boolean seenFirst = false, seenSecond = false;
		public boolean hasNext() { return !seenSecond; }
		public E next() {
			if (!seenFirst) { seenFirst = true; return first; }
			if (!seenSecond) { seenSecond = true; return second; }
			throw new NoSuchElementException();
		}
		public void remove() {
			throw new UnsupportedOperationException();
		}
	}
}

访问者模式

访问者模式将数据和作用在数据上的某种(或某些)特定操作分离开来,运行时进行动态绑定、灵活更改而无需修改被访问的类。通过为ADT预留一个将来可扩展功能的“接入点”,外部实现的功能代码可以在不改变ADT本身的情况下通过委托接入ADT。

示意图:
访问者模式
示例代码:

/* 元素的抽象接口 */
public interface ItemElement {
	public int accept(ShoppingCartVisitor visitor);
}

/* 具体元素类 */
public class Book implements ItemElement{
	private double price;
	...
	// 将处理数据的功能委托给外部传入的visitor
	@Override
	public int accept(ShoppingCartVisitor visitor) {
		return visitor.visit(this);
	}
}
public class Fruit implements ItemElement{
	private double weight;
	...
	int accept(ShoppingCartVisitor visitor) {
		return visitor.visit(this);
	}
}

/* visitor实现 */
public class ShoppingCartVisitorImpl implements ShoppingCartVisitor {
	public int visit(Book book) {
		int cost=0;
		if(book.getPrice() > 50){
			cost = book.getPrice()-5;
		}else 
			cost = book.getPrice();
		System.out.println("Book ISBN::"+book.getIsbnNumber() + " cost ="+cost);
		return cost;
	}
	public int visit(Fruit fruit) {
		int cost = fruit.getPricePerKg()*fruit.getWeight();
		System.out.println(fruit.getName() + " cost = "+cost);
		return cost;
	}
}

/* 客户端代码 */
public static void main(String[] args) {
	ItemElement[] items = new ItemElement[]{
			new Book(20, "1234"),new Book(100, "5678"),
			new Fruit(10, 2, "Banana"), new Fruit(5, 5, "Apple")};
	int total = calculatePrice(items);
	System.out.println("Total Cost = "+total);
}

private static int calculatePrice(ItemElement[] items) {
	// 若有多个visitor的具体实现,只需在此处切换
	ShoppingCartVisitor visitor = new ShoppingCartVisitorImpl();
	int sum=0;
	for(ItemElement item : items)
		sum = sum + item.accept(visitor);
	return sum;
}

访问者模式与迭代器模式的对比

  • 二者都是通过委托建立两个对象的动态联系。
  • 访问者模式强调的是外部定义某种对ADT的操作,该操作于ADT自身关系不大(只是访问ADT),故ADT内部只需要开放accept(visitor)即可,客户端通过它设定visitor操作并在外部调用。
  • 策略模式强调对ADT内部某些要实现的功能的相应算法的灵活替换。这些算法是ADT功能的重要组成部分,只不过是委托到到外部strategy类而已。
  • 访问者模式是站在外部客户端的角度,灵活增加对ADT的各种不同操作(哪怕ADT没实现该操作),策略模式则是站在内部ADT的角度,灵活变化对其内部功能的不同配置。

Chapter 12:Construction for Robustness and Correctness

健壮性和正确性

相关概念

健壮性:系统在不正常输入或不正常外部环境下仍能够表现正常的程度。要求我们封闭实现细节,限定用户的恶意行为并考虑极端情况。让用户变得更容易:出错也可以容忍,程序内部已有容错机制。
正确性:程序按照spec加以执行的能力,是最重要的质量指标。让开发者变得更容易:用户输入错误,直接结束(不满足precondition的调用)。

正确性倾向于直接报错(error),健壮性则倾向于容错(fault-tolerance)。
对外的接口倾向于健壮;对内的实现倾向于正确。

可靠性 = 健壮性 + 正确性

如何衡量

  • 平均失效间隔时间(Mean time between failures, MTBF)——外部观察角度
  • 残余缺陷率(Residual defect rates)——内部观察角度

Java中的错误(Error)与异常(Exception)

异常与错误
错误:包括用户输入错误、设备错误、物理限制等几类。程序员通常无能为力,一旦发生,想办法让程序优雅的结束。
异常:程序本身导致的问题,可以捕获、可以处理。

异常处理

异常是程序执行中的非正常事件,程序无法再按预想的流程执行。异常可以将错误信息传递给上层调用者,并报告“案发现场”的信息,是return之外的第二种退出途径。若找不到异常处理程序,整个系统最后会完全退出。

异常的分类

异常是从Throwable派生的,主要分为运行时异常(RuntimeException)和其他异常两大类。

  • 运行时异常由程序员在代码里处理不当造成,如果在代码中提前进行验证就可以避免;
  • 其他异常由外部原因造成,程序员无法完全控制,即使在代码中提前加以验证也无法完全避免。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. 智慧社区背景与挑战 随着城市化的快速发展,社区面临健康、安全、邻里关系和服务质量等多方面的挑战。华为技术有限公司提出智慧社区解决方案,旨在通过先进的数字化技术应对这些问题,提升城市社区的生活质量。 2. 技术推动智慧社区发展 技术进步,特别是数字化、无线化、移动化和物联化,为城市社区的智慧化提供了可能。这些技术的应用不仅提高了社区的运行效率,也增强了居民的便利性和安全性。 3. 智慧社区的核心价值 智慧社区承载了智慧城市的核心价值,通过全面信息化处理,实现对城市各个方面的数字网络化管理、服务与决策功能,从而提升社会服务效率,整合社会服务资源。 4. 多层次、全方位的智慧社区服务 智慧社区通过构建和谐、温情、平安和健康四大社区模块,满足社区居民的多层次需求。这些服务模块包括社区医疗、安全监控、情感沟通和健康监测等。 5. 智慧社区技术框架 智慧社区技术框架强调统一平台的建设,设立数据中心,构建基础网络,并通过分层建设,实现平台能力及应用的可持续成长和扩展。 6. 感知统一平台与服务方案 感知统一平台是智慧社区的关键组成部分,通过统一的RFID身份识别和信息管理,实现社区服务的智能化和便捷化。同时,提供社区内外监控、紧急救助服务和便民服务等。 7. 健康社区的构建 健康社区模块专注于为居民提供健康管理服务,通过整合医疗资源和居民接入,实现远程医疗、慢性病管理和紧急救助等功能,推动医疗模式从治疗向预防转变。 8. 平安社区的安全保障 平安社区通过闭路电视监控、防盗报警和紧急求助等技术,保障社区居民的人身和财产安全,实现社区环境的实时监控和智能分析。 9. 温情社区的情感沟通 温情社区着重于建立社区居民间的情感联系,通过组织社区活动、一键呼叫服务和互帮互助平台,增强邻里间的交流和互助。 10. 和谐社区的资源整合 和谐社区作为社会资源的整合协调者,通过统一接入和身份识别,实现社区信息和服务的便捷获取,提升居民生活质量,促进社区和谐。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值