您的位置:首页 > 其它

设计模式---工厂模式,我的理解,总结

2017-02-25 18:52 148 查看

1,首先说,什么是设计模式?设计模式为什么会出现?它的出现是为了解决什么问题?

设计模式,design pattern,是一套被反复使用,多数人知晓的,代码设计经验的总结。

设计模式是为了1,提高代码重用性,2,提高代码可扩展性,3,代码更容易被他人所理解,提高代码可读性,保证代码可靠性。

代码引入设计模式的目的大概是以上3个目的, 如何实现这3个目的呢,方式就是,千方百计的降低代码耦合度来实现,引入设计模式也是为了降低代码耦合度从而实现那3个目的。

什么是耦合?怎么解耦和?

其实耦合就是系统内部各个部分之间关联度太高了,牵一发动全身。解耦和就是降低这各个部分之间的关联,解耦和的原则,其实就是设计模式的6大原则,如何解耦和?很简单,其实就是隔离变化,分离变化,将变化的部分单独隔离出来进行处理,这样就降低了各部分之间的关联度,因为已经将一个大部分拆成了很多小部分,

每一种设计模式的出现,都是为了解决现实开发中不断重复发生的问题而不断积淀产生的,可以说,任何一种设计模式,都完美的解决了一种不断重复出现的问题,或者说,是某一种问题的核心的解决方案,设计模式就想模板,使代码编程工程化,实现工厂中流水线一样的作业。

首先说说使用最广泛,最简单的工厂模式,

什么是工厂模式?从字面意思,似乎想到的是一个factory,进去的是原料,出来的是产品,这就是工厂,设计模式,当然是现实的高度抽取,但是又是来自于现实的情景,通过代码解释似乎更否和程序员的逼格。

工厂模式(Factory Method)

没对比就没有伤害,对比一下使用和没使用工厂模式的区别,然后再对工厂进行优化。

1,没有使用工厂模式的情形

interface Fruit{    // 定义一个水果接口
public void eat() ; // 吃水果
}
class Apple implements Fruit{
public void eat(){
System.out.println("** 吃苹果。") ;
}
};
class Orange implements Fruit{
public void eat(){
System.out.println("** 吃橘子。") ;
}
};
public class InterfaceCaseDemo03{
public static void main(String args[]){
Fruit f = new Apple() ; // 实例化接口
f.eat() ;
}
};


分析:

这里没有使用工厂,可以发现,代码并没有语法错误,但是设计的真的是糟糕透了,主方法相当于客户端,原则上来说,客户端的代码越少越好,客户端尽可能不要有大的频繁的改动。

然而子这里,可以发现,直接在主方法中指定了要操作的子类,客户端和子类实例紧紧的耦合在了一起,当我想扩展程序,当想要更换子类的时候,想更换一个Orange实例的时候,就肯定需要修改客户端,就必须得再客户端,把子类实例改为
new Orangle();
就很不合理。

解决:既然发现是耦合度太高,解决方案当然就是解耦和了,

进一步分析:

可以发现,其实问题就是处在这一句代码中
Fruit f = new Apple() ;
,就是这里存在变化,可能出现若干的不同类型的子类对象,使用父类对象接收子类实例,那么就可以从这个地方着手,隔离变化。

2,初步使用工厂

interface Fruit{    // 定义一个水果接口
public void eat() ; // 吃水果
}
class Apple implements Fruit{
public void eat(){
System.out.println("** 吃苹果。") ;
}
};
class Orange implements Fruit{
public void eat(){
System.out.println("** 吃橘子。") ;
}
};
class Factory{  // 定义工厂类
public static Fruit getInstance(String className){
Fruit f = null ;
if("apple".equals(className)){  // 判断是否要的是苹果的子类
f = new Apple() ;
}
if("orange".equals(className)){ // 判断是否要的是橘子的子类
f = new Orange() ;
}
return f ;
}
};
public class InterfaceCaseDemo04{
public static void main(String args[]){
Fruit f = Factory.getInstance("apple") ;    // 实例化接口
f.eat() ;
}
};


分析:

这里新增了一个类,factory,实例化不同对象的动作,全部归纳在这个类里面进行处理了,实现了这一变化部分的隔离,耦合度果然大大降低了,但是这里又出现了一个新的问题—-》代码健壮性的问题,当传入的参数,不正确,既不是“apple”又不是“ orangle”,而是其他的字符的时候,就返回了一个null对象,这个null去调用eat()方法,当然是会程序崩溃的,如何保证虽然传入了错误的参数,程序依然不崩溃,还给一个提示呢?这就是代码健壮性。

3,优化工厂:

interface Fruit{    // 定义一个水果接口
public void eat() ; // 吃水果
}
class Apple implements Fruit{
public void eat(){
System.out.println("** 吃苹果。") ;
}
};
class Orange implements Fruit{
public void eat(){
System.out.println("** 吃橘子。") ;
}
};
class Factory{  // 定义工厂类
public static Fruit getInstance(String className){
Fruit f = null ;
if("apple".equals(className)){  // 判断是否要的是苹果的子类
f = new Apple() ;
}
if("orange".equals(className)){ // 判断是否要的是橘子的子类
f = new Orange() ;
}
return f ;
}
};
public class InterfaceCaseDemo05{
public static void main(String args[]){
Fruit f = Factory.getInstance(args[0]) ;    // 实例化接口
if(f!=null){    // 判断是否取得实例
f.eat() ;
}
}
};


这个例子里,就做了健壮性验证了,看起来就好多了,

其实可以换一个例子,来说明这个工厂的进化过程:

1,简易工厂



public interface Sender {
public void Send();
}

public class MailSender implements Sender {
@Override
public <
da67
span class="hljs-keyword">void Send() {
System.out.println("this is mailsender!");
}
}

public class SmsSender implements Sender {

@Override
public void Send() {
System.out.println("this is sms sender!");
}
}

public class SendFactory {

public Sender produce(String type) {
if ("mail".equals(type)) {
return new MailSender();
} else if ("sms".equals(type)) {
return new SmsSender();
} else {
System.out.println("请输入正确的类型!");
return null;
}
}
}

测试:
public class FactoryTest {

public static void main(String[] args) {
SendFactory factory = new SendFactory();
Sender sender = factory.produce("sms");
sender.Send();
}
}


以上代码似乎看起来已经不错了,但是还是可以进行优化的:

2,优化工厂—避免返回null对象问题

分析:

在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。



public interface Sender {
public void Send();
}

public class MailSender implements Sender {
@Override
public void Send() {
System.out.println("this is mailsender!");
}
}

public class SmsSender implements Sender {

@Override
public void Send() {
System.out.println("this is sms sender!");
}
}

public Sender SendFactory(){
return new MailSender();
}

public Sender produceSms(){
return new SmsSender();
}
}

public class FactoryTest {

public static void main(String[] args) {
SendFactory factory = new SendFactory();
Sender sender = factory.produceMail();
sender.Send();
}
}


分析:

这就避免了null对象的问题,但是似乎还是可以继续优化呢

3,继续优化工厂—静态工厂

public interface Sender {
public void Send();
}

public class MailSender implements Sender {
@Override
public void Send() {
System.out.println("this is mailsender!");
}
}

public class SmsSender implements Sender {

@Override
public void Send() {
System.out.println("this is sms sender!");
}
}

public class SendFactory {

public static Sender produceMail(){
return new MailSender();
}

public static Sender produceSms(){
return new SmsSender();
}
}

public class FactoryTest {

public static void main(String[] args) {
Sender sender = SendFactory.produceMail();
sender.Send();
}
}


分析:

实现了静态工厂,但是似乎发现,这使用了一个工厂对变化进行隔离,似乎还是不够,变化还是不能够很好的控制,当我想扩展功能,比如,现在有发送邮件,发送短信,再扩展一个发送语音的功能的时候,还是要修改之前的代码,要修改工厂,这并不是一个好的现象,并不是一个好的开发设计,需求是——>>>>,

直接新增,要扩展的部分,1:新增自己的代码,2:而不去深入详细阅读之前已经写好的代码,不用深入看懂每一个变量所代表的意思。直接新增自己的代码进工程,就可以完成代码的开发,完成项目的升级扩展

问题:既然需求又一次出来,那怎么做呢????

解决方案:其实很简单,就是继续隔离变化,新增工厂咯。

4继续优化工厂–抽象工厂

仔细分析

上面的工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。因为抽象工厂不太好理解,我们先看看图,然后就和代码,就比较容易理解。



public interface Sender {  //第一工厂接口
public void Send();
}

public class MailSender implements Sender {
@Override
public void Send() {
System.out.println("this is mailsender!");
}
}

public class SmsSender implements Sender {

@Override
public void Send() {
System.out.println("this is sms sender!");
}
}

public interface Provider {  //第二工厂接口
public Sender produce();
}

public class SendMailFactory implements Provider {

@Override
public Sender produce(){
return new MailSender();
}
}

public class SendSmsFactory implements Provider{

@Override
public Sender produce() {
return new SmsSender();
}
}

测试:
public class Test {

public static void main(String[] args) {
Provider provider = new SendMailFactory();
Sender sender = provider.produce();
sender.Send();
}
}


分析:

这样的工厂,当需要扩展一个新的功能,比如发送语音工鞥呢,则只需做一个实现类,语音类,实现Sender接口,同时做一个工厂类,实现Provider接口,就OK了,无需去改动现成的代码。

这样做,拓展性很好,非常棒的满足了需求!

以上代码,类图,来自网络,下面的博客地址,这里拿来学习使用,总结,尊重知识产权。

参考博客:这个帖子写的非常好,

参考下
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: