软件构造9——各种常用模式总结

复习各种模式的时候的心得

Liskov可替换原则

更强的不变量、更弱的前置条件、更强的后置条件

委托

委托的意思就是,我们想要实现一个方法,我们不用A类去实现,而是另外写一个类B,让这个类B去实现,然后我们在A类中实例化类B,然后调用B类中的方法,主要好处就是充分实现单一职责原则。(应对场景:比如有鸟这个类,我们有会叫的鸟,叫的方式有很多种,会飞的鸟,飞的方式也有很多种,如果我们用一个类鸟,然后用许多类来继承鸟这个类,我们最后就很容易组合爆炸。但是我们可以用将飞和叫都封装成类,然后在鸟这个类里面实例化,这样我们就想用什么飞法和叫法我们就将他复制成什么就好了)

interface Flyable {//飞的接口
	public void fly();
}
interface Quackable {//叫的接口
	public void quack();
}
class FlyWithWings implements Flyable { //某种飞的方式
	@Override
	public void fly() {
		System.out.println("fly with wings");
	}
}
class Quack implements Quackable {//某种叫的方式
	@Override
	public void quack() {
		System.out.println("quack like duck");
	}
}

interface Ducklike extends Flyable, Quackable {}
public class Duck implements Ducklike {
	Flyable flyBehavior;//我们在这个动物的类里面实例化飞和叫
	Quackable quackBehavior;
	void setFlyBehavior(Flyable f) {//是哪种飞我就赋值成哪种
		this.flyBehavior = f;
	}
	void setQuackBehavior(Quackable q) {//是哪种叫我就赋值成哪种
		this.quackBehavior = q;
	}
	@Override
	public void fly() {//飞就调用飞的方法
		this.flyBehavior.fly();
	}
	@Override
	public void quack() {//叫就调用叫的方法
		this.quackBehavior.quack();
	}
}

结构型模式

适配器模式

我们写了很多个类来实现同一个功能,但是实现方式不一样,这就造成接口也大不相同,但是用户端一般都是希望只是用一个接口,就能完成所有的功能,所以,我们就应该将这些类装化成一个接口,统一的开放给用户。(应用场景:比如我们用一个显示图形的类,比如我们在显示长方形的时候是按照一个点的x,y值和宽高进行显示,但是在用户那边习惯用长方形的对角顶点来输入,这时候,我们就需要用到适配器模式,其实就是将用户输入的参数做一些调整,然后匹配我们的方法)

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);
	}
}

装饰器模式

我们在创建完一个类之后,如果我们要在类中新增加一些功能的时候,我们通常是利用继承,但是如果功能很多,并且每个功能有分成了不同的实现方式呢?这就造成了一个问题,组合爆炸。所以这时候我们就会用到装饰器模式,再不改变原来的类的前提下,进行增加功能。(应用场景:比如我们有一个形状的类,我们实现了各种形状,比如正方形、长方形、圆形等,但是每一种形状在图形化展示的时候应该有颜色,而且又有各种不同的颜色,难道我们要对每种颜色继承每一个类来实现吗?答案肯定是否定的。这时候,我们就用装饰器模式。)

public interface Shape {
	void draw();
}
public class Rectangle implements Shape {//长方形的类
   	@Override
   	public void draw() {
      		System.out.println("Shape: Rectangle");
   	}
}
public class Circle implements Shape {//圆形的类
   	@Override
   	public void draw() {
      		System.out.println("Shape: Circle");
   	}
}

public abstract class ShapeDecorator implements Shape {//我们要增加颜色功能的话
   	protected Shape decoratedShape;
   	public ShapeDecorator(Shape decoratedShape){
      		this.decoratedShape = decoratedShape;
   	}
   	public void draw(){
      		decoratedShape.draw();
   	}  
}
public class RedShapeDecorator extends ShapeDecorator {//对于每一种颜色,不用管是什么形状,只需要看颜色即可
   	public RedShapeDecorator(Shape decoratedShape) {
      		super(decoratedShape);     
   	}
   	@Override
   	public void draw() {
      		decoratedShape.draw();         
      		setRedBorder(decoratedShape);
   	}
   	private void setRedBorder(Shape decoratedShape){
      		System.out.println("Border Color: Red");
   	}
}

外观模式

我们用很多种类,但是用户肯定是分不清那个类是哪个类的,这时候我们就需要用一个类把这些类包含在一起,然后我们用这一个类调用别的类的方法,来实现功能就好了(比如:我们有MySQL和Oracle数据库这两个类,我们需要分别进行查找等操作,在用户端,我们就用一个类,然后对用户的输入进行判断,看用户想用哪种数据库类的操作,我们就实例化一个类,然后调用该类的操作)

public class MySqlHelper {//MySQL类
	public static Connection getMySqlDBConnection() {}
	public void generateMySqlPDFReport(String tableName, Connection con){}
	public void generateMySqlHTMLReport(String tableName, Connection con){}
}
public class OracleHelper {//Oracle类
	public static Connection getOracleDBConnection() {}
	public void generateOraclePDFReport(String tableName, Connection con){}
	public void generateOracleHTMLReport(String tableName, Connection con){}
}
//在用户端我们只需要给他一个类,然后对用户的输入进行判断就好了
public class HelperFacade {
	public static void generateReport(DBTypes dbType, ReportTypes reportType, String tableName){
	Connection con = null;
	switch (dbType){
		case MYSQL: 
			con = MySqlHelper.getMySqlDBConnection();
			MySqlHelper mySqlHelper = new MySqlHelper();
			switch(reportType){
				case HTML:
					mySqlHelper.generateMySqlHTMLReport(tableName, con);
					break;
				case PDF:
					mySqlHelper.generateMySqlPDFReport(tableName, con);
					break;
			}
			break;
		case ORACLE: …
	}
	public static enum DBTypes { MYSQL,ORACLE; }
	public static enum ReportTypes { HTML,PDF;}
}

代理模式

我们做摸个操作的时候代价比较高,这是我们就可以用到代理模式,在不需要这个操作的时候,就先用一个代理站位,等到真正需要执行操作的时候再去实例化。(应用场景:比如我们需要从磁盘中读一个文件,但是文件很大,如果在程序一开始我们就读进去的话占用很大的内存空间,我们就可以使用代理模式)

public interface Image {//读图片的接口
	void display();
}
public class RealImage implements Image {//真正读图片需要用到的类
	private String fileName;
	public RealImage(String fileName){
		this.fileName = fileName;
		loadFromDisk(fileName);
	}
	@Override
	public void display() {}
	private void loadFromDisk(String fileName){}
}
public class ProxyImage implements Image {//代理类
	private Image realImage;
	private String fileName;
	public ProxyImage(String fileName){//初始化的时候并不需要读图片
		this.fileName = fileName;
	}
	@Override
	public void display() {//等到执行显示图片的时候,我们再从磁盘上读入图片就好了
		if(realImage == null){
			realImage = new RealImage(fileName);
		}
		realImage.display();
	}
}

行为模式

策略模式

我们一种功能的实现可能有很多种方式,我们需要的是给用户提供出一个接口,在实例化功能实现形式的时候,用户按照希望的实现方式实例化就好了。(应用场景:比如我们有两种支付方式,信用卡支付和现金支付,当用户不作出选择时,我们并不知道用户怎么选择,我们就要把选择的余地留给用户,当选择信用卡支付的时候,我们就将接口实例化成信用卡支付就好了)

public interface PaymentStrategy {
	public void pay(int amount);
}
public class CreditCardStrategy implements PaymentStrategy {//信用卡支付
	@Override
	public void pay(int amount) {
		System.out.println(amount +" paid with credit card");
	}
}
public class PaypalStrategy implements PaymentStrategy {//Paypal支付
	@Override
	public void pay(int amount) {
		System.out.println(amount + " paid using Paypal.");
	}
}

public class ShoppingCart {
...
	public void pay(PaymentStrategy paymentMethod){//用户想要什么样的支付,就把PaymentStrategy实例化成哪种方式
		paymentMethod.pay(amount);
	}
}

模板模式

一些相似的类,我们将公共的方法提取到一个抽象类中,模板方法用final,然后对每一种差异化的行为我们在子类中重写(应用场景:比如我们有游戏类,对应的游戏有棋类游戏,球类游戏等,每一种游戏肯定有开始游戏、结束游戏、初始化游戏、玩游戏等功能,玩游戏这个其实就是调用开始游戏、结束游戏、初始化游戏,所以他就是一个模板方法,然后我们只需要在不同的子类中重写开始游戏、结束游戏、初始化游戏这三个方法就可以了)

public abstract class Game {
   	abstract void initialize();
   	abstract void startPlay();
   	abstract void endPlay();
   	public final void play(){//模板
      		initialize();
      		startPlay(); 
      		endPlay();
   	}
}
public class Cricket extends Game {//重写差异化的方法
   	@Override
   	void endPlay() {
      		System.out.println("Cricket Game Finished!");
   	}
  	@Override
   	void initialize() {
      		System.out.println("Cricket Game Initialized! Start playing.");
   	}
   	@Override
   	void startPlay() {
      		System.out.println("Cricket Game Started. Enjoy the game!");
   	}
}
public class Football extends Game {
   	@Override
   	void endPlay() {
      		System.out.println("Football Game Finished!");
   	}
   	@Override
   	void initialize() {
      		System.out.println("Football Game Initialized! Start playing.");
   	}
   	@Override
   	void startPlay() {
      		System.out.println("Football Game Started. Enjoy the game!");
   	}
}

迭代器模式

我们以类中的某个属性,对类进行遍历而使用的模式。主要就是需要实现next()和hasNext()方法。

public interface Iterator {//迭代器接口
   	public boolean hasNext();
   	public Object next();
}
public interface Container {
   	public Iterator getIterator();
}
public class NameRepository implements Container {
   	public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};
   	@Override
   	public Iterator getIterator() {
     		return new NameIterator();
   	}
   	private class NameIterator implements Iterator {//重写迭代器
      		int index;
      		@Override
      		public boolean hasNext() {
         		if(index < names.length){
            		return true;
         		}
         		return false;
      		}
      		@Override
      		public Object next() {
         		if(this.hasNext()){
            			return names[index++];
         		}
         		return null;
      		}     
   	}
}

观察者模式

相当于是偶像和粉丝之间的关系,偶像的一举一动粉丝都应该知道,如果粉丝加入到偶像的粉丝团,那么偶像也应该知道该粉丝团中加入了这个粉丝。

public class Subject {//偶像
	private List<Observer> observers = new ArrayList<Observer>();//偶像的粉丝团
	private int state;//偶像的状态
	public int getState() {return state;}
	public void setState(int state) {//相当于偶像发了个微博,然后所有的粉丝就应该都能收到
		this.state = state;
		notifyAllObservers();
	}
	public void attach(Observer observer){observers.add(observer);}//粉丝团加入粉丝
	private void notifyAllObservers(){
		for (Observer observer : observers) {
			observer.update();
		}
	} 
}
public abstract class Observer {//粉丝的抽象类
	protected Subject subject;
	public abstract void update();
}
public class BinaryObserver extends Observer{//一种粉丝
	public BinaryObserver(Subject subject){//粉丝初始化的时候应该有偶像
		this.subject = subject;
		this.subject.attach(this);
	}
	@Override
	public void update() {
		System.out.println( "Binary String: " +Integer.toBinaryString( subject.getState() ) ); 
	}
}

访问者模式

在特定ADT上执行某种特定操作,但该操作不在ADT内部实现,而是delegate到独立的visitor对象,客户端可灵活扩展/改变visitor的操作算法,而不影响ADT(应用场景:比如我要去买东西,可以买菜也可以买书,但是众所周知,菜是按斤买的,书是按本买的,所以计价方式不一样,但是我们都是要去买,这时候就可以用到访问者模式)

public interface ItemElement {//买东西的时候,东西也知道是谁买的
	public int accept(ShoppingCartVisitor visitor);
}
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);
	}
}
public interface ShoppingCartVisitor { //人去买东西
	int visit(Book book); 
	int visit(Fruit fruit); 
} 
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 class ShoppingCartClient {
	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) {
		ShoppingCartVisitor visitor = new ShoppingCartVisitorImpl();
		int sum=0;
		for(ItemElement item : items)//买的东西调用accept方法,在accept方法中调用visitor.visit
			sum = sum + item.accept(visitor);
		return sum;
	}
}

状态模式

这个模式设计主要就是为了不使用if else语句,因为如果要是使用if else的话,如果状态转移图有一些变化,那么我们就可能需要大量的改if else语句,但是在状态模式中,我们只需要改一些内部的状态转移函数就好了(应用场景:比如我们有一个自动机,当在S1状态下输入a转移到S2,输入b不动,在S2状态下输入a或b都转移到S1,如果输入的是其他,两个状态都直接报错,我们就可以应用状态模式)

class Context {//我们具体的一个对象
	State state;//状态
	public Context(State s) {state = s;}
	public void move(char c) { state = state.move(c); }
	public boolean accept() { return state.accept(); }
	public State getState() { return this.state; } 
}
public interface State {//状态模式的接口
	State move(char c); 
	boolean accept();
}
class State1 implements State {//其中的一个状态
	static State1 instance = new State1();
	private State1() {} 
	public State move (char c) {//状态的转移
		switch (c) {
			case 'a': return State2.instance; 
			case 'b': return State1.instance;
			default: throw new IllegalArgumentException();
		}
	}
	public boolean accept() {
		return false;
	} 
} 
class State2 implements State {//另一个状态
	static State2 instance = new State2();
	private State2() {}
	public State move (char c) {//状态的转移
		switch (c) {
			case 'a': return State1.instance;
			case 'b': return State1.instance;
			default: throw new IllegalArgumentException();
		}
	}
	public boolean accept() {return true;}
}

备忘录模式

其实就是相当于我们经常进行的一个操作ctrl+z

public class Memento {//备忘录,我们能够存储一个状态
   	private String state;
   	public Memento(String state){
      		this.state = state;
   	}
   	public String getState(){
      		return state;
   	}  
}
public class Originator {
   	private String state;
   	public void setState(String state){
      		this.state = state;
   	}
   	public String getState(){
      		return state;
   	}
   	public Memento saveStateToMemento(){//将状态存进备忘录里面
      		return new Memento(state);
   	}
   	public void getStateFromMemento(Memento Memento){//取出来
      		state = Memento.getState();
   	}
}
public class CareTaker {
   	private List<Memento> mementoList = new ArrayList<Memento>();//有一堆备忘录,想要那个我们就取哪个
   	public void add(Memento state){
      		mementoList.add(state);
   	}
   	public Memento get(int index){
      		return mementoList.get(index);
   	}
}

创建型模式

工厂模式

我们对一个接口有很多种实现,人但是我们并不知道用户想用哪一种,这时候就需要工厂模式,我们通过用户的输入来确定返回某一种具体的类。(应用场景:比如说我们有两种路径查找方式,一种是文件查找,一种是系统查找,但是我们并不知道用户想用哪种,这时候我们就把接口留出来,让用户去选择)

public interface Trace {
	public void setDebug( boolean debug );
	public void debug( String message );
	public void error( String message );
}
public class FileTrace implements Trace {//两种具体的实现方式FileTrace
	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();
	}
}
public class SystemTrace implements Trace {//SystemTrace
	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 );
	}
}

public class Factory1 implements TraceFactory {//工厂1,只能生产SystemTrace
	public Trace getTrace() {
		return new SystemTrace();
	}
}
public class Factory2 implements TraceFactory {//工厂2,两种都能生产
	public getTrace(String type) {
		if(type.equals(“file”)
			return new FileTrace();
		else if (type.equals(“system”)
			return new SystemTrace();
	}
}

抽象工厂模式

我们的一个工厂可能不止能生产一种商品,我们可能能生产很多不同种类的商品(应用场景:我们或一个图形,图形的样子可能是圆形和方形,颜色可能是红色和蓝色,但是我们规定圆形只能是红色,方形只能是蓝色,这时候我们就不应该让用户自己去选择图形和颜色的搭配,我们应该先搭配好在让用户去选择,这有一种套餐的感觉。)

public interface Window{
	public void setTitle(String s);
	public void repaint();
}
public class PMWindow implements Window{
	public void setTitle(){}
	public void repaint(){}
}
public class MotifWindow implements Window{
	public void setTitle(){}
	public void repaint(){}
}
public interface AbstractWidgetFactory{//抽象工厂
	public Window createWindow();
	public Scrollbar createScrollbar();
}
public class WidgetFactory1{//固定搭配1
	public Window createWindow(){
		return new MSWindow();
	}
	public Scrollbar createScrollbar(){A}
}
public class WidgetFactory2{//固定搭配2
	public Window createWindow(){
		return new MotifWindow();
	}
	public Scrollbar createScrollbar(){B}
}

参考:菜鸟教程;HIT软件构造PPT;设计模式

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值