交给子类

一、Template 模式-将具体处理交给子类

1. 场景

某一个简单程序,用于将字符或者字符串循环输出 5 次

2. UML

image.png

3. Code

3.1 模板模式 定义在 AbstractDisplay中

/**
 * @author CSZ
 */
public abstract class AbstractDisplay {

    public abstract void open();
    public abstract void print();
    public abstract void close();
    // 以下就是模板方法
    public final void display(){
        open();
        for (int i = 0; i < 5; i++) {
            print();
        }
        close();
    }
}

3.2 第一个子类 字符处理

/**
 * @author CSZ
 */
public class CharDisplay extends AbstractDisplay{
    private char ch;

    public CharDisplay(char ch) {
        this.ch = ch;
    }

    @Override
    public void open() {
        System.out.print("<<");
    }

    @Override
    public void print() {
        System.out.print(ch);
    }

    @Override
    public void close() {
        System.out.println(">>");
    }
}

3.3 第二个子类处理

/**
 * @author CSZ
 */
public class StringDisplay extends AbstractDisplay{

    private String string;
    private int width;

    public StringDisplay(@NonNull String string) {
        this.string = string;
        this.width = string.getBytes().length;
    }

    @Override
    public void open() {
        printLine();
    }

    @Override
    public void print() {
        System.out.println("|" + string + "|");
    }

    @Override
    public void close() {
        printLine();
    }

    private void printLine(){
        System.out.print("+");
        for (int i = 0; i < width; i++) {
            System.out.print("-");
        }
        System.out.println("+");
    }
}

3.4 测试方法

/**
 * @author CSZ
 */
public class MainTest {
    public static void main(String[] args) {
        AbstractDisplay display1 = new CharDisplay('H');
        AbstractDisplay display2 = new StringDisplay("Hello");
        display1.display();
        display2.display();
    }
}

测试效果

<<HHHHH>>
+-----+
|Hello|
|Hello|
|Hello|
|Hello|
|Hello|
+-----+
image.png

根据UML 加深理解

  1. 在一个类中,我们定义了很多操作,比如业务逻辑类,有时常用的一部分逻辑我们抽取公共部分,抽成一个方法,对于一个对象,如果他想实现某个功能,他每次都要先调用A方法再调用B方法,然后补充一些信息在调用C方法,顺序是一直的只不过ABC会因为对象的不同,而有细微差异,此时就适合使用 模板模式。
  2. 另一方面,所有的方法,由于父类定义了骨架,具体实现交由子类,我们就必须使两者紧密联系起来,在不知道父类的源码下,想编写子类是不太可能的。
    3.父类与子类要保持一致,对于构造函数中的输入值,其实保存在了 父类变量中,无论保存着是哪个子类的实例,程序都可以正常运行。
  3. 这里书中提出了一种有意思的思考方向:通常,我们会站在子类的角度,子类继承了父类的属性和方法,子类还可以定义自己的方法。如果我们站在父类的角度呢?角度一变,我们在父类中只声明了抽象方法,并且把实现交给了子类,换言之,就是我父类要做的事情只声明,而实行延迟到交给子类去做。所以这种交由子类实现也可以看作,子类责任。


二、Factory 模式(简单工厂)-将实例的生成交给子类

1. 需求分析

这里的工厂模式是简单工厂模式,实际上是连创建对象的过程也下方给了子类。

2. UML

image.png

3. Code

3.1简单工厂-实际上是基于 模板模式

/**
 * @author CSZ
 */
public abstract class Factory {
    public final Product create(String owner){
        Product p = createProduct(owner);
        registerProduct(p);
        return p;
    }

    protected abstract Product createProduct(String owner);
    protected abstract void registerProduct(Product product);
}

3.2 抽象类声明了方法

/**
 * @author CSZ
 */
public abstract class Product {

    public abstract void use();
}

3.3 具体工厂

/**
 * @author CSZ
 */
public class IDCardFactory extends Factory {

    private List owners = new ArrayList();

    @Override
    protected Product createProduct(String owner) {
        return new IDCard(owner);
    }

    @Override
    protected void registerProduct(Product product) {
        owners.add(((IDCard)product).getOwner());
    }

    // 体现作为实际的工厂,还可以额外补充一些操作,类似于 spring 中 context.getBeanDefinitionNames();
    // public List getOwners(){
    //     return owners;
    // }
}

3. 4 抽象类 Product 的实现类

/**
 * @author CSZ
 */
public class IDCard extends Product {

    private String owner;

    IDCard(String owner) {
        System.out.println("制作" + owner + "的 ID 卡");
        this.owner = owner;
    }

    @Override
    public void use() {
        System.out.println("使用" + owner + "的 ID 卡");
    }

    public String getOwner(){
        return owner;
    }
}

3.5 测试类

/**
 * @author CSZ
 */
public class MainTest {
    public static void main(String[] args) {
        Factory factory = new IDCardFactory();
        Product a = factory.create("A");
        Product b = factory.create("B");
        Product c = factory.create("C");
        a.use();
        b.use();
        c.use();
    }
}
/**
 * @author CSZ
 */
public class MainTest {
    public static void main(String[] args) {
        // 父类引用指向子类的实例,当我们有了新的工厂产生新的产品时,直接替换工厂即可
        Factory factory = new IDCardFactory();
        Product a = factory.create("A");
        Product b = factory.create("B");
        Product c = factory.create("C");
        a.use();
        b.use();
        c.use();
    }
}

总结:

  1. 实际上,在 Factory 中规定了,怎样创建一个 Product 对象,简单说就是通过 create() 方法创建并返回一个Product 的对象。而在 create() 中要做几个操作,于是结合前面的模板模式学习,我们不难想出,将这几个操作的方法进行抽象,具体的实现延迟到子类去实现。
  2. 这里面关键的区分,Factory 是声明生产相同类型的产品对象,但是 Product 才是声明业务方法的主体。于是当我们的工厂和抽象产品完后,我们要创建具体的工厂,具体的产品,本案例中使用的是 IDCard。
    Product 产品之一是 IDCard。正如标题所说的,交由子类,Product 交给子类的责任就是 具有 use() 这个方法的责任,所以 IDCard 必须重写和实现这个方法。
  3. 另外,值得注意的是,在 Factory类下的 createProduct 方法,有几种实现手段:
    1. 指定为抽象方法,就是 Code 中的实现方式
    2. 默认实现:在方法体内 直接 return new Product(name) ; 但是由此 Product 类,不能为抽象。
    3. 抛出异常:如果使用默认的父类 create 方法,内部抛出异常,因为我们希望子类来重写该方法。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容