深入理解简单的工厂模式、工厂方法模式、策略模式、装饰模式、代理模式

1,简单的工厂模式

针对实现了同一个接口或者继承了实现了同一个抽象父类的多个逻辑类建立实例化对象对的工厂,工厂通过不同的情况下的向上转型将不同的实例化对象返回,来看一下实现的UML图:

《大话设计模式》中讲到了几个很好的例子,可以有助理解工厂模式的优点:

如果你要去开发一个多种语言下的游戏,其实游戏的逻辑代码是可以复用的,所以将逻辑代码与界面交互代码分离可以增强逻辑代码的复用性。通过继承实现抽象类的抽象方法,实现了多态。如果你在公司,有一个关于发送工资的系统需要你加一部分功能代码进去,但是BOSS又怕你动了其它的方法,比如你可以将工资计算逻辑代码修改,(当然这是犯法的。)所以不希望你可以看到所有的逻辑代码,就将逻辑(功能)分离成一个一个的类,这样你只用写好你的代码,然后在界面交互的代码中添加引用即可,可以保证其它逻辑代码的安全性。最后工厂模式本身就是具有拓展性的。

//邮件发送的抽象基类,一个待实现了发送方法
public abstract class SenderEntity {
	public abstract void Sender();
}
//子类继承实现Sender()方法
public class AttachSender extends SenderEntity {
	@Override
	public void Sender() {
		System.out.println("带有附件的发送");
	}
}
public class NomalSender extends SenderEntity{
	@Override
	public void Sender() {
		System.out.println("普通的邮件发送");
	}
}
public class PicSender extends SenderEntity{
	@Override
	public void Sender() {
		System.out.println("带有图片的邮件发送");
	}
}
//工厂类
public class SenderFactory {
	public SenderEntity SenderIt(String senderWay){
		SenderEntity se = null;
		if(!senderWay.equals("")&& senderWay!=null)
		switch(senderWay){
			case "发送普通邮件":
				se = new NomalSender();
				break;
			case "发送带有图片的邮件":
				se = new PicSender();
				break;
			case "发送带有附件的图片":
				se = new AttachSender();
				break;
			default:
				System.out.println("bug!!!!");
				return null;
		}
		return se;	
	}
}
//界面交互类
public class askwithHTML{
    main(){
        SenderFactory senderFactory = new SenderFactory();
        senderFactory.SenderIt(...);
   }
}

2,工厂方法模式

前面通过邮件发送的例子说了简单的工厂模式,如果现在需要加一个需求,需要发送又有图片又有附件又有内容的邮件。那么就需要通过继承发送类,实现新的逻辑发送类,然后再工厂中添加一个新的case逻辑去让客户端操作选择。说到这里,会发现简单工厂模式并没有很好的实现开放-封闭原则。简单工厂模式实现了对外的拓展了,但是因为工厂类为了保证客户端对于工具依赖性添加了必要的访问逻辑,比如你发送邮件不用管你是用那个类的实例,你只需要传入“发送带有附件的图片”这样的字样就可以使用了。对于添加拓展开放了,但是对于修改也开放了(需要修改SenderFactory中的逻辑判断),违背了封闭的原则,先来看看关系实现UML图:

针对上面的代码进行添加修改:将原本的工厂通过向上转型修改成单个的实例化工厂,可能会认为这样让程序变得更加的复杂。工厂方法模式没了之前的逻辑判断,将之前的修改变成了添加拓展的实现,转变了一下思维,使用开放-封闭的原则。这样子做的就相当于将逻辑的判断从工厂交给了客户端,让客户端去判断需要调用那个实例化工厂。但是由于其代码的逻辑复杂度与代码量的提高,所以并不是所有的情况都适用工厂方法模式。如果对于工程的需求后续拓展比较大,那就建议使用工厂方法模式去实现。

//父类工厂接口, 待实现的创建工厂方法
public interface FatherFactory {
	public SenderEntity createFatherFactory();
}
//普通邮件发送工厂
public class NomalFactory implements FatherFactory{
	@Override
	public SenderEntity createFatherFactory() {
		return new NomalSender();
	}
}
//带有图片的发送工厂
public class PicFactory implements FatherFactory{
	@Override
	public SenderEntity createFatherFactory() {
		return new PicSender();
	}
}
//带有附件的发送工厂
public class AttachFactory implements FatherFactory {
	@Override
	public SenderEntity createFatherFactory() {
		return new AttachSender();
	}
}

3,策略模式

策略模式对实现了同一个抽象类抽象方法或接口的算法逻辑进行分离封装,算法类之间可以根据需求相互替换。策略模式取决于用户,由用户判断使用哪种算法来获得自己想要的结果。来看一下UML代码结构图:

看了以下代码可能会问这样子的处理方法 和工厂模式的处理方法有什么大的区别吗,除了使用Context类进行了一层多的处理之外,但是实际上,在界面操作交互类上,可以看到,工厂模式需要知道基类SenderEntity与工厂类SenderFactory(原因很简单,你新添加的逻辑需要继承或者去实现SenderEntity,然后将你写好的逻辑无论是在简单工厂添加界面输入字样然后去进行case判断,还是如工厂模式中对于SenderFactory类继承或者实现,在很多小工厂中实现方法向上转型返回一个小工厂都需要用到这两个类)。但是到策略模式中你只需要知道Context既可以进行交互了,不用进行继承处理上的操作对象建立,这样较少了代码的耦合性。

//待实现的抽象类与抽象方法
public abstract class TotalNnum {
	public abstract double getTotalprice();
}
//继承实现抽象类的抽象方法
public class NomalPrice extends TotalNnum{
	@Override
	public double getTotalprice() {
		System.out.println("普通的收费标准");
		return 0;
	}
}
public class DisCount extends TotalNnum{
	@Override
	public double getTotalprice() {
		System.out.println("打折的收费标准");
		return 0;
	}
}
public class CutPrice extends TotalNnum{
	@Override
	public double getTotalprice() {
		System.out.println("满减的收费标准");
		return 0;
	}
}
public class CutAndDisCount extends TotalNnum{
	@Override
	public double getTotalprice() {
		System.out.println("打折满减都支持的收费标准");
		return 0;
	}
}
//Context类来整合所有的逻辑方法
public class Context {
	TotalNnum tn;
	public Context(){
	}
	public Context(TotalNnum tn){
		this.tn = tn;
	}
	public double getTotalPrice(){
		return tn.getTotalprice();
	}
}
//界面交互类
public class ChatWithHTML {
	Context context;
	public Double getKey(String key){
		switch(key){
		    case "nomal":
		    	context = new Context(new NomalPrice());
		    	return context.getTotalPrice();
		    case "cut" :
		    	context = new Context(new CutPrice());
		    	return context.getTotalPrice();
		    case "disCount" :
		    	context = new Context(new DisCount());
		    	return context.getTotalPrice();
		    case "cutAndDiscount" :
		    	context = new Context(new CutAndDisCount());
		    	return context.getTotalPrice();
		    default:
		    	return null;
		}
	}
}

4,装饰模式

装饰模式通过对已有功能添加一些新的功能,但是这个这些功能只需要在特定的情况下使用,所以不能在原有的代码上修改。

之所以不是将每个修饰类的对象都一一进行实例化在具体对象中方法调用,这样可以实现封闭性的原则,与特定情况下的使用,可以搭配使用不同的组合(例子:person的基类与穿衣服的操作)。通过基类中抽象需要进行的操作,具体的实体类来实现这个基类,对该操作下可以进行的修饰操作进行一个一个封装,形成一个对象链来组合使用。要求在每个修饰类中都要调用上一层基类的方法获取当前已经进行的内容。 其实例子还有很多,例如Person的基类,可以有穿衣吃饭的操作,你所需要实现的修饰就是穿衣的搭配与吃饭的搭配。

这里之所以以加密来说明,就是要强调装饰模式下,对象链封装的顺序是有要求的,比如你的密码如果先加密了在过滤就达不到这样的效果了。

/**加密基类,拥有待实现的加密操作**/
public abstract class LockComponent {
	public abstract void lockThisPwd();
}
/**具体的加锁对象**/
public class MyHtmlSpecilLock extends LockComponent{
	@Override
	public void lockThisPwd() {
		System.out.println("我的html登录pwd加锁操作");
	}
}
/**对加锁操作修饰,修饰类  过滤操作**/
public class ModifyAController extends LockComponent {
	LockComponent lc;
	public void setComenent(LockComponent lc){
		this.lc = lc;
	}
	@Override
	public void lockThisPwd() {
		lc.lockThisPwd(); //调用基类的操作内容
		System.out.println("密码的过滤操作不能有%,@,#...等特殊字符");
	}
}
/**对加锁操作修饰,修饰类  加密操作**/
public class ModifyBController extends LockComponent{
	LockComponent lc;
	public void setComenent(LockComponent lc){
		this.lc = lc;
	}
	@Override
	public void lockThisPwd() {
		lc.lockThisPwd(); //调用基类的操作内容
		System.out.println("md5密码加密操作。。");
	}
}
/**客户端操作部分**/
public class UseComponent {
	public static void main(String[] args) {
		MyHtmlSpecilLock msl = new MyHtmlSpecilLock();
		ModifyAController mac = new ModifyAController();
		ModifyBController mbc = new ModifyBController();
		mac.setComenent(msl);
		mbc.setComenent(mac);
		mbc.lockThisPwd();
	}
}

5,代理模式

代理模式是一个很常用的设计模式,它通过对上一级的封装,通过让客户端访问代理来实现基本的内容。听起来和上面的装饰模式很像,甚至代码的实现封装性质上都有很多相似点。但是装饰模式是对上一级内容的修饰,并没有对上一级对象访问的控制,而代理模式更加注重对上一级对象访问的控制作用,例如你可以通过继承的方式,对必要的不能访问的私有方法不能进行访问,起到控制对象访问的作用。下面来看一个很简单的例子:(例子出自《大话设计模式》)

这里代理对象实现追求者行为的三个基本方法,在方法中对追求者对象方法进行封装。第一,可以控制为其它的追求者局部行为进行封装起到控制访问的作用。第二,对于底层访问对象进行了有效的保护作用。代理模式应用的比较广泛的就是AOP编程,面向切面编程,其中比如过滤器操作。也就是控制访问,使用到了代理模式。

//接口,送礼物的三个待实现方法
public interface GiveGift {
	public void sendFlower();
	public void sendFood();
	public void sendMessageLove();
}
//追求者
public class Suitors implements GiveGift{
	private String girlName;
	public Suitors(){
	}
	public Suitors( String girlName){
		this.girlName = girlName;
	}
	@Override
	public void sendFlower() {
		System.out.println("送给" + girlName +"的花");
	}
	@Override
	public void sendFood() {
		System.out.println("送给" + girlName +"零食");
	}
	@Override
	public void sendMessageLove() {
		System.out.println("送给" + girlName +"情书");		
	}
}
//代理类,代理Suitors的行为
public class SendProxy implements GiveGift{
	private String girlName;
	private Suitors sors;
	public SendProxy(){
	}
	public SendProxy(String girlName,Suitors sors){
		this.girlName = girlName;
		this.sors = new Suitors(girlName);
	}
	@Override
	public void sendFlower() {
		sors.sendFlower();
	}

	@Override
	public void sendFood() {
		sors.sendFood();
	}

	@Override
	public void sendMessageLove() {
		sors.sendMessageLove();
	}
}
//客户端实现
public class UserMain {
	private static Suitors st;
	public static void main(String[] args) {
		String name = "小红";
		SendProxy sp = new SendProxy(name,st);
		sp.sendFlower();
		sp.sendFood();
		sp.sendMessageLove();
	}
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值