趁热打铁,紧跟着上一节的工厂方法模式。这一节介绍一下抽象工厂模式,以及分析俩个模式的不同

1、何为抽象模式?

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

在Abstract Factory模式中将会出现抽象工厂,它会将抽象零件组装为抽象产品。也就是说,我们并不关心零件的具体实现,而是只关心接口(API )。我们仅使用该接口( API )将零件组装成为产品。

在Tempate Method模式和Builder模式中,子类这- -层负责方法的具体实现。在Abstract Factory模式中也是一样的。在子类这一层中有 具体的工厂,它负责将具体的零件组装成为具体的产品。

我们赶紧来看看下面这段抽象工厂的示例程序吧。跟着代码看抽象模式!

2、示例程序

效果:

类图:

类的一览表:

类的位置:

2.1 定义抽象的零件 Item类

package cn.design.abstractfactory.factrory;

/**
* @author lin
* @version 1.0
* @date 2020-07-17 9:11
* @Description Item类是Link类和Tray类的父类(Item有 “ 项目 ” 的意思)。这样 Link类和Tray类就具有可替换性了。
*/
public abstract class Item {
   /**
    * caption字段表示项目的“标题”。
    */
   protected String caption;    public Item(String caption) {
       this.caption = caption;
  }    /**
    * makeHTML方法是抽象方法,需要子类来实现这个方法。该方法会返回HTML文件的内容(需要子类去实现)。
    *
    * @return HTML
    */
   public abstract String makeHTML();
}

2.2 定义抽象的零件组成 Link类

package cn.design.abstractfactory.factrory;

/**
* @author lin
* @version 1.0
* @date 2020-07-17 9:14
* @Description Link类(代码清单8 - 2)是抽象地表示HTML的超链接的类。
* 由于Link类中没有实现父类( Item类)的抽象方法(ma keHTML),因此它也是抽象类。
*/
public abstract class Link extends Item {
   /**
    * url字段中保存的是超链接所指向的地址。乍一看,在Link类中好像一个抽象方法都没有,
    * 但实际上并非如此。
    */
   protected String url;    public Link(String caption, String url) {
       super(caption);
       this.url = url;
  }
}

2.3 定义抽象的零件组成 Tray类

package cn.design.abstractfactory.factrory;

import java.util.ArrayList;
import java.util.List; /**
* @author lin
* @version 1.0
* @date 2020-07-17 9:18
* @Description Tray类(代码清单8 - 3)表示的是-一个含有多个Link类和Tray类的容器( Tray有托盘的意
* 思。请想象成在托盘上放置着-一个- -个项目 )。
* 虽然Tray类也继承了Item类的抽象方法makeHTML,但它并没有实现该方法。因此,Tray
* 类也是抽象类。
*/
public abstract class Tray extends Item {
   protected List<Item> tray = new ArrayList<>();    public Tray(String caption) {
       super(caption);
  }    /**
    * Tray类使用add方法将Link类和Tray类集合在- -起。为了表示集合的对象是“Link类
    * 和Tray类”,我们设置add方法的参数为Link类和Tray类的父类Item类。
    *
    * @param item
    */
   public void add(Item item) {
       tray.add(item);
  } }

2.4 定义抽象的产品 Page 类

package cn.design.abstractfactory.factrory;

import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List; /**
* @author lin
* @version 1.0
* @date 2020-07-17 10:43
* @Description Page类是抽象地表示HTML页面的类。
* 如果将Link和Tray比喻成抽象的“零件”,那么Page类就是抽象的“产品”。
*/
public abstract class Page {
   /**
    * title 和author分别是表示页面标题和页面作者的字段。作者名字通过参数传递给Page类的构造函数。
    */
   protected String title;
   protected String author;
   protected List<Item> content = new ArrayList<>();    public Page(String title, String author) {
       this.title = title;
       this.author = author;
  }    /**
    * 可以使用add方法向页面中增加Item(即Link或Tray)。增加的Item将会在页面中显示出来。
    *
    * @param item 零件
    */
   public void add(Item item) {
       content.add(item);
  }    /**
    * output方法首先根据页面标题确定文件名,接着调用ma keHTML方法将自身保存的HTML
    * 内容写人到文件中。
    * 其中,我们可以去掉如下语句(1 )中的this,将其写为如下语句(2 )那样。
    * writer .write (this . makeHTML()) ;
    * ...... ( 1 )
    * writer . write (makeHTML()) ;
    * ...... (2 )
    * 为了强调调用的是Page类自己的makeHTML方法,我们显式地加上了this。这里调用的
    */
   public void output() {
       try {
           String fileName = title + ".html";
           FileWriter writer = new FileWriter(fileName);
           writer.write(this.makeHTML());
           writer.close();
           System.out.println(fileName + " 编写完成");
      } catch (IOException e) {
           e.printStackTrace();
      }
  }    /**
    * makeHTML方法是一- 个抽象方法。output 方法是一个简单的Template Method模式的方法。
    *
    * @return html 字符串
    */
   public abstract String makeHTML(); }

2.5 定义抽象的工厂 Factory类

package cn.design.abstractfactory.factrory;

/**
* @author lin
* @version 1.0
* @date 2020-07-17 11:00
* @Description TODO
*/
public abstract class Factory {
   /**
    * getFactory 方法通过调用Class类的forName方法来动态地读取类信息,接着使用,
    * newInstance方法生成该类的实例,并将其作为返回值返回给调用者。
    * Class类属于java.lang包,是用来表示类的类。Class 类包含于Java的标准类库中。
    * forName是java.lang.Class的类方法(静态方法),newInstance则是java. lang.
    * Class的实例方法。
    * 请注意,虽然getFactory方法生成的是具体工厂的实例,但是返回值的类型是抽象工厂类型。
    * @param className
    * @return
    */
   public static Factory getFactory(String className) {
       Factory factory = null;
       try {
           factory = (Factory) Class.forName(className).newInstance();
      } catch (InstantiationException | IllegalAccessException e) {
           e.printStackTrace();
      } catch (ClassNotFoundException e) {
           System.out.println("ClassNotFoundException 没有找到 " + className + " 类.");
      }
       return factory;   }
   public abstract Link createLink(String caption, String url);    public abstract Tray createTray(String caption);    /**
    * createLink、createTray. createPage等方法是用于在抽象工厂中生成零件和产品的方
    * 法。这些方法都是抽象方法,具体的实现被交给了Factory类的子类。不过,这里确定了方法的
    * 名字和签名。
    * @param title
    * @param author
    * @return
    */
   public abstract Page createPage(String title, String author);
}

2.6 定义具体的工厂 ListFactory类

package cn.design.abstractfactory.listfactory;

import cn.design.abstractfactory.factrory.Factory;
import cn.design.abstractfactory.factrory.Link;
import cn.design.abstractfactory.factrory.Page;
import cn.design.abstractfactory.factrory.Tray; /**
* @author lin
* @version 1.0
* @date 2020-07-17 11:29
* @Description TODO
*/
public class ListFactory extends Factory {    @Override
   public Link createLink(String caption, String url) {
       return new ListLink(caption, url);
  }    @Override
   public Tray createTray(String caption) {
       return new ListTray(caption);
  }    @Override
   public Page createPage(String title, String author) {
       return new ListPage(title, author);
  }
}

2.7 定义具体的零件 ListLink类

package cn.design.abstractfactory.listfactory;

import cn.design.abstractfactory.factrory.Link;

/**
* @author lin
* @version 1.0
* @date 2020-07-17 11:31
* @Description TODO
*/
public class ListLink extends Link {    public ListLink(String caption, String url) {
       super(caption, url);
  }    @Override
   public String makeHTML() {
       return "<li><a href =\"" + url + "\">" + caption + "</a></li>\n";
  }
}

2.8 定义具体的零件 ListTray类

package cn.design.abstractfactory.listfactory;

import cn.design.abstractfactory.factrory.Item;
import cn.design.abstractfactory.factrory.Tray; import java.util.Iterator; /**
* @author lin
* @version 1.0
* @date 2020-07-17 11:32
* @Description TODO
*/
public class ListTray extends Tray {
   public ListTray(String caption) {
       super(caption);
  }    @Override
   public String makeHTML() {
       StringBuffer buffer = new StringBuffer();
       buffer.append("<li>\n");
       buffer.append(caption + "\n");
       buffer.append("<ul>\n");
       Iterator it = tray.iterator();
       while (it.hasNext()) {
           Item item = (Item) it.next();
           buffer.append(item.makeHTML());
      }
       buffer.append("</ul>\n");
       buffer.append("</li>\n");
       return buffer.toString();   }
}

2.9 定义具体的产品 ListPage类

package cn.design.abstractfactory.listfactory;

import cn.design.abstractfactory.factrory.Item;
import cn.design.abstractfactory.factrory.Page; import java.util.Iterator; /**
* @author lin
* @version 1.0
* @date 2020-07-17 11:34
* @Description TODO
*/
public class ListPage extends Page {
   public ListPage(String title, String author) {
       super(title, author);
  }    @Override
   public String makeHTML() {
       StringBuffer buffer = new StringBuffer();
       buffer.append("<html><head><title>" + title + "</title></head>\n");
       buffer.append("<body>\n");
       buffer.append("<h1>" + title + "</h1>\n");
       buffer.append("<ul>\n");
       Iterator it = content.iterator();
       while (it.hasNext()) {
           Item item = (Item) it.next();
           buffer.append(item.makeHTML());
      }
       buffer.append("</ul>\n");
       buffer.append("<hr><address>" + author + "</address>");
       buffer.append("</body></html>\n");
       return buffer.toString();   }
}

2.10 测试Main类

package cn.design.abstractfactory;

import cn.design.abstractfactory.factrory.Factory;
import cn.design.abstractfactory.factrory.Link;
import cn.design.abstractfactory.factrory.Page;
import cn.design.abstractfactory.factrory.Tray;
import cn.design.abstractfactory.listfactory.ListFactory;
import cn.design.abstractfactory.tablefactory.TableFactory;
import com.alibaba.fastjson.JSON; /**
* @author lin
* @version 1.0
* @date 2020-07-17 9:10
* @Description TODO
*/
public class Main {
   public static void main(String[] args) {
       Factory factory = Factory.getFactory(ListFactory.class.getName());
//       Factory factory = Factory.getFactory(TableFactory.class.getName());        Link people = factory.createLink("人民日报", "http://www.people.com.cn/");
       Link gmw = factory.createLink(" 光明日报", "http://www.gmw.cn/");
       Link usYahoo = factory.createLink("Yahoo!", "http://www.yahoo.com/");
       Link jpYahoo = factory.createLink("Yahoo!Japan", "http://ww.yahoo.co.jp/");
       Link excite = factory.createLink("Excite", "http://www.excite.com/");
       Link google = factory.createLink("Google", "http://www.google.com/");        Tray trayNews = factory.createTray(" 日报");
       trayNews.add(people);
       trayNews.add(gmw);        Tray trayYaHoo = factory.createTray("Yahoo!");
       trayYaHoo.add(usYahoo);
       trayYaHoo.add(jpYahoo);        Tray traySearch = factory.createTray("检索引擎");
       traySearch.add(trayYaHoo);
       traySearch.add(excite);
       traySearch.add(google);        Page page = factory.createPage("LinkPage", " 发哥讲");
       page.add(trayNews);
       page.add(traySearch);
       page.output();
  }
}

运行效果如开篇效果图

3、改造成table工厂示例

3.1 定义TableFactory类

package cn.design.abstractfactory.tablefactory;

import cn.design.abstractfactory.factrory.Factory;
import cn.design.abstractfactory.factrory.Link;
import cn.design.abstractfactory.factrory.Page;
import cn.design.abstractfactory.factrory.Tray; /**
* @author lin
* @version 1.0
* @date 2020-07-17 14:53
* @Description TODO
*/
public class TableFactory extends Factory {
   @Override
   public Link createLink(String caption, String url) {
       return new TableLink(caption, url);
  }    @Override
   public Tray createTray(String caption) {
       return new TableTray(caption);
  }    @Override
   public Page createPage(String title, String author) {
       return new TablePage(title, author);
  }
}

3.2定义TableLink类

package cn.design.abstractfactory.tablefactory;

import cn.design.abstractfactory.factrory.Link;

/**
* @author lin
* @version 1.0
* @date 2020-07-17 14:54
* @Description TODO
*/
public class TableLink extends Link {
   public TableLink(String caption, String url) {
       super(caption, url);
  }    @Override
   public String makeHTML() {
       return "<td><a href=\"" + url + "\">" + caption + "</a></td>\n";   }
}

3.3定义TableTray类

package cn.design.abstractfactory.tablefactory;

import cn.design.abstractfactory.factrory.Item;
import cn.design.abstractfactory.factrory.Tray; import java.util.Iterator; /**
* @author lin
* @version 1.0
* @date 2020-07-17 14:56
* @Description TODO
*/
public class TableTray extends Tray {
   public TableTray(String caption) {
       super(caption);
  }    @Override
   public String makeHTML() {
       StringBuffer buffer = new StringBuffer();
       buffer.append("<td>");
       buffer.append("<table width=\"100%\" border=\"1\"><tr>");
       buffer.append("<td bgcolor=\"#ccccc\" align=\"center\" colspan=\"" + tray.size() + "\"><b>" + caption + "</b></td>");
       buffer.append("</tr>\n");
       buffer.append("<tr>\n");
       Iterator it = tray.iterator();
       while (it.hasNext()) {
           Item item = (Item) it.next();
           buffer.append(item.makeHTML());
      }
       buffer.append("</tr></table>");
       buffer.append("</td>");
       return buffer.toString();   }
}

3.4定义TablePage类

package cn.design.abstractfactory.tablefactory;

import cn.design.abstractfactory.factrory.Item;
import cn.design.abstractfactory.factrory.Page; import java.util.Iterator; /**
* @author lin
* @version 1.0
* @date 2020-07-17 14:57
* @Description TODO
*/
public class TablePage extends Page {
   public TablePage(String title, String author) {
       super(title, author);
  }    @Override
   public String makeHTML() {
       StringBuffer buffer = new StringBuffer();
       buffer.append("<html><head><title>" + title + "</title></head>\n");
       buffer.append("<body>\n");
       buffer.append("<h1>" + title + "</h1>\n");
       buffer.append("<table width=\"80号\" border=\"3\">\n");
       Iterator it = content.iterator();
       while (it.hasNext()) {
           Item item = (Item) it.next();
           buffer.append("<tr>" + item.makeHTML() + "</tr>");
      }
       buffer.append("</table>\n");
       buffer.append("<hr><address>" + author + "</address>");
       buffer.append("</body></html>\n");
       return buffer.toString();   }
}

3.5 测试类

测试类与2.10一样。

使用这个即可

Factory factory = Factory.getFactory(TableFactory.class.getName());

3.6效果

4、分析各个模块的作用

4.1 抽象工厂类图

4.2作用介绍

4.2.1 AbstractProduct (抽象产品)

AbstractProduct角色负责定义AbstractFactory角色所生成的抽象零件和产品的接口( API)。在示例程序中,由Link类、Tray类和Page类扮演此角色。

4.2.2 AbstractFactory (抽象工厂)

AbstractFactory角色负责定义用于生成抽象产品的接口(API)。在示例程序中,由Factory类扮演此角色。

4.2.3 Client (委托者)

Client角色仅会调用AbstractFactory角色和AbstractProduct角色的接口( API)来进行工作,对于具体的零件、产品和工厂- -无所知。在示例程序中,由Main类扮演此角色。图8-9省略了Client这- -角色。

4.2.4 ConcreteProduct (具体产品)

ConcreteProduct角色负责实现AbstractProduct角色的接口( API)。在示例程序中,由以下包中的以下类扮演此角色。

●listfactory包: ListLink类、ListTray类和ListPage类●tablefactory包: TableLink类、TableTray 类和TablePage类

4.2.5 ConcreteFactory (具体工厂)

ConcreteFactory角色负责实现AbstractFactory角色的接口( API)。在示例程序中,由以下包中的以下类扮演此角色。

●listfactory包: Listfactory类●tablefactory 包: Tablefactory类

5、总结

无论是简单工厂模式,工厂方法模式,还是抽象工厂模式,他们都属于工厂模式,在形式和特点上也是极为相似的,他们的最终目的都是为了解耦。在使用时,我们不必去在意这个模式到底工厂方法模式还是抽象工厂模式,因为他们之间的演变常常是令人琢磨不透的。经常你会发现,明明使用的工厂方法模式,当新需求来临,稍加修改,加入了一个新方法后,由于类中的产品构成了不同等级结构中的产品族,它就变成抽象工厂模式了;而对于抽象工厂模式,当减少一个方法使的提供的产品不再构成产品族之后,它就演变成了工厂方法模式。所以,在使用工厂模式时,只需要关心降低耦合度的目的是否达到了。

5.1 抽象工厂模式的优点

抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理。

5.2 抽象工厂模式的缺点

产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的。

5.3 适用场景

当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存

在着一定的关联或者约束,就可以使用抽象工厂模式。假如各个等级结构中的实现类之间不存在关联或约束,则

使用多个独立的工厂来对产品进行创建,则更合适一点。

5.4 对比

抽象工厂模式是工厂方法模式的升级版本,他用来创建一组相关或者相互依赖的对象。他与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。

在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。我们依然拿生产汽车的例子来说明他们之间的区别。

自己尝试写着代码区体会。那种方式方便就是用那种,也是根据场景的改变而做出选择!!

6、延伸( 生成实例的方法)

此处作为彩蛋~~~~ 扩展小知识

6.1 new

new 的方式 常用 , 不用多说。

创建一个日期类, 实例:

new Date();

6.2 clone

package cn.design.abstractfactory.clone;

import java.io.Serializable;

/**
* @author lin
* @version 1.0
* @date 2020-07-17 17:02
* @Description TODO
*/
public class User implements Serializable, Cloneable {
   private static final long serialVersionUID = 6695447736493L;
   String name;
   int age;
   Object obj;    public User(String name, int age, Object obj) {
       this.name = name;
       this.age = age;
       this.obj = obj;
  }    public User() {
  }    public User createClone() {
       User user = null;
       try {
           user = (User) super.clone();
      } catch (CloneNotSupportedException e) {
           e.printStackTrace();
      }
       return user;
  }    @Override
   public String toString() {
       return "User{" +
               "name='" + name + '\'' +
               ", age=" + age +
               ", obj=" + obj +
               '}';
  }    public static void main(String[] args) throws CloneNotSupportedException {
       User user = new User("发哥讲", 23, "人逢知己千杯少,难得在漫漫人生路上能认识你");
       System.out.println(user.toString());
       User clone = user.createClone();
       System.out.println("clone: " +clone.toString());
  }
}

clone 包含 浅拷贝和深拷贝, 后续有时间 会出一个专辑,专门介绍

6.3 反射

      Class<?> aClass = Class.forName(User.class.getName());
      Object o = aClass.newInstance();
      System.out.println(o);

反射也是后续会出一个专辑, 通过反射 可以获取到类的所有信息,还有类名,属性,方法上的注解.

自定义注解也是一个高级进阶专题的,放心各位,都不会少!!!

发哥讲

如果你觉得文章还不错,就请点击右上角选择发送给朋友或者转发到朋友圈~

● 扫码关注公众号

5、抽象工厂 abstract factory 将关联组件组成产品 创建型模式的更多相关文章

  1. 抽象工厂(Abstract Factory),工厂方法(Factory Method),单例模式(Singleton Pattern)

    在谈工厂之前,先阐述一个观点:那就是在实际程序设计中,为了设计灵活的多态代码,代码中尽量不使用new去实例化一个对象,那么不使用new去实例化对象,剩下可用的方法就可以选择使用工厂方法,原型复制等去实 ...

  2. 工厂模式[3] 抽象工厂 Abstract Factory

    简介 1.简单工厂,或静态工厂,产品接口 定义:专门定义一个类来负责创建其他类的实例,被创建的实例通常具有共同的父类或实现同一接口 优点:客户端可以直接消费产品,而不必关心具体产品的实现(不关心对象的 ...

  3. 面向对象设计——抽象工厂(Abstract Factory)模式

    定义 提供一个创建一系列相关或者相互依赖对象的接口,而无需指定它们具体的类.抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道或关心实际产出的具体产品是什么.这样一来,客户就能从具体的产 ...

  4. 设计模式四: 抽象工厂(Abstract Factory)

    简介 抽象工厂模式是创建型模式的一种, 与工厂方法不同的是抽象工厂针对的是生产一组相关的产品, 即一个产品族. 抽象工厂使用工厂方法模式来生产单一产品, 单一产品的具体实现分别属于不同的产品族. 抽象 ...

  5. C2:抽象工厂 Abstract Factory

    提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 应用场景: 一系列相互依赖的对象有不同的具体实现.提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合 UM ...

  6. 设计模式——抽象工厂(Abstract Factory)

    提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们的具体类. ——DP UML类图 模式说明 抽象工厂与工厂方法在定义上最明显的区别是“创建一系列相关或相互依赖对象的接口”,由此可以看出抽象工 ...

  7. Java 工厂模式(一)— 抽象工厂(Abstract Factory)模式

    一.抽象工厂模式介绍: 1.什么是抽象工厂模式: 抽象工厂模式是所有形态的工厂模式中最为抽象和最具有一般性的一种形态,抽象工厂模式向客户端提供一个接口,使得客户端在不知道具体产品的情类型的情况下,创建 ...

  8. 【设计模式】——抽象工厂Abstract Factory

    模式意图 提供对象的使用接口,隐藏对象的创建过程. 模式结构 AbstractFactory 提供创建对象的接口. ConcreteFactory 提供真正创建对象的实现类,用于组合并创建不同的对象, ...

  9. Headfirst设计模式的C++实现——抽象工厂(Abstract Factory)

    Dough.h #ifndef _DOUGH_H #define _DOUGH_H class Dough { }; #endif ThinCrustDough.h #ifndef _THIN_CRU ...

随机推荐

  1. redis(十九):Redis 架构模式,特点

    单机版 特点:简单 问题: 1.内存容量有限 2.处理能力有限 3.无法高可用. 主从复制 Redis 的复制(replication)功能允许用户根据一个 Redis 服务器来创建任意多个该服务器的 ...

  2. 08-Python面对对象进阶

    一.面向对象编程三大特征 Python是面向对象的语言,同样支持面向对象的编程的三大特征:继承,封装,多态. 封装是指隐藏对象的属性和实现细节,只对外提供必要的一些方法,私有属性,私有方法是实现封装地 ...

  3. 3dTiles 数据规范详解[4.2] i3dm瓦片二进制数据文件结构

    i3dm,即 Instanced 3D Model,实例三维模型的意思. 诸如树木.路灯.路边的垃圾桶.长椅等具有明显 重复 特征的数据.这类数据用得较少(笑,现在都喜欢搞BIM.倾斜摄影.精模.白模 ...

  4. As 布局文件太多很乱的问题

    //添加自定义文件整理文件夹的方法,没有之一在build.gradle(Module: app)里加入布局需要放入的路径代码>>>>>> sourceSets { ...

  5. android studio 正式版打包错误的一个问题

    今日在下载了别人的demo后,编译到我的手机上,然后通过qq等把软件发到其他的手机上使用时,无法安装,好像是因为这个是调试版本才安装不上,在网搜了一堆资料怎么建key怎么发布正式的版本,问题现在已解决 ...

  6. P5836 [USACO19DEC]Milk Visits S 从并查集到LCA(最近公共祖先) Tarjan算法 (初级)

    为什么以它为例,因为这个最水,LCA唯一黄题. 首先做两道并查集的练习(估计已经忘光了).简单来说并查集就是认爸爸找爸爸的算法.先根据线索理认爸爸,然后查询阶段如果发现他们的爸爸相同,那就是联通一家的 ...

  7. ATX学习(一)-atx-server

    今天无意中发现了ATX手机设备管理平台,瞬间勾引起了我极大的兴趣,这里对学习过程中的情况做个记录. 1.搭建环境 先按照作者步骤搭建环境出来吧,哇,突然发现ATX搭建环境很方便(一会就搭建好了)   ...

  8. 少儿编程:python趣味编程第一课

    本文仅针对8-16岁的青少年,所以流程是按如何去教好中小学生走的,并不适合成人找工作学习,因为进度也是按照青少年走的 大家好,我是C大叔,从事少儿编程行业三年有余(2016年从事少儿编程行业,少儿编程 ...

  9. Java中static、final和static final(final static)的区别(转)

    大佬的总结(大赞!) final可以修饰:属性,方法,类,局部变量(方法中的变量) final修饰的属性的初始化可以在编译期,也可以在运行期,初始化后不能被改变. final修饰的属性跟具体对象有关, ...

  10. 不是吧,阿sir,2020年程序员要不好过?

    自从网传程序员到了35岁之后必须要转行,现在又有人传言:“疫情之下,程序员今年要过苦日子了,降薪裁员是大趋势.” 不是,我就不明白了,你们怎么就看不得程序员好呢?天天巴望着程序员降薪.转行.裁员…   ...