`

工厂模式及模板方法模式深度思考

阅读更多
(注:代码在最底下的附件)
1.简单工厂
郭大神和盘哥在说好想买ipad,用代码实现一下
不用模式的设计
public interface Product {

    String getDesc();
}

public class IpadProduct implements Product {

    @Override
    public String getDesc() {
        return "Ipad2";
    }

}

public class Client {

    public static void main(String[] args) {
        Product product = new IpadProduct();
        System.out.println("郭大神说好想买" + product.getDesc() + ",但没钱!!!");
        product = new IpadProduct();
        System.out.println("盘哥说我好想买" + product.getDesc() + ",但没钱!!!");
    }
}

有何问题?
如果想买的iphone5时怎么办?
得找到所有new IpadProduct改成new IphoneProduct
而且改的是客户端的代码

应用模式的设计
public class IphoneProduct implements Product {

    @Override
    public String getDesc() {
        return "Iphone5";
    }
}
public class SimpleFactory {

    public static Product getProdcut() {
        return new IpadProduct();
    }
}

public class Client {

    public static void main(String[] args) {
        Product product = SimpleFactory.getProduct();
        System.out.println("郭大神说好想买" + product.getDesc() + ",但没钱!!!");
        product = SimpleFactory.getProduct();
        System.out.println("盘哥说我好想买" + product.getDesc() + ",但没钱!!!");
    }
}

无模式遇到的问题如何解决?
只要在SimpleFactory.getProdcut()换成IphoneProdcut即可
优点
创建对象收拢,扩展性加强了。
扩展时不需要修改客户端代码。
对象创建与使用解耦
缺点
多出一个工厂类

2.工厂方法


应用工厂方法模式的设计
abstract public class Person {
    private String name;

    Person(String name){
        this.name = name;
    }

    abstract Product getProduct();

    public void say() {
        Product product = getProduct();
        System.out.println(name + "说我好想买" + product.getDesc() + ",但没钱!!!");
    }
}

public class GuoPerson extends Person {
    public GuoPerson(){
        super("郭大神?);
    }

    @Override
    Product getProduct() {
        return new IpadProduct();
    }
}

public class ShenPerson extends Person {
    public ShenPerson(){
        super("盘哥");
    }

    @Override
    Product getProduct() {
        return new IpadProduct();
    }
}

public class ModeClient {

    public static void main(String[] args) {
        Person person = new GuoPerson();
        person.say();
        person = new ShenPerson();
        person.say();
    }
}

优点
可以在不知道具体产品下实现编程
可以在不改变业务代码上很容易扩展出一个新的产品
缺点
多出几个具体工厂类

3.抽象工厂
考虑一下生产ipad和iphone的一个程序
工厂模式的设计有何问题?

public interface Ipad extends Product {
}
public class HongKongIpad implements Ipad {
    @Override
    public String getDesc() {
        return "香港版的Ipad";
    }
}
public class USAIpad implements Ipad {
    @Override
    public String getDesc() {
        return "美国版的Iphone";
    }
}
public interface Iphone extends Product {
}
public class HongKongIphone implements Iphone {
    @Override
    public String getDesc() {
        return "香港版的Iphone";
    }
}
public class USAIphone implements Iphone {
    @Override
    public String getDesc() {
        return "美国版的Iphone";
    }
}
public class SimpleFactory {
    public static Ipad createIpad(int type) {
        if (type == 1) {
            return new HongKongIpad();
        }

        return new USAIpad();
    }

    public static Iphone createIphone(int type) {
        if (type == 1) {
            return new HongKongIphone();
        }

        return new USAIphone();
    }
}
public class Client {
    public static void main(String[] args) {
            Ipad ipad = SimpleFactory.createIpad(1);
            Iphone iphone = SimpleFactory.createIphone(1);
            System.out.println("我采购的是:" + ipad.getDesc() + "和" + iphone.getDesc());
//            ipad = SimpleFactory.createIpad(2);
//            iphone =  SimpleFactory.createIphone(2);
//            System.out.println("我采购的是:" + ipad.getDesc() + "和" + iphone.getDesc());
    }
}

工厂模式的设计有何问题?

客户端想只买一家公司的产品,客户端需要了解每种类型是出自哪一家公司?
港版ipad与iphone是出自同一家公司,美版ipad与iphone也是出自同一样公司,对于采购时

它只要报一下要什么哪个品牌的就可以买到同一个品牌的ipad和iphone


应用抽象工厂模式的设计


public interface AppleFactory {
    
    Ipad createIpad();
    
    Iphone createIphone();
}
public class HongKongCompanyAppleFactory implements AppleFactory {
    @Override
    public Ipad createIpad() {
        return new HongKongIpad();
    }

    @Override
    public Iphone createIphone() {
        return new HongKongIphone();
    }
}
public class USACompanyAppleFactory implements AppleFactory {
    @Override
    public Ipad createIpad() {
        return new USAIpad();
    }

    @Override
    public Iphone createIphone() {
        return new USAIphone();
    }
}
public class ModeClient {
    public static void main(String[] args) {
        AppleFactory appleFactory = new HongKongCompanyAppleFactory();
        Ipad ipad = appleFactory.createIpad();
        Iphone iphone = appleFactory.createIphone();
        System.out.println("我采购的是:" + ipad.getDesc() + "和" + iphone.getDesc());
//        appleFactory = new USACompanyAppleFactory();
//        ipad = appleFactory.createIpad();
//        iphone = appleFactory.createIphone();
//        System.out.println("我采购的是:" + ipad.getDesc() + "和" + iphone.getDesc());
     }
}

优点

缺点

深度思考
spring容器是最大的工厂
BeanFactory.getBean("xxx")
FileSystemXmlApplicationContext/ClassPathXmlApplicationContext

下面吐槽一下郭大神
考虑一下郭大神的家谱
...
郭大神的祖父
|
郭大神的父亲
|
郭大神
|
郭大神的儿子
...
郭大神的祖父创造了郭大神的父亲,郭大神的父新创造了郭大神,郭大神创造了郭大神的儿子
盘哥这边呢
...
盘哥的祖父
|
盘哥的父亲
|
盘哥
|
盘哥的儿子
...
用类来表示
interface Grandfather{
    Father createFather();
}
interface Father{
    Self createSelf();
}
interface Self {
    Son createSon();
}

如果我把郭明先生的祖父换成了姓郑(盘哥姓郑),则
当我换掉Grandfather时,奇迹出现了,整个家族的姓都变了。
从上面来看其实是工厂模式与工厂模式组合使用,经过组合后我们能写出具备极其扩展性的代码。
上面的原理是把工厂抽象成是一个产品(就是把工厂也当成是产品,那么生产这个产品的就是工厂的工厂。),于是就出现了"工厂的工厂的工厂"生产出"工厂的工厂","工厂的工厂"生产"工厂",最后工厂生成产品。这样就是级联使用工厂。
我们可以在任意一个环节替换实现,于是可以产生一个从大到小的扩展点。

考虑一下我们的建站平台框架的设计
站点有站点的接口, 同时还有站点资源接口(静态资源:js,css), 站点渲染接口, 站点数据接口。站点数据又可以分为站点数据读取接口, 和站点数据变更接口。
如果我设计下面这样的一个接口
interface SiteAPIFactory
{
    getSiteAPI();
}
interface SiteAPI{
  getSiteResourceAPI();
  getSiteDataAPI();
  getRenderAPI();
}
interface SiteDataAPI{
  getSiteDataReadAPI();
    getSiteDataDesignAPI();
}
interface SiteDataReadAPI{
    getSiteData();
}
interface SiteDataDesignAPI{
    updateSiteData();
    deleteSiteData();
}

经过上面这样设计之后, 如果我替换了SiteAPIFactory的实现, 我就可以操控整个站点的所有接口实现, 当我只替换SiteDataAPI时我能控制站点读取与写入数据的实现。也就是说从大到小的粒点扩展点我都支持了。做为平台的设计, 应用就可以根据需要自行替换实现。从而达到各种粒度的扩展。
很多模式都能组合起来使用,同时许多模式能与自身组合使用,像工厂,桥接等等
同时如果我写个SiteAPIUtil的获取SiteAPIFacotry,于是我就能提供所有接口了

SiteAPIUtil{
  SiteAPIFactory getSiteAPIFactory(){
      DefaultSiteAPIFactory.instance
  };
    SiteAPI getSiteAPI(){
        getSiteAPIFactory().getSiteAPI();
    };
    SiteDataAPI getSiteDataAPI(){
        getSiteAPI().getSiteDataAPI();
    };
    SiteDataDesignAPI getSiteDataDesignAPI(){
        getSiteDataAPI().getSiteDesignAPI();
    }
    ...
}

再认真思考一下,你会发现SiteAPIUtil其实也是一个简单工厂,可以命名为SiteAPISimpleFactory

4.模板方法

考察一下郭大神与盘哥是如何上班的
不用模式的设计
public interface Person {
    String getName();
    void summary();
}

public class GuoPerson implements Person {
    @Override
    public void summary() {
        System.out.println(getName() + "起床");
        System.out.println(getName() + "坐公交去上班");
        System.out.println(getName() + "上班到9点时上了一次厕所");
        System.out.println(getName() + "上班到10点时上了一次厕所");
        System.out.println(getName() + "上班到11点时上了一次厕所");
        System.out.println(getName() + "坐公交回到家");
        System.out.println(getName() + "洗个澡睡觉了");
    }

    @Override
    public String getName() {
        return "郭大神";
    }
}

public class ShenPerson implements Person {
    @Override
    public void summary() {
        System.out.println(getName() + "起床");
        System.out.println(getName() + "骑自行车去上班");
        System.out.println(getName() + "上班到10点时上了一次厕所");
        System.out.println(getName() + "骑自行车回到家");
        System.out.println(getName() + "洗个澡睡觉了");
    }

    @Override
    public String getName() {
        return "盘哥";
    }
}

public class Client {
    public static void main(String[] args) {
        Person person = new GuoPerson();
        person.summary();
        person = new ShenPerson();
        person.summary();
    }
}

不用模式有何问题?
他们两个上班过程基本上是一样的, 出现了重复的代码。

再考察一个人得同样要写很多重复的代码。
应用模式的设计
abstract public class AbstractPerson implements Person {

    public void summary() {
        System.out.println(getName() + "起床");
        goToCompany();
        work();
        backToHome();
        System.out.println(getName() + "洗个澡睡觉了");
    }
    abstract public void goToCompany();
    abstract public void work();
    abstract public void backToHome();
}
public class GuoPerson extends AbstractPerson {
    @Override
    public String getName() {
        return "郭大神";
    }

    @Override
    public void goToCompany() {
        System.out.println(getName() + "坐公交去上班");
    }

    @Override
    public void work() {
        System.out.println(getName() + "上班到9点时上了一次厕所");
        System.out.println(getName() + "上班到10点时上了一次厕所");
        System.out.println(getName() + "上班到11点时上了一次厕所");
    }

    @Override
    public void backToHome() {
        System.out.println(getName() + "坐公交回到家");
    }
}
public class ShenPerson extends AbstractPerson {
    @Override
    public String getName() {
        return "盘哥";
    }

    @Override
    public void goToCompany() {
        System.out.println(getName() + "骑自行车去上班");
    }

    @Override
    public void work() {
        System.out.println(getName() + "上班到10点时上了一次厕所");
    }

    @Override
    public void backToHome() {
        System.out.println(getName() + "骑自行车回到家");
    }
}
public class ModelClient {
    public static void main(String[] args) {
        Person person = new GuoPerson();
        person.summary();
        person = new ShenPerson();
        person.summary();
    }
}

优点
没有重复的代码了,新增一个人时也同样减少一直重复的代码
如果在上班完加一个先吃个饭再回家,则只需要在抽象类里加上这行代码,无需改动所有Person
缺点
多出一个类,有时多出好几个方法
深度思考
模式方法模式其实就是一个抽象的过程,是最小抽象,位于抽象的最低层
与工厂方法的区别



总结:

简单工厂能把具体实现包装起来,让客户端真正达到面向接口编程

工厂方法可以在高层进行编码,让服务端的产品线真正达到面向接口编程

抽象工厂能聚合整个产品簇,让整个服务端的多个产品线真正达到面向接口编程

模板方法同样是在高层进行编码,也同样是面向接口编程。

但工厂方法及抽象工厂方法着重抽象的是产品,而模板方法着重抽象的是步骤。

而我们通常会两者一起结合起来使用。



思考上面那个模板模式,你会发现去上班和回到家代码很相似,

于是我们组合使用工厂模式又能去除重复代码。

在抽象类返回一个交通工具,上下班和回到家就可以在基类编程了。

代码如下:

public interface Vehicle {
    String by();
}

public class Bus implements Vehicle {
    @Override
    public String by() {
        return "坐公交车";
    }
}

public class Bike implements Vehicle {
    @Override
    public String by() {
        return "骑自行车";
    }
}

abstract public class AbstractPerson implements Person {
    public void summary() {
        Vehicle vehicle = getVehicle();
        System.out.println(getName() + "起床");
        System.out.println(getName() + vehicle.by() + "去上班");
        work();
        System.out.println(getName() + vehicle.by() + "回到家");
        System.out.println(getName() + "洗个澡睡觉了");
    }
    abstract public Vehicle getVehicle();
    abstract public void work();
}

public class GuoPerson extends AbstractPerson {
    @Override
    public String getName() {
        return "郭大神";
    }

    @Override
    public void work() {
        System.out.println(getName() + "上班到9点时上了一次厕所");
        System.out.println(getName() + "上班到10点时上了一次厕所");
        System.out.println(getName() + "上班到11点时上了一次厕所");
    }

    @Override
    public Vehicle getVehicle() {
        return new Bus();
    }
}

public class ShenPerson extends AbstractPerson {
    @Override
    public String getName() {
        return "盘哥";
    }

    @Override
    public void work() {
        System.out.println(getName() + "上班到10点时上了一次厕所");
    }

    @Override
    public Vehicle getVehicle() {
        return new Bike();
    }
}

这样,在AbstractPerson的子类只需要返回交通工具, 就可以少掉两个方法

分享到:
评论

相关推荐

    Java与模式pdf

    2. **创建型模式**:包括单例模式、工厂模式(简单工厂、工厂方法、抽象工厂)、建造者模式、原型模式等,它们关注于如何创建对象,减少类之间的耦合。 3. **结构型模式**:如适配器模式、装饰器模式、代理模式、...

    设计模式解析.pdf

    《设计模式解析》这一标题暗示了书籍将深度探讨各种设计模式,包括其原理、应用及背后的思维逻辑,帮助读者掌握并灵活运用这些模式来优化软件设计。 #### 描述解析:设计模式的入门与精通之路 描述中提到设计模式...

    设计模式PPT

    首先,我们来看三个主要的设计模式:抽象工厂、模板模式和装饰器模式。 **抽象工厂模式**(Abstract Factory Pattern)是一种创建型设计模式,它提供了一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体...

    这是一个基于深度学习分类模板

    深度学习使机器模仿视听和思考等人类的活动,解决了很多复杂的模式识别难题,使得人工智能相关技术取得了很大进步。 [1] 深度学习是一类模式分析方法的统称,就具体研究内容而言,主要涉及三类方法: [2] (1)基于...

    《Java与模式 阎宏 摘录》.doc 更新中……

    《Java与模式 阎宏 摘录》是一本深度探讨Java编程语言与设计模式的书籍,由著名IT专家阎宏所著。这本书旨在帮助Java开发者深入理解面向对象设计原则,掌握并应用各种设计模式,提升软件开发的效率和质量。通过摘录,...

    设计新思维:范型编程与设计模式之应用(中文版)

    总的来说,《设计新思维:范型编程与设计模式之应用》是一本深度与广度兼备的C++技术指南,它不仅教导读者如何运用范型编程和设计模式,还启发了开发者对于软件设计的全新思考方式。通过阅读这本书,无论是初学者...

    设计模式精解3chm文档

    设计模式是解决特定软件设计问题的模板或框架,它提供了一种标准化的方法来处理常见的编程挑战。与面向对象设计相比,设计模式强调的是行为封装而非单纯的继承。这意味着设计模式关注于如何组织代码,使其具有更高的...

    Head_First_设计模式

    GoF)定义的23种经典设计模式,包括但不限于Strategy(策略)、Observer(观察者)、Decorator(装饰器)、Abstract Factory(抽象工厂)、Factory Method(工厂方法)、Singleton(单例)、Command(命令)、...

    深度学习的教学创新研究与实践.pdf

    STEM教育的普及和深入发展为各国教育模式的创新提供了模板,这对于深度学习的教学创新具有重要的参考价值。 6. 实验重构与系统工程: 深度学习的实施被看作是一项系统工程。这要求教育者不仅仅将重点放在技术上,...

    C++模板编程 C++沉思录 代码设计与重用

    《C++沉思录》是一部深度剖析C++哲学与实践的著作,它引导读者思考如何编写优雅、高效的C++代码。书中涵盖了C++的关键特性,如面向对象编程、模板元编程、异常处理和STL(标准模板库)的使用。通过阅读此书,开发者...

    java简历模板

    5. **设计模式理解**:表明对Java设计模式的掌握程度,如单例模式和工厂模式,这反映了解决复杂问题的能力。 6. **项目经验**:列举实际项目经验,如本例中的网上购物系统。详细说明项目的技术栈、功能实现和自己的...

    Head First Design Patterns

    - **行为型模式**:包括策略模式、模板方法模式、观察者模式、迭代器模式、访问者模式、命令模式、备忘录模式、状态模式、解释器模式等。这些模式侧重于对象间的交互方式。 #### 五、结语 《Head First Design ...

    C++高级编程与个人学习思考应用

    6. **设计模式**:设计模式是解决软件设计中常见问题的经验总结,如工厂模式、单例模式、装饰器模式等,熟练运用设计模式能提升代码质量。 接下来,我们将逐一分析压缩包内的文件,它们代表了C++高级编程在不同领域...

    C++设计新思维_C++_

    《C++设计新思维》是一本深入探讨C++编程技巧和设计模式的书籍,它将泛型编程与设计模式的概念巧妙地结合在一起,为程序员提供了一种全新的思考方式。在C++的世界里,理解并掌握这些知识对于提升编程效率和写出高...

    基于_校企合作_产教融合_模式下的软件技术_省略_以山东理工职业学院软件技术专业_计算机专业论文范文模板、范本.pdf

    总的来说,文章揭示了当前软件技术专业校企合作模式的优点与不足,为深化产教融合提供了思考路径。未来,教育机构应持续探索与企业的紧密合作,既要满足行业需求,也要关注学生的个性化成长,以期在培养高素质技术...

    软件工程与项目管理讲义.doc

    作者提倡探讨和推广能引导这三个主体走向成功的"方法论和模式",方法论是系统性的思考工具,帮助解决根本问题,而模式则是可复用的解决方案模板,如设计模式、编程规范等。 解决软件危机的关键在于发展和应用能够...

    精通并发与netty视频教程(2018)视频教程

    75_适配器模式与模板方法模式在入站处理器中的应用 76_Netty项目开发过程中常见且重要事项分析 77_Java NIO Buffer总结回顾与难点拓展 78_Netty数据容器ByteBuf底层数据结构深度剖析 79_Netty的ByteBuf底层实现大...

    精通并发与 netty 视频教程(2018)视频教程

    Channel选择器工厂与轮询算法及注册底层实现 72_Netty线程模型深度解读与架构设计原则 73_Netty底层架构系统总结与应用实践 74_Netty对于异步读写操作的架构思想与观察者模式的重要应用 75_适配器模式与模板方法模式...

    Head_First_Design_Patterns.pdf (英文版)

    《Head_First_Design_Patterns》是一本专...总之,《Head_First_Design_Patterns》不仅是一本技术书籍,它还引导读者思考如何通过设计模式来优化软件架构,提高代码质量,是一本值得每个软件开发者深度阅读的经典之作。

Global site tag (gtag.js) - Google Analytics