Java设计模式之factory、abstract factory、proxy、observer、visitor、state、memento

提示:设计模式最好自己动手写代码实践一下,这样更有助于理解

设计模式(二)

1. Factory(工厂模式)

1.1 目的

用来解决接口的选择问题,避免向客户端暴露实例类

1.2 使用方法

为同一个接口是实例类建立一个工厂类,然后在工厂类中的工厂方法传入的参数来返回一个对应的实例类

Animal接口:

public interface Animal {

	public void sound();
	
}

Dog类:

public class Dog implements Animal {

	@Override
	public void sound() {
		System.out.println("汪汪");
	}

}

Cat类:

public class Cat implements Animal {

	@Override
	public void sound() {
		System.out.println("喵喵");
	}

}

Factory类(工厂方法所在类):

public class Factory {

	public Animal get(String str) {
		if(str.toLowerCase().equals("dog")) {
			return new Dog();
		}else if(str.toLowerCase().equals("cat")) {
			return new Cat();
		}else {
			return null;
		}
	}
	
}

测试代码:

public class tryness {

	public static void main(String[] args) {
		Factory factory = new Factory();
		
		Animal dog = factory.get("Dog");
		dog.sound();
		
		Animal cat = factory.get("Cat");
		cat.sound();
	}
	
}
运行结果:
汪汪
喵喵

我们可以看到利用Factory来返回一个Animal的实例类,客户端不需要知道具体实例类的名称,只是传入想要的动物类型即可。

1.3 工厂方法的优缺点

优点:
调用者只需要传入名称即可,不需要知道具体的类名,扩展性较强,操作方便

缺点:
在一定程度上增加了结构的复杂性

2. Abstract Factory(抽象工厂模式)

2.1 目的

同工厂模式一样,但是如果有多个工厂模式我们想要把他们聚合起来,就需要抽象工厂方法模式了

2.2 使用方法

直接看代码,然后再解释

Anima接口:

public interface Animal {

	public void sound();
	
}

Dog类:

public class Dog implements Animal {

	@Override
	public void sound() {
		System.out.println("汪汪");
	}

}

Cat类:

public class Cat implements Animal {

	@Override
	public void sound() {
		System.out.println("喵喵");
	}

}

Food接口:

public interface Food {

	public void print();
	
}

Hamburger类:

public class Hamburger implements Food {

	@Override
	public void print() {
		System.out.println("I am hamburger");
	}

}

Pizza类:

public class Pizza implements Food {

	@Override
	public void print() {
		System.out.println("I am pizza");
	}

}

AbstractFactory类:

public abstract class AbstractFactory {

	public abstract Animal getAnimal(String str);
	public abstract Food getFood(String str);
	
}

AnimalFactory类:

public class AnimalFactory extends AbstractFactory {

	@Override
	public Animal getAnimal(String str) {
		if(str.toLowerCase().equals("dog")) {
			return new Dog();
		}else if(str.toLowerCase().equals("cat")) {
			return new Cat();
		}else {
			return null;
		}
	}

	@Override
	public Food getFood(String str) {
		return null;
	}

}

FoodFactory类:

public class FoodFactory extends AbstractFactory {

	@Override
	public Animal getAnimal(String str) {
		return null;
	}

	@Override
	public Food getFood(String str) {
		if(str.toLowerCase().equals("hamburger")) {
			return new Hamburger();
		}else if (str.toLowerCase().equals("pizza")) {
			return new Pizza();
		}else {
			return null;
		}
	}

}

FactoryProducer类:

public class FactoryProducer {

	public static AbstractFactory getFactory(String str) {
		if(str.toLowerCase().equals("animal")) {
			return new AnimalFactory();
		}else if(str.toLowerCase().equals("food")) {
			return new FoodFactory();
		}else {
			return null;
		}
	}
	
}

测试代码:

public class tryness {

	public static void main(String[] args) {
		AbstractFactory animalFactory = FactoryProducer.getFactory("Animal");
		
		Animal dog = animalFactory.getAnimal("Dog");
		dog.sound();
		
		Animal cat = animalFactory.getAnimal("Cat");
		cat.sound();
		
		AbstractFactory foodFactory = FactoryProducer.getFactory("Food");
		
		Food hamburger = foodFactory.getFood("Hamburger");
		hamburger.print();
		
		Food pizza = foodFactory.getFood("Pizza");
		pizza.print();
	}
	
}
运行结果:
汪汪
喵喵
I am hamburger
I am pizza

这里的动物和事物是两个需要用工厂方法处理的类别,正常是需要两个工厂方法,但是现在想把两个工厂方法合并起来统一管理,那么就需要建立一个抽象工厂类,抽象工厂类里的两个方法自然就是返回Animal的和返回Food的,但是要确定我们需要哪个工厂方法就需要再建立一个工厂的生成类FactoryProducer,输入参数选择是animal工厂还是food工厂,然后就和工厂方法的使用方法一样了。

2.3 抽象工厂方法的优缺点

优点:
多个不相关的工厂方法被聚合到一起,方便管理

缺点:
扩展比较麻烦,而且在结构上增加了复杂程度

3. Proxy(代理模式)

3.1 目的

避免客户端对对象的直接访问,我们要在客户端和对象之间加一层代理,可以避免直接访问造成的麻烦

3.2 使用方法

先看代码,然后再解释

Pictrue接口:

public interface Picture {

	public void view();
	
}

RealPicture类:

public class RealPicture implements Picture {

	String name;
	
	public RealPicture(String str) {
		this.name = str;
	}
	
	@Override
	public void view() {
		System.out.println(name + " is open");
	}

}

ProxyPicture类:

public class ProxyPicture implements Picture {

	RealPicture rp;
	String name;
	
	public ProxyPicture(String str) {
		this.name = str;
	}
	
	@Override
	public void view() {
		if(rp == null) {
			rp = new RealPicture(name);
		}
		rp.view();
	}

}

测试代码:

public class tryness {

	public static void main(String[] args) {
		ProxyPicture pp = new ProxyPicture("Doraemon");
		pp.view();
	}
	
}
运行结果:
Doraemon is open

RealPicture是真实的图像类,但是为了避免客户端直接访问此类,我们应该加一个代理ProxyPicture,用ProxyPicture来访问RealPicture,避免了直接访问的麻烦以及不安全性,在测试代码中,我们可以看到并没有出现有关RealPicture的任何信息。

3.3 代理模式的优缺点

优点:
具有可扩展性,为客户端提供了便捷

缺点:
在客户端和目标类之间加代理,一定程度上增加了复杂性

4. Observer(观察者模式)

4.1 目的

当一个对象的状态发生变化时,所有依赖于他的对象都能得到通知,并作出相应的反应

4.2 使用方法

先看代码,然后解释

Observer类:

public abstract class Observer {

	Forest forest;
	
	public abstract void upDate();
	
}

Dog类:

public class Dog extends Observer {

	public Dog(Forest forest) {
		forest.attach(this);
		this.forest = forest;
	}
	
	@Override
	public void upDate() {
		System.out.println(this.forest.getMessage());
	}

}

Cat类:

public class Cat extends Observer {

	public Cat(Forest forest) {
		forest.attach(this);
		this.forest = forest;
	}
	
	@Override
	public void upDate() {
		System.out.println(this.forest.getMessage());
	}

}

Forest类:

public class Forest {

	private List<Observer> list = new ArrayList<Observer>();
	
	String message = "森林安全";
	
	public void attach(Observer o) {
		list.add(o);
	}
	
	public String getMessage() {
		return this.message;
	}
	
	public void changeMessage(String str) {
		this.message = str;
		note();
	}
	
	private void note() {
		for(Observer i : list) {
			i.upDate();
		}
	}
	
}

测试代码:

public class tryness {

	public static void main(String[] args) {
		Forest f = new Forest();
		Observer dog = new Dog(f);
		Observer cat = new Cat(f);
		
		f.changeMessage("森林失火了,快跑");
		
		f.changeMessage("森林恢复安全");
	}
	
}
运行结果:
森林失火了,快跑
森林失火了,快跑
森林恢复安全
森林恢复安全

猫和狗都得到了相应的信息
Observer是一个抽象类,代表观察者,Forest是森林类,是所有动物的被观察者,一旦森林信息发生改变,所有动物都应该被通知到,主要就是要将所有的Observer都储存在Forest中,并且在每个Observer中都保存一个Forest的信息,用来相互关联。

4.3 观察者模式的优缺点

优点:
观察者和被观察者是耦合的,一旦被观察者发生信息变化,观察者都能及时收到通知

缺点:
如果一个对象有很多观察者时,一点的信息修改就会要全都通知一遍,很耗时,如果两个对象互为观察者,那么会无限的循环。

5. Visitor(访问者模式)

5.1 目的

需要对一个对象进行不同的不相关的操作,并且要避免这些操作影响这些对象的类,可以使用访问者模式将这些封装到类中

5.2 使用方法

先看代码,然后解释

Computer类:

public interface ComputerPart {

	public void accept(Visitor visitor);
	
}

Mouse类:

public class Mouse implements ComputerPart {
	
	@Override
	public void accept(Visitor visitor) {
		visitor.visit(this);
	}

}

KeyBoard类:

public class Keyboard implements ComputerPart {

	@Override
	public void accept(Visitor visitor) {
		visitor.visit(this);
	}

}

Computer类:

public class Computer implements ComputerPart {

	ComputerPart[] cp;
	
	public Computer() {
		cp = new ComputerPart[] {new Mouse(), new Keyboard()};
	}
	
	@Override
	public void accept(Visitor visitor) {
		for(int i = 0; i < cp.length; i ++) {
			cp[i].accept(visitor);
		}
	}

}

Visitor类:

public interface Visitor {

	public void visit(Mouse mouse);
	public void visit(Keyboard keyboard);
	
}

MessageGotbyVisitor类:

public class MessageGotbyVisitor implements Visitor {

	@Override
	public void visit(Mouse mouse) {
		System.out.println("This is mouse");
	}

	@Override
	public void visit(Keyboard keyboard) {
		System.out.println("This is keyboard");
	}

}

测试代码:

public class tryness {
	
	public static void main(String[] args) {
		ComputerPart cp = new Computer();
		MessageGotbyVisitor mgbv = new MessageGotbyVisitor();
		cp.accept(mgbv);
	}

}
运行结果:
This is mouse
This is keyboard

这个模式之前我虽然能看懂代码,但是并没有完全理解,这里来解释一下为什么这就是访问者模式。
首先ComputerPart是计算机组件的接口,Mouse是鼠标,KeyBoard是键盘,至于其他组件为了简便,这里就忽略了,Visitor是访问者的接口,MessageGotbyVisitor是访问后得到的信息,==visit()==方法是访问当前设备,accept() 方法代表接受访问。
我们把主体看做是设备,那么如果主体接受了访问,访问者就可以获得相应的信息,这就是访问者模式。

5.3 访问者模式的优缺点

优点:
符合单一职责的原则,扩展性强

缺点:
在一定程度上加强了结构的复杂性

6. State(状态模式)

6.1 目的

进行一定规则的状态的转换,一个易懂的例子就是实验3中的状态转换

6.2 使用方法

先看代码,再做解释

State接口:

public interface State {
	
	public void doAction(Context context);
	
}

Start类:

public class Start implements State {

	@Override
	public void doAction(Context context) {
		context.set(this);
	}
	
	public String toString() {
		return "Start";
	}

}

End类:

public class End implements State {

	@Override
	public void doAction(Context context) {
		context.set(this);
	}
	
	public String toString() {
		return "End";
	}
	
}

Context类:

public class Context {

	private State state;
	
	public void set(State state) {
		this.state = state;
	}
	
	public State getState() {
		return this.state;
	}
	
}

测试代码:

public class tryness {

	public static void main(String[] args) {
		Context c = new Context();
		
		State start = new Start();
		State end = new End();
		
		start.doAction(c);
		System.out.println(c.getState().toString());
		
		end.doAction(c);
		System.out.println(c.getState().toString());
		
	}
	
}
运行结果:
Start
End

Context可以看做是我们的主要研究的对象,他的状态可变,我们可以通过操作改变他的状态,并且状态是我们限定的,State及其实例类就是设定好的状态,当然也可以加状态转换条件,类似实验3那样。

6.3 状态模式的优缺点

优点:
自定义转换规则,只能在我们设定好的状态及转换规则下进行转换

缺点:
每个状态都要有一个类,如果状态过多的话,可能会导致结构变得十分庞大,而且状态之间的转化规则也会变得十分复杂

7. Memento(备忘录模式)

7.1 目的

在不破坏封装性的条件下,获取一个对象的内部状态,并且在此对象外保存这个状态

7.2 使用方法

先看代码,再做解释

Memento类:

public class Memento {

	private String message;
	
	public Memento(String message) {
		this.message = message;
	}
	
	public String getMessage() {
		return this.message;
	}
	
}

Action类:

public class Action {

	private String message;
	
	public void setMessage(String message) {
		this.message = message;
	}
	
	public String getMessage() {
		return this.message;
	}
	
	public Memento save() {
		return new Memento(this.message);
	}
	
}

Log类:

public class Log {

	private List<Memento> memList = new ArrayList<Memento>();
	
	public void add(Memento mem) {
		memList.add(mem);
	}
	
	public Memento get(int index) {
		return memList.get(index);
	}
	
}

测试代码:

public class tryness {

	public static void main(String[] args) {
		Log log = new Log();
		Action a = new Action();
		
		a.setMessage("First message");
		log.add(a.save());
		
		a.setMessage("Second message");
		log.add(a.save());
		
		System.out.println(log.get(0).getMessage());
		System.out.println(log.get(1).getMessage());
		
	}
	
}
运行结果:
First message
Second message

其中Memento是一条备忘录,用来记录一个重要信息,Log是所有备忘录的合集,用来记录或者获取备忘录的信息,Action是可能产生重要信息的类,备忘录记录的也正是Action的信息,总的来说就是把需要被记录的信息都集中在一起进行管理。

7.3 备忘录模式的优缺点

优点:
实现了信息的储存,并且信息是可恢复的,不用担心一步的错误导致不可复原,类似Ctrl + Z 的功能

缺点:
消耗了大量的存储资源,如果需要记录的备忘信息过多,那么将会占用大量的存储空间

此篇文章只是我个人理解,如果有错误欢迎指出,感谢阅读!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值