本篇文章针对三个问题来学习几个常见设计模式:设计模式如何实现?设计模式的应用场景?设计模式有什么优点?
1.策略模式(stratrgy)
如何实现?
用动作的多个实现方法(多个算法)实现动作接口,在动作所属变量实例化时将动作的完成方法赋值进去,调用时调用该实例的动作用的则是赋值进去的实现方法:
public interface Chengfa {
void doChengfa();
}
public class Zhiri implements Chengfa {
@Override
public void doChengfa(){
System.out.println("值日!");
}
}
public class Zhaojiazhang implements Chengfa {
@Override
public void doChengfa(){
System.out.println("找家长!");
}
}
public class Teacher {
private Chengfa chengfa;
Teacher(Chengfa chengfa){
this.chengfa = chengfa;
}
public void chengFaStudent(){
this.chengfa.doChengfa();
}
}
上面代码定义了教师的"惩罚学生"方法,可以通过不同的实现类来实现,下面执行上面的策略模式:
public static void main(String[] args) {
Teacher teacher = new Teacher(new Zhiri());//这是一个会罚值日的老师
Teacher teacher2 = new Teacher(new Zhaojiazhang());//这是一个会找家长的老师
System.out.println("学生犯错误....两个老师分别:");
teacher.chengFaStudent();
teacher2.chengFaStudent();
}
输入结果:
学生犯错误....两个老师分别:
值日!
找家长!
应用场景以及优点?
这种模式典型的应用就是TreeSet的排序方法,程序员可以实现Comparator接口然后再TreeSet初始化的时候将实现实体类放入构造函数的参数中,treeSet就会按照这个方法排序.
这种设计模式主要强调一个动作的不同实现方法,拓展性较强.
2.观察者模式(Observer)
如何实现?
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新,
观察者模式实现方法分为推和拉,推模型是假定主题对象知道观察者需要的数据;而拉模型是主题对象不知道观察者具体需要什么数据,没有办法的情况下,干脆把自身传递给观察者,让观察者自己去按需要取值,下面看一下推模型的实现方法:
public interface Observer {
public void update(Object object);
}
public abstract class AbstractEvent{
private List<Observer> list=new ArrayList<Observer>();
public void addObserver(Observer observer){
list.add(observer);
}
public void notifyObservers(Object object){
for(Observer o:list){
o.update(object);
}
}
}
public class Event extends AbstractEvent{
private Object object;
public void setObject(Object object) {
this.object = object;
notifyObservers(object);
}
}
public class NewObserver implements Observer{
@Override
public void update(Object object) {
System.out.println("观察者获得:"+object);
}
}
拉模式只不过将推送代码o.update(object);改成了o.update(this);,从而观察者的update方法变成了update(Event event),这样就获取到了事件中最大的父类结构体,可以强制类型转化成任意子类;拉模型复用性更强,但个人比较喜欢推模型,毕竟推送的可以是任意结构体,并且感觉层次更清晰,对于编写观察者类也会友好很多.
执行一下察者模型:
public class TestObserver1 {
public static void main(String[] args) {
Event subject=new Event();
Observer observer=new NewObserver();
subject.addObserver(observer);
subject.setObject("22");
}
}
运行结果:
观察者获得:22
应用场景以及优点?
观察者模式通过将被观察者注册到观察者中,通过编写被观察者的赋值逻辑,在赋值的同时调用观察者的监听方法。有效的实现了信息同步的功能,强调信息的同步告知,从上述模型可以看出,观察者可以有多个,只需要注册即可,被观察者可以通过继承的方式进行扩展。这里需要注意,通知消息是循环调用接口方法,可能会存在堵塞,异常等情况,可以根据个人需求和实现环境,通过多线程等方式处理问题。
3.模板模式(template)
如何实现?
public abstract class AbstractPerson{
//抽象类定义整个流程骨架,定义成final使子类不能修改
public final void GotoSchool(){
dressUp();
eatBreakfast();
takeThings();
}
//以下是不同子类根据自身特性完成的具体步骤
protected abstract void dressUp();
protected abstract void eatBreakfast();
protected abstract void takeThings();
}
像这样先定义一个去学校的算法骨架然后柑橘自己的需求对其扩展:
public class Students extends AbstractPerson{
@Override
protected void dressUp() {
System.out.println("穿校服");
}
@Override
protected void eatBreakfast() {
System.out.println("吃妈妈做好的早饭");
}
@Override
protected void takeThings() {
System.out.println("背书包,带上家庭作业和红领巾");
}
}
class Teacher extends AbstractPerson{
@Override
protected void dressUp() {
System.out.println("穿工作服");
}
@Override
protected void eatBreakfast() {
System.out.println("做早饭,照顾孩子吃早饭");
}
@Override
protected void takeThings() {
System.out.println("带上昨晚准备的考卷");
}
}
然后编写测试类执行算法:
AbstractPerson student = new Students();
student.GotoSchool();
System.out.println("---------------------");
AbstractPerson teacher = new Teacher();
teacher.GotoSchool();
结果输出:
穿校服
吃妈妈做好的早饭
背书包,带上家庭作业和红领巾
---------------------
穿工作服
做早饭,照顾孩子吃早饭
带上昨晚准备的考卷
应用场景以及优点?
强调一个操作中算法的可延伸的点的扩展,像springMVC的preHandleafterCompletion方法,就用到了这种模式,在不影响算法统一骨架的情况下,对算法的某个步骤进行扩展.
模板模式和策略模式在简单算法应用上比较相像,但如果涉及到多维度的借口配合构成一个大的方法体或者该方法只是一个类中的一个功能,则策略模式比较实用。毕竟模板模式相当于多种方法构成一个抽象的总方法,而策略模式则是一个对象中的一个功能的延伸。使用时因实际需求而异。
4.装饰(Decorator)设计模式
如何实现?
这里引用百度百科的例子:
首先一个已经定义好的接口以及实现类:
public interface IThirdParty {
public String sayMsg();
}
public class ThirdParty implements IThirdParty {
public String sayMsg() {
return "hello";
}
}
装饰类1和装饰类2:
public class Decorator1 implements IThirdParty {
private IThirdParty thirdParty;
public Decorator1(IThirdParty thirdParty){
this.thirdParty= thirdParty;
}
public String sayMsg(){
return "##1"+ thirdParty.sayMsg() + "##1";
}
}
public class Decorator2 implements IThirdParty {
private IThirdParty thirdParty;
public Decorator2(IThirdParty thirdParty){
this.thirdParty= thirdParty;
}
public String sayMsg(){
return "##2"+ thirdParty.sayMsg() + "##2";
}
}
测试上述模型:
IThirdParty decorator2 =new Decorator2(new Decorator1(new ThirdParty()));
System.out.println(decorator2.sayMsg());
测试结果:
##2##1hello##1##2
使用场景以及优点?
java IO 流是典型的装饰模式。装饰模式可以在不改变原有接口功能的情况下对原有接口的方法做一些操作,比集成更加灵活,使接口更符合自己的用法,比较适用于为对象添加功能并希望功能可以动态的撤销,或者需要添加基础功能的排列组合而不能用继承的情况.
5.外观模式(facade)
本模式较为简单,即外观类为子系统提供一个共同的对外接口,不做实例讲解.
适用于子系统功能复杂,而对外界来说并不需要过于复杂接口的情况,系统对外开放式api即为该模式.