headfirst设计模式(4)—工厂模式
开篇
天天逛博客园,就是狠不下心来写篇博客,忙是一方面,但是说忙能有多忙呢,都有时间逛博客园,写篇博客的时间都没有?(这还真不好说)
每次想到写一篇新的设计模式,我总会问自己:
1,自己理解了吗?
2,我能以一种简单且有逻辑的方式把它说出来吗?
不说做到有的放矢,但是一本正经的胡说八道还是要有吧,起码要忽悠得头头是道嘛(手动斜眼笑)
关于工厂模式的几个问题
1,这个是拿来干什么的?
2,怎么用?
3,不用行不行?
第一个和第三个问题,我现在就可以告诉你答案:早点下班,可以
所有的设计模式对我来说都是为了减少工作量。关于减少工作量我的理解是:每个需求,都应该在它适当的时候出现适当的代码!这个太重要了
代码偷懒,后期返工多
过度设计,后期返工多
设计模式+经验可以解决这个问题,其他的我还不知道。没有经验怎么办?两个要点:
1,能用
2,简洁
首先要达到能用,然后就是尽量简洁,这样代码就不会太差。首先你要自己看得懂,然后是让队友看得懂。
你知道你队友看到一堆烂的看都看不懂,也一句注释都没有的代码的时候的心理阴影面积吗?
这其实也没什么,谁没填过别人的坑呢?关键是他知道你家在哪里,而且还知道你经常走夜路,就问你怕不怕?(卧槽,又跑题了。。)
需求:你有一个披萨店,只卖一种披萨,代码如下:
披萨:
- import java.util.ArrayList;
- import java.util.List;
- /**
- * 披萨类
- * @author skysea
- */
- public class Pizza {
- private String name;//披萨名称
- private String dough;//面团
- private String sauce;//酱料
- private List<String> toppings = new ArrayList<>();//佐料
- public Pizza() {
- this.name = "原味披萨";
- this.dough = "原味面团";
- this.sauce = "原味酱料";
- }
- void prepare() {
- System.out.println("开始准备披萨:" + name);
- System.out.println("开始处理面团:" + dough);
- System.out.println("添加酱料:" + sauce);
- System.out.println("添加佐料:");
- if(toppings.size() > 0) {
- for(String t : toppings) {
- System.out.println(" " + t);
- }
- }
- }
- void bake() {
- System.out.println("烘焙25分钟..");
- }
- void cut() {
- System.out.println("披萨切片..");
- }
- void box() {
- System.out.println("披萨打包..");
- }
- public String getName() {
- return name;
- }
- }
披萨店:
- /**
- * 只卖一种披萨的披萨店
- * @author skysea
- */
- public class PizzaStore {
- public Pizza orderPizza() {
- Pizza pizza = new Pizza();
- pizza.prepare();
- pizza.bake();
- pizza.cut();
- pizza.box();
- return pizza;
- }
- }
测试类:
- /**
- * pizza测试类
- * @author skysea
- */
- public class PizzaTest {
- public static void main(String[] args) {
- PizzaStore pizzaStore = new PizzaStore();
- Pizza pizza = pizzaStore.orderPizza();
- System.out.println("当前预定的披萨:" + pizza.getName());
- }
- }
现在披萨店要拓展业务了,因为卖一种披萨顾客已经吃腻了,现在要开始添加新的披萨类型
简单工厂模式
Pizza类的改进
- import java.util.ArrayList;
- import java.util.List;
- /**
- * 披萨抽象类
- * 1,修改private -> protected(保证子类拥有这些属性)
- * 2,将Pizza定义为abstract类,防止被new,也是为后面的改造做准备
- * @author skysea
- */
- public abstract class Pizza {
- protected String name;//披萨名称
- protected String dough;//面团
- protected String sauce;//酱料
- protected List<String> toppings = new ArrayList<>();//佐料
- void prepare() {
- System.out.println("开始准备披萨:" + name);
- System.out.print("开始处理面团:" + dough);
- System.out.println("添加酱料:" + sauce);
- System.out.println("添加佐料:");
- for(String t : toppings) {
- System.out.println(" " + t);
- }
- }
- void bake() {
- System.out.println("烘焙25分钟..");
- }
- void cut() {
- System.out.println("披萨切片..");
- }
- void box() {
- System.out.println("披萨打包..");
- }
- public String getName() {
- return name;
- }
- @Override
- public String toString() {
- return "Pizza [name=" + name + ", dough=" + dough + ", sauce=" + sauce + ", toppings=" + toppings + "]";
- }
- }
先给出新增的披萨
芝士披萨:
- /**
- * 芝士披萨
- * @author skysea
- */
- public class CheesePizza extends Pizza{
- public CheesePizza() {
- this.name = "芝士披萨";
- this.dough = "芝士披萨的面团";
- this.sauce = "芝士披萨的酱料";
- this.toppings.add("很多芝士....");
- }
- }
蛤蜊披萨:
- /**
- * 蛤蜊披萨
- * @author skysea
- */
- public class ClamPizza extends Pizza {
- public ClamPizza() {
- this.name = "蛤蜊披萨";
- this.dough = "蛤蜊披萨的面团";
- this.sauce = "蛤蜊披萨的酱料";
- this.toppings.add("蛤蜊");
- }
- }
意大利烤肠披萨:
- /**
- * 意大利烤肠披萨
- * @author skysea
- */
- public class PepperoniPizza extends Pizza{
- public PepperoniPizza() {
- this.name = "意大利烤肠披萨";
- this.dough = "意大利烤肠披萨的面团";
- this.sauce = "意大利烤肠披萨的酱料";
- this.toppings.add("一大波意大利烤肠...");
- }
- }
素食比萨:
- /**
- * 素食比萨
- * @author skysea
- */
- public class VeggiePizza extends Pizza {
- public VeggiePizza() {
- name = "素食比萨";
- dough = "素食比萨的面团";
- sauce = "素食比萨的酱料";
- toppings.add("素食比萨");
- toppings.add("素食比萨佐料1");
- toppings.add("素食比萨佐料2");
- }
- }
贴了这么多代码,先给出一波简单的实现:
- /**
- * pizza店
- * @author skysea
- */
- public class PizzaStore {
- public Pizza orderPizza(String type) {
- Pizza pizza = null;
- if (type.equals("cheese")) {
- pizza = new CheesePizza();
- } else if (type.equals("pepperoni")) {
- pizza = new PepperoniPizza();
- } else if (type.equals("clam")) {
- pizza = new ClamPizza();
- } else if (type.equals("veggie")) {
- pizza = new VeggiePizza();
- }
- pizza.prepare();
- pizza.bake();
- pizza.cut();
- pizza.box();
- return pizza;
- }
- }
在不考虑继续扩展披萨种类的时候,这样的实现有没有问题,一般来说,达到了可以用的标准,但是不好用,问题如下:
1,没有兼容原来的一种披萨方法 public Pizza orderPizza(),相信我,每一个public方法都是很重要的,因为你不知道有多少地方用到过。当然也不是没办法知道,只是你知道也不一定就能改,就算你能改,也不一定改对。
2,String类型的type太容易出错了,个人感觉对程序开发不友好,当然这个也要分情况,灵活和严谨本来就很难做到两全
3,推荐取不到合适的type时抛异常,而不是返回空,便于排查问题(此处的if里面只是直接new返回的对象,实际情况远比现在的复杂)
给出第二版:
- /**
- * pizza店
- * @author skysea
- */
- public class PizzaStore {
- public Pizza orderPizza() {
- return orderPizza(PizzaTypeEnum.CHEESE);
- }
- public Pizza orderPizza(PizzaTypeEnum type) {
- Pizza pizza;
- pizza = SimplePizzaFactory.getPizza(type);
- pizza.prepare();
- pizza.bake();
- pizza.cut();
- pizza.box();
- return pizza;
- }
- }
SimplePizzaFactory:
- /**
- * 简单工厂类
- * @author skysea
- */
- public class SimplePizzaFactory {
- /**
- * 根据类型获取pizza
- * @param type
- * @return
- */
- public static final Pizza getPizza(PizzaTypeEnum type){
- switch (type) {
- case CHEESE: return new CheesePizza();
- case CLAM: return new ClamPizza();
- case PEPPERONI: return new PepperoniPizza();
- case VEGGIE: return new VeggiePizza();
- default: throw new NoSuchPizzaException(type.getCode());
- }
- }
- }
辅助类(枚举,异常):
- /**
- * 定义pizza类型枚举
- * @author skysea
- *
- */
- public enum PizzaTypeEnum{
- /**
- * 芝士披萨
- */
- CHEESE("cheese"),
- /**
- * 意大利烤肠披萨
- */
- PEPPERONI("pepperoni"),
- /**
- * 蛤蜊披萨
- */
- CLAM("clam"),
- /**
- * 素食比萨
- */
- VEGGIE("veggie");
- private final String code;
- PizzaTypeEnum(String code) {
- this.code = code;
- }
- public String getCode() {
- return code;
- }
- }
- /**
- * 没有匹配的pizza异常
- * @author skysea
- */
- public class NoSuchPizzaException extends RuntimeException{
- private static final long serialVersionUID = 6831396172306375611L;
- public NoSuchPizzaException(String message) {
- super(message);
- }
- }
测试类:
- /**
- * pizza测试类
- * @author skysea
- */
- public class PizzaTest {
- public static void main(String[] args) {
- PizzaStore store = new PizzaStore();
- Pizza pizza = store.orderPizza(PizzaTypeEnum.CHEESE);
- System.out.println(pizza);
- pizza = store.orderPizza(PizzaTypeEnum.VEGGIE);
- System.out.println(pizza);
- }
- }
好了,代码写到这里,其实对于:新增披萨类型的这个需求的实现其实已经很好了。至少来说现阶段的需求实现了,其次就是对调用方友好,至少队友不会跑过来问你类型传啥,不会告诉你他string字符串传错了,不会在你改个类型的时候,还要通知他(当然这个也可以通过常量来处理)。
吹了半天,来说说这段代码的问题,正常情况下,需求会是这样变:
1,PepperoniPizza暂时不要了,一般来说,你问他要不要,他会说,这个要看后面的运营情况(我:...)
2,你给我新加一个xx披萨
现在需要改的是两个地方,一个是工厂类,一个是枚举,但是主要的流程是不用改了,如果你觉得还是很麻烦在不考虑性能的情况下,你还可以用反射来玩,改造一下工厂类(实现通过class来创建对象)和枚举(添加一个字段来存放type对应的class)就可以了,不赘述..
第一波需求就差不多可以这样收手了,随着业务的发展,披萨店那叫一个红火啊,虽然中间也对代码做了很多新的披萨,但是由于PizzaStore相当稳定,也没出什么大问题。
新的问题(开分店):
1,旗舰店在芝加哥,现在要在纽约开一家新的店
2,分店的披萨口味要根据当地的口味来进行调整,保证能够不失品牌特色的同时,也能满足当地独特的风味
3,分店披萨的种类与暂时与旗舰店保持一致
工厂方法模式
先把所有的披萨列出来
芝加哥的披萨:
- /**
- * 芝加哥芝士披萨
- * @author skysea
- */
- public class ChicagoStyleCheesePizza extends Pizza {
- public ChicagoStyleCheesePizza() {
- name = "芝加哥芝士披萨";
- dough = "芝加哥芝士披萨面团";
- sauce = "芝加哥芝士披萨酱料";
- toppings.add("芝加哥芝士披萨调料1");
- toppings.add("芝加哥芝士披萨调料2");
- }
- @Override
- void cut() {
- System.out.println("芝加哥芝士披萨版切片...");
- }
- }
- /**
- * 芝加哥蛤蜊披萨
- * @author skysea
- */
- public class ChicagoStyleClamPizza extends Pizza {
- public ChicagoStyleClamPizza() {
- name = "芝加哥蛤蜊披萨";
- dough = "芝加哥蛤蜊披萨面团";
- sauce = "芝加哥蛤蜊披萨酱料";
- toppings.add("芝加哥蛤蜊披萨佐料1");
- toppings.add("芝加哥蛤蜊披萨佐料2");
- }
- @Override
- void cut() {
- System.out.println("芝加哥蛤蜊披萨版切片...");
- }
- }
- /**
- * 芝加哥意大利烤肠披萨
- * @author skysea
- */
- public class ChicagoStylePepperoniPizza extends Pizza {
- public ChicagoStylePepperoniPizza() {
- name = "芝加哥意大利烤肠披萨";
- dough = "芝加哥意大利烤肠披萨面团";
- sauce = "芝加哥意大利烤肠披萨酱料";
- toppings.add("芝加哥意大利烤肠披萨调料1");
- toppings.add("芝加哥意大利烤肠披萨调料2");
- toppings.add("芝加哥意大利烤肠披萨调料3");
- toppings.add("芝加哥意大利烤肠披萨调料4");
- }
- @Override
- void cut() {
- System.out.println("芝加哥意大利烤肠披萨版切片...");
- }
- }
- /**
- * 芝加哥素食比萨
- * @author skysea
- */
- public class ChicagoStyleVeggiePizza extends Pizza {
- public ChicagoStyleVeggiePizza() {
- name = "芝加哥素食比萨";
- dough = "芝加哥素食比萨的面团";
- sauce = "芝加哥素食比萨的酱料";
- toppings.add("芝加哥素食比萨调料1");
- toppings.add("芝加哥素食比萨调料2");
- toppings.add("芝加哥素食比萨调料3");
- }
- void cut() {
- System.out.println("芝加哥素食比萨版切片...");
- }
- }
纽约的披萨:
- /**
- * 纽约芝士披萨
- * @author skysea
- */
- public class NYStyleCheesePizza extends Pizza {
- public NYStyleCheesePizza() {
- name = "纽约芝士披萨";
- dough = "纽约芝士披萨面团";
- sauce = "纽约芝士披萨酱料";
- toppings.add("纽约芝士披萨调料1");
- toppings.add("纽约芝士披萨调料2");
- }
- @Override
- void cut() {
- System.out.println("纽约芝士披萨版切片...");
- }
- }
- /**
- * 纽约蛤蜊披萨
- * @author skysea
- */
- public class NYStyleClamPizza extends Pizza {
- public NYStyleClamPizza() {
- name = "纽约蛤蜊披萨";
- dough = "纽约蛤蜊披萨面团";
- sauce = "纽约蛤蜊披萨酱料";
- toppings.add("纽约蛤蜊披萨佐料1");
- toppings.add("纽约蛤蜊披萨佐料2");
- }
- @Override
- void cut() {
- System.out.println("纽约蛤蜊披萨版切片...");
- }
- }
- /**
- * 纽约意大利烤肠披萨
- * @author skysea
- */
- public class NYStylePepperoniPizza extends Pizza {
- public NYStylePepperoniPizza() {
- name = "纽约意大利烤肠披萨";
- dough = "纽约意大利烤肠披萨面团";
- sauce = "纽约意大利烤肠披萨酱料";
- toppings.add("纽约意大利烤肠披萨调料1");
- toppings.add("纽约意大利烤肠披萨调料2");
- toppings.add("纽约意大利烤肠披萨调料3");
- toppings.add("纽约意大利烤肠披萨调料4");
- }
- @Override
- void cut() {
- System.out.println("纽约意大利烤肠披萨版切片...");
- }
- }
- /**
- * 纽约素食比萨
- * @author skysea
- */
- public class NYStyleVeggiePizza extends Pizza {
- public NYStyleVeggiePizza() {
- name = "纽约素食比萨";
- dough = "纽约素食比萨的面团";
- sauce = "纽约素食比萨的酱料";
- toppings.add("纽约素食比萨调料1");
- toppings.add("纽约素食比萨调料2");
- toppings.add("纽约素食比萨调料3");
- }
- void cut() {
- System.out.println("纽约素食比萨版切片...");
- }
- }
披萨倒是列完了,但是在实际的开发过程中,业务逻辑这么简单那是不可能的,想要改那什么旗舰店披萨的类名是很困难的
一般要考虑:
1,是不是单机,有没有其他外部系统在调用
2,改动原来的代码有什么好处,更容易理解吗?迭代了几个版本过后垃圾代码太多了吗?
3,影响大不大
当然,我这里是随便造,你们呢,我就不知道了,嘿嘿嘿,所以碰到这种情况,一般来说要悠着点,看时间,也要看影响,开发就是这样,同一个功能,2天有2天的做法,5天有5天的做法,10天有10天的做法
披萨店改造:
- /**
- * 披萨店抽象类
- * @author skysea
- */
- public abstract class PizzaStore {
- abstract Pizza createPizza(String item);
- public Pizza orderPizza(String type) {
- Pizza pizza = createPizza(type);
- System.out.println("--- 制作 " + pizza.getName() + " ---");
- pizza.prepare();
- pizza.bake();
- pizza.cut();
- pizza.box();
- return pizza;
- }
- }
- /**
- * 芝加哥披萨店
- * @author skysea
- */
- public class ChicagoPizzaStore extends PizzaStore {
- public static final String CHEESE = "cheese";
- public static final String VEGGIE = "veggie";
- public static final String CLAM = "clam";
- public static final String PEPPERONI = "pepperoni";
- Pizza createPizza(String item) {
- if (CHEESE.equals(item)) {
- return new ChicagoStyleCheesePizza();
- } else if (VEGGIE.equals(item)) {
- return new ChicagoStyleVeggiePizza();
- } else if (CLAM.equals(item)) {
- return new ChicagoStyleClamPizza();
- } else if (PEPPERONI.equals(item)) {
- return new ChicagoStylePepperoniPizza();
- } else {
- throw new NoSuchPizzaException(item);
- }
- }
- }
纽约披萨店(和芝加哥披萨店几乎一毛一样,这里就不展开了):
- /**
- * 纽约披萨店
- * @author skysea
- */
- public class NYPizzaStore extends PizzaStore {
- public static final String CHEESE = "cheese";
- public static final String VEGGIE = "veggie";
- public static final String CLAM = "clam";
- public static final String PEPPERONI = "pepperoni";
- Pizza createPizza(String item) {
- if (CHEESE.equals(item)) {
- return new NYStyleCheesePizza();
- } else if (VEGGIE.equals(item)) {
- return new NYStyleVeggiePizza();
- } else if (CLAM.equals(item)) {
- return new NYStyleClamPizza();
- } else if (PEPPERONI.equals(item)) {
- return new NYStylePepperoniPizza();
- } else {
- throw new NoSuchPizzaException(item);
- }
- }
- }
这段代码有三个问题要理解清楚:
1,这个地方为啥要弄个抽象类出来?
这个就要结合实际来理解了,分店与分店之间,需不需要统一规范化管理?需不需要保证自己的特色?答案毫无疑问,都是需要的
这个地方制作披萨的过程,毫无疑问是肯定要一致的。就像外卖一样,下单,炒菜,配送。整套流程都是这样,不能说你出来就开始炒菜了啊,这不科学。不一样的地方就是,你炒的什么菜,好不好吃。配送得快不快,稳不稳,服务好不好。
所以,抽象类的意义就是:规范、特色
2,factory咋个不见了?
因为把它和具体的store合并在一起了,这样又引申出另外一个问题:为啥要合并?因为store现在充当的角色就是facotry,刚才说过的制作过程已经放到父类中实现了,现在只需要在具体的store中去解决披萨的创建问题
3,为啥又不用枚举了,弄个String来创建pizza?
如果还是单机,用枚举当然会比直接扔个string来得稳当。
开了分店,要是每个分店都是一套完整的服务在玩,丢个string,要比枚举来得好。原因有2:传输过程中的序列化和反序列化、更加灵活(客户端不用每次都因为这个原因要去升级对应的包,特别是多个版本在跑得时候,升级了又会导致其他东西不能玩)
测试类:
- /**
- * 披萨测试类
- * @author skysea
- */
- public class PizzaTest {
- public static void main(String[] args) {
- PizzaStore nyStore = new NYPizzaStore();
- PizzaStore chicagoStore = new ChicagoPizzaStore();
- Pizza pizza = nyStore.orderPizza(NYPizzaStore.CHEESE);
- System.out.println("Ethan ordered a " + pizza.getName() + "\n");
- pizza = chicagoStore.orderPizza(ChicagoPizzaStore.CHEESE);
- System.out.println("Joel ordered a " + pizza.getName() + "\n");
- pizza = nyStore.orderPizza(NYPizzaStore.CLAM);
- System.out.println("Ethan ordered a " + pizza.getName() + "\n");
- pizza = chicagoStore.orderPizza(ChicagoPizzaStore.CLAM);
- System.out.println("Joel ordered a " + pizza.getName() + "\n");
- pizza = nyStore.orderPizza(NYPizzaStore.PEPPERONI);
- System.out.println("Ethan ordered a " + pizza.getName() + "\n");
- pizza = chicagoStore.orderPizza(ChicagoPizzaStore.PEPPERONI);
- System.out.println("Joel ordered a " + pizza.getName() + "\n");
- pizza = nyStore.orderPizza(NYPizzaStore.VEGGIE);
- System.out.println("Ethan ordered a " + pizza.getName() + "\n");
- pizza = chicagoStore.orderPizza(ChicagoPizzaStore.VEGGIE);
- System.out.println("Joel ordered a " + pizza.getName() + "\n");
- }
- }
结果(结果太多了,就不全部截图出来了):
headfirst设计模式(4)—工厂模式的更多相关文章
- HeadFirst设计模式之工厂模式
一. 1."工厂模式"不是种真正的设计模式,而是一种编程术语 2.The Factory Method Pattern defi nes an interface for crea ...
- HeadFirst 设计模式 04 工厂模式
除了 new 操作符之外, 还有更多创造对象的方法. 工厂处理创建对象的细节. 这么做的目的是为了抽象, 例如把创建比萨的代码包装进一个类, 当以后实现改变时, 只需修改这个类即可. 利用静态方法定义 ...
- 设计模式——抽象工厂模式及java实现
设计模式--抽象工厂模式及java实现 设计模式在大型软件工程中很重要,软件工程中采用了优秀的设计模式有利于代码维护,方便日后更改和添加功能. 设计模式有很多,而且也随着时间在不断增多,其中最著名的是 ...
- 5. 星际争霸之php设计模式--抽象工厂模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- 3. 星际争霸之php设计模式--简单工厂模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- iOS 设计模式之工厂模式
iOS 设计模式之工厂模式 分类: 设计模式2014-02-10 18:05 11020人阅读 评论(2) 收藏 举报 ios设计模式 工厂模式我的理解是:他就是为了创建对象的 创建对象的时候,我们一 ...
- 设计模式之工厂模式(Factory)
设计模式的工厂模式一共有三种:简单工厂模式,工厂模式,抽象工厂模式 简单工厂模式原理:只有一个工厂类,通过传参的形式确定所创建的产品对象种类 代码如下: #include <stdio.h> ...
- php设计模式:工厂模式
php设计模式:工厂模式 意图: 定义一个用于创建对象的接口,让子类决定实例化哪一个类. 工厂模式实现: 工厂模式中任何创建对象的工厂类都要实现这个接口,实现接口的方法体中都要实现接口中的方法,它声明 ...
- 浅析JAVA设计模式之工厂模式(一)
1 工厂模式简单介绍 工厂模式的定义:简单地说,用来实例化对象,取代new操作. 工厂模式专门负责将大量有共同接口的类实例化.工作模式能够动态决定将哪一个类实例化.不用先知道每次要实例化哪一个类. 工 ...
- java 设计模式之工厂模式与反射的结合
工厂模式: /** * @author Rollen-Holt 设计模式之 工厂模式 */ interface fruit{ public abstract void eat(); } ...
随机推荐
- 使用ztree展示树形菜单结构
官网:http://www.treejs.cn/v3/main.php#_zTreeInfo 一.功能简介 在权限系统中,实现给角色指定菜单权限的功能.主要包括以下几点: 读取全部菜单项,并以树形结构 ...
- asp.net core 实现一个简单的仓储
一直有自己写个框架的想法,但是一直没有行动起来,最近比较闲,正好可以开工了. 现在已经完成了两部分.1.一个简单仓储,实现使用的是ef 2.IOC部分,这里是把内置的ioc替换成了aotofac,这部 ...
- 「JavaScript」手起刀落-一起来写经典的贪吃蛇游戏
回味 小时候玩的经典贪吃蛇游戏我们印象仍然深刻,谋划了几天,小时候喜欢玩的游戏,长大了终于有能力把他做出来(从来都没有通关过,不知道自己写的程序,是不是能通关了...),好了,闲话不多谈,先来看一下效 ...
- python3.5安装pyHook,解决【TypeError: MouseSwitch() missing 8 required positional arguments: 'msg', 'x', 'y', 'data', 'time', 'hwnd', and 'window_name'】这个错误!
为什么安装 pyHook包:为Windows中的全局鼠标和键盘事件提供回调. Python应用程序为用户输入事件注册事件处理程序,例如鼠标左键,鼠标左键,键盘键等 先要实时获取系统的鼠标位置或者键盘输 ...
- [C#]使用GroupJoin将两个关联的集合进行分组
本文为原创文章.源代码为原创代码,如转载/复制,请在网页/代码处明显位置标明原文名称.作者及网址,谢谢! 本文使用的开发环境是VS2017及dotNet4.0,写此随笔的目的是给自己及新开发人员作为参 ...
- Linux 链接详解----动态链接库
静态库的缺点: 库函数被包含在每一个运行的进程中,会造成主存的浪费. 目标文件的size过大 每次更新一个模块都需要重新编译,更新困难,使用不方便. 动态库: 是一个目标文件,包含代码和数据,它可以在 ...
- Android开发之漫漫长途 番外篇——内存泄漏分析与解决
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列.该系列引用了<Android开发艺术探索>以及<深入理解And ...
- NYOJ 323 Drainage Ditches 网络流 FF 练手
Drainage Ditches 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 Every time it rains on Farmer John's fields, ...
- How to get table pg_stat_user_functions.
修改配置文件postgres.conf track_functions = all # none, pl, all 或者 在当前事物中设置 postgres=# s ...
- .Net Core实现将文件上传到七牛云存储
功能:将图片上传到七牛云存储 准备工作 注册七牛账号,提交实名认证(基本上1天内内审核通过) 登录七牛后台->对象存储->新建空间 (基本概念:https://developer.qini ...