欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

关于软件构造中的设计模式汇总

程序员文章站 2024-02-09 15:54:04
...

在《软件构造》这门课程的学习过程中,除了学习了很多java中的数据类型、数据结构等内容,更让我印象深刻的是软件构造中的各种设计模式。下面我将会列出我在实验中使用的各种设计模式,叙述其内容及作用并列出我在实验中的用法。

1.适配器模式(Adapter)
适配器模式能够将某个类/接口转换为client期望的其他形式,具体地说就是解决类之间接口不兼容的问题,以及通过增加一个接口,将已存在的子类封装起来,client面向接口编程,从而隐藏了具体子类。加个“适配器”以便于复用,也是挺高复用性的一种方法。
在我的实验中,虽然实验要求并没有要求使用适配器模式,我也没有主观地刻意去使用适配器模式,但是依然无意间使用了该模式。在我的函数中,由于函数的输入类型与客户端的数据类型不匹配导致无法使用,于是我在代码中使用了这个方法

public boolean checkLocationConflict(List<PlanningEntry<R>> entries) {
	for (int i = 0; i < entries.size(); i++) {
		for (int j = 0; j < entries.size(); j++) {
			if (i != j && 	entries.get(i).getLocation(0).equals(entries.get(j).getLocation(0))
						&& !entries.get(i).getLocation(0).checkIfCanShare()) {
				if (timeOverlap(entries))
					return false;
				}
			}
		}
	return true;
}

private static List<PlanningEntry<Plane>> transform(List<FlightEntry<Plane>> list){
	List<PlanningEntry<Plane>> list1 = new ArrayList<PlanningEntry<Plane>>();
	for(FlightEntry<Plane> entry : list)
		list1.add(entry);
	return list1;
}

public boolean checkLocationConflictTransform(List<PlanningEntry<R>> list){
	return checkLocationConflict(transform(list));
}

2.装饰器模式(Docorator)
装饰者模式用每个子类实现不同的特性,在我们需要大量有重复属性但是同时又有特定属性的时候,使用单纯地继承委托等方法可能会造成组合爆炸、大量代码重复等等问题。而装饰器模式能很好地解决这个问题。
其问题是为对象增加不同侧面的特性,解决方式是对每一个特性构造子类,通过委派机制增加到对
象上,其工作原理是以递归的方式实现,接口:定义装饰物执行的公共操作,起始对象,在其基础上增加功能(装饰),将通用的方法放到此对象中。Decorator抽象类是所有装饰类的基类,里面包含的成员变量component指向了被装饰的对象。
虽然当时写实验的时候很遗憾未能很好地理解装饰器模式,没有在实验中采用这个方法,但是通过后来的学习和复习之后理解了其作用,个人认为其是解决复用性的非常好的方法之一。

3.外观模式(Facade)
外观模式解决的问题是客户端需要通过一个简化的接口来访问复杂系统内的功能,其解决方式是提供
一个统一的接口来取代一系列小接口调用,相当于对复杂系统做了一个封装,简化客户端使用,作用简单来说就是便于客户端学习使用,解耦。
在我的实验代码中,我将很多的方法放入了一个类中,降低了耦合度,提高了内聚度,降低了客户端的调用难度。

package PlanningEntry;

import java.util.List;

public class FacadePlanningEntry<R> {

	public FacadePlanningEntry() 

	public boolean timeOverlap(List<PlanningEntry<R>> entries) 
	
	public boolean checkLocationConflict(List<PlanningEntry<R>> entries)

	public PlanningEntry<R> findPreEntryPerResource(R r, PlanningEntry<R> e, List<PlanningEntry<R>> entries) 
		
	
}

具体的方法内容就不在此处展示

4.策略模式
策略模式解决的问题是有多种不同的算法来实现同一个任务,但需要client根据需要动态切换算法,而不是写死在代码里。其解决方式是不同的实现算法构造抽象接口,利用delegation,运行时动态传入client倾向的算法类实例,其优势在于易于为新的算法实现进行扩展及从客户端上下文分离算法。
在我的代码中,虽然两种方法大同小异,并没有十分直接的差别,但是以后如果出现上述问题的时候相信这个模式是十分有用的

public boolean checkResourceExclusiveConflict1(List<PlanningEntry<R>> entries) {
	for (int i = 0; i < entries.size(); i++) {
		for (int j = 0; j < entries.size(); j++) {
			if (i != j) {
				if (entries.get(i).getResource().equals(entries.get(j).getResource()))
					return false;
			}
		}
	}
		return true;
}

public boolean checkResourceExclusiveConflict2(List<PlanningEntry<R>> entries) {
	for (PlanningEntry<R> entry1 : entries) {
		for (PlanningEntry<R> entry2 : entries) {
			if (!entry1.equals(entry2)) {
				if (entries.get(i).getResource().equals(entries.get(j).getResource()))
					return false;
			}
		}
	}
	return true;
}

//在客户端中的使用
try{
		System.out.println("Please choose a strategy to check(1 or 2)");
		int strategy = in.nextInt();
		if(strategy == 1) {
			if (check_resource.checkResourceExclusiveConflict(transform(list_check), strategy))
				System.out.println("\nNo conflict!\n");
			else
				System.out.println("\nResource conflict!\n");
				break;
			} else if(strategy == 2) {
				if (check_resource.checkResourceExclusiveConflict(transform(list_check), strategy))
					System.out.println("\nNo conflict!\n");
				else
					System.out.println("\nResource conflict!\n");
					break;
			} else {
					System.out.println("\nWrong input!\n");
					break;
					}
			} catch (InputMismatchException e){
				System.out.println("Please enter the correct type");
				in.nextLine();
				continue;
			}

5.迭代器(Iterator)
迭代器解决的问题是客户端希望遍历被放入
容器/集合类的一组ADT对象,无需关心容器的具体类型。也就是说,不管对象被放进哪里,都应该提供同样的遍历方式。其解决方式是迭代的策略模式。其作用有:隐藏底层容器的内部实现、使用统一接口支持多遍历、策略易于更改容器类型、促进程序各部分之间的沟通。
我在实验中同样完成了迭代器

	public Iterator<CourseEntry<Teacher>> iterator() {
		return new Itr();
	}

	private class Itr implements Iterator<CourseEntry<Teacher>> {
		int cursor; // index of next element to return
		@SuppressWarnings("unused")
		int lastRet = -1; // index of last element returned; -1 if no such

		@Override
		public boolean hasNext() {
			// TODO Auto-generated method stub
			return cursor != list.size();
		}

		@Override
		public CourseEntry<Teacher> next() {
			// TODO Auto-generated method stub
			int i = cursor;
			cursor = i + 1;
			return list.get(lastRet = i);
		}
	}

6.状态模式
状态模式允许在运行时修改对象的行为或状态,每个行为(一组方法构成)用一个状态类表达。状态对象通常不包含任何属性;状态改变时,修改状态对象;具体执行的方法,委托给状态对象。
在我的代码中同样使用了状态模式,防止代码内部出现大量的 if-else 结构导致难以维护。

package State;

public class Context {
	
	// TODO fields
	private State state;
	
	// Abstraction function:
    // TODO
	// Context类,定义当前状态
	
    // Representation invariant:
    // TODO
	// 状态state,代表当前状态
	
    // Safety from rep exposure:
    // TODO
	// 所有数据均为private类型
	// 防拷贝式编程
	
	// TODO constructor
	public Context() {
		
	}
	
	/**
	 * Set the current state.
	 * 
	 * @param current state
	 */
	public void setState(State state) {
		this.state = state;
	}
	
	/**
	 * Get the current state.
	 * 
	 * @return current state
	 */
	public String getState() {
		return state.getState();
	}
}

package State;

//其余状态不再列出,只写出父类State
public interface State {

	/**
	 * Get state.
	 * 
	 * @return state
	 */
	public String getState();
}

7.工厂模式
工厂模式也称虚拟构造器。其解决的问题是client不知道/不确定要创建哪个具体类的实例,或者不想在client代码中指明要具体创建的实例时,用工厂方法。其解决问题的方法是定义一个用于创建对象的接口,让该接口的子类型来决定实例化哪一个类,从而使一个类的实例化延迟到其子类。
在我的代码中十分好地运用了这个技术,通过这个技术避免了每次创建新对象都需要使用构造器new一个对象。

public abstract class Factory {
	
	/**
	 * New a product.
	 * 
	 * @return a new product
	 */
	public abstract PlanningEntryProduct Manufacture();
}

public abstract class PlanningEntryProduct {

	/**
	 * New a planning entry.
	 *
	 * @param label of the entry
	 */
	public abstract void CreateEntry(String label);

}
//具体的工厂和产品不再一一写出

以上就是我总结的有效且运用到了实验中的各种方法。