GVKun编程网logo

thinking in Swift:重新审视装饰器模式(重试装饰器)

1

如果您想了解thinkinginSwift:重新审视装饰器模式的相关知识,那么本文是一篇不可错过的文章,我们将对重试装饰器进行全面详尽的解释,并且为您提供关于d3.js学习笔记--MikeBostoc

如果您想了解thinking in Swift:重新审视装饰器模式的相关知识,那么本文是一篇不可错过的文章,我们将对重试装饰器进行全面详尽的解释,并且为您提供关于d3.js学习笔记--Mike Bostock: Thinking with Joins、Effective Python (Pythonic Thinking)、iOS Swift 应用程序随机 EXC_BAD_ACCESS 崩溃:swift_bridgeObjectRetain swift_retain swift::RefCounts、java 线程 原子类相关操作示例 thinking in java4 目录21.3.4的有价值的信息。

本文目录一览:

thinking in Swift:重新审视装饰器模式(重试装饰器)

thinking in Swift:重新审视装饰器模式(重试装饰器)

(点击上方公众号,可快速关注)

来源:没故事的卓同学

链接:http://www.jianshu.com/p/65463cd65a92



如果在swift中按部就班的谈Gof设计模式,这在一开始就是错误的命题。原因主要有两个:


  • 设计模式是基于面向对象的编程范式

  • 实现基于当时的主流编程语言:C++ 和 Java


如今的swift的推荐编程范式并不是面向对象,很多人都大谈面向协议、函数式编程我就不展开了;现代的swift中有一些语法特性是当时的语言所不具备的,比如protocol extension,高阶函数等。


所以本文将利用swift的语法来谈下装饰器模式在swift下的解决思路。


Decorator pattern


有人翻作装饰器模式,也有翻成装饰者模式,英文的名称就是Decorator pattern。


装饰器模式能够实现动态的为对象添加功能,是从一个对象外部来给对象添加功能。装饰器模式就是基于对象组合的方式,可以很灵活的给对象添加所需要的功能。


直接用代码来说明。


用dish表示菜肴,一道菜有两个属性,名称和价格。然后为了方便测试重写了description属性,返回名称和价格。


class dish: customstringconvertible {

 

    var name: String

priceInt

 

    init(String,Int) {

        self.name = name

        selfprice = price

    }

 

descriptionString        get            return "\(name): price)元"

        }

}

}


再假设有一个菜的订单对象,接收一个dish对象后,最后可以通过total方法返回这些菜的总价钱。具体就不实现了,大概这个逻辑。


dishOrder    func appenddish: dish    func total() -> Int}


假设在一个饭馆里,老板发现这里的客人点菜的时候喜欢让厨师多放点盐,大家都知道非典时期盐很贵,所以老板觉得很亏,决定如果一道菜多加盐就要贵一块钱。接着又来了一个需求,如果打包带走,一道菜再加两块钱。如果我们不能改变dish的源码(在实际项目中常会遇到这种情况,可能这类定义在第三方的库里),要怎么实现这两个需求呢?


可以定义两个装饰器,注意这两个装饰器都要继承dish:


// 加盐的装饰器

classSaltdishDecorator: dish        super.init:"加糖 dish.)"dish + 1)

}

 

}

 

// 外带打包的装饰器

PackagedishDecorator"打包 2}


现在我们要表示一道打包带走的松鼠桂鱼就这样表示了:


let dish = PackagedishDecorator(dish: SaltdishDecorator(dish: dish(name: "松鼠桂鱼", price: 15)))



这样我们就可以给任意一道菜增加一些装饰性的功能。也有人用咖啡举例子,一杯咖啡可能要加糖,加奶,加巧克力等等。一层包一层。如果取名字的是中国人可能就叫洋葱模式了。最后使用的时候行为和dish是一样的。因为这些Decorator是继承自dish的。只是在初始化过程中改变了原有的一些属性。


缺陷:继承不是一个优秀的解决方案


编程时常常提到的一个指导思想就是组合优于继承。


继承最大的问题就在于你只能有一个爹。一个爹的结果就是能力有限,不够灵活。所以最后还得认一些干爹。


就拿上面的例子来讲,现在是给dish做了几个装饰功能,如果有一天说店里的点心也要支持这两个功能(给我来一个加盐的馒头!),是不是有要继承点心类写两个装饰器呢?


利用Swift中的Extension


我们可以这么理解这个需求,需要有这么一个方法,接受一个dish类型的参数,经过处理后返回一个dish。我们完全可以把这个方法通过extension写在dish身上。


extension dish    func salted -> dish        return dish"加盐     func packaged}


然后我们就可以链式调用:


let exteneddish = dish(name: "松鼠桂鱼", price: 15).salted().packaged()


更进一步:protocol extension


如果为了将来的扩展灵活,也可以把这个装饰写到protocol的extension里。


protocol Product{ get set}

 

protocol Salteable: Product     func salted -> Self

}


上面先定义了一个产品的协议,有名称和价格两个属性。

接着再定义了一个继承Product的Salteable的协议。里面有一个返回自身的salted方法。接着给这个protocol增加扩展实现:


extension Salteable  func salted -> Self        newProduct = self

        newProduct = )"

= 1

newProduct

}


然后我们再定义一个表示小吃的Snack,和菜一样也有两个属性。


structSnack}


如果我们要给这个Snack增加加盐的效果,只要声明他实现Salteable协议就可以了。


extension : Salteable{

 

}


这样就够啦!

看下输出:



欢迎关注我的微博:@没故事的卓同学


关注「 iOS大全 」

看更多精选 iOS 技术文章

↓↓↓

d3.js学习笔记--Mike Bostock: Thinking with Joins

d3.js学习笔记--Mike Bostock: Thinking with Joins

    我们可以使用append方法, 来创建一个单一元素:

  var svg = d3.select(''svg''),
      d = {"x": 50, "y": 50};
  svg.append("circle")
      .attr("cx", d.x)
      .attr("cy", d.y)
      .attr("r", 25);

    如果想传递多条数据, 则需要这样编写:

  var svg = d3.select(''svg''),
      data = [{"x": 50, "y": 50}, {"x": 120, "y": 50}];
  svg.selectAll("circle")
      .data(data)
      .enter()
      .append("circle")
      .attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; })
      .attr("r", 25);

这里代码主要的疑惑点在于: 

  svg.selectAll("circle")

为什么我们要选择要新创建的DOM元素呢?

以下是处理方式. 我们不必告诉D3如何实现, 而是告诉D3我们所想要的. 我想要一个circle绑定到一个data上, 即每个circle和data数组中的元素一一对应. 这种概念叫做: data join

数据 join to 存在的DOM元素, 产生一个update操作. 坐标非update的数据产生enter的操作, 而右边的DOM元素由于没有绑定, 则处于Exit状态, 代表被删除.

现在我们来解释以下神奇的enter-append 的代码是如何data join:

1. 首先, svg.selectAll("circle")返回一个空的选择器, 它的父节点是svg.

2. 空的选择器绑定于数据data, 产生三个新的选择器分别代表Eneter, update 和 exit. 这三个选择器都是空的, 只有Enter为每个新的元素保留占位符.

3. selection.data返回update选择器, 当enter/exit均解绑于update的时候. selection.enter返回enter选择器.

4. 

 

 

 

 

 

 

 

Effective Python (Pythonic Thinking)

Effective Python (Pythonic Thinking)

  • Know the differences Between bytes,str and unicode

In Python 3, there are two types that represent sequences of characters: bytes and str. Instances of bytes contain raw 8-bit values. Instances of str contain Unicode characters. 

# to_str
def to_str(bytes_or_str):
    if isinstance(bytes_to_str, bytes):
        value = bytes_or_str.decode(''utf-8'')
    else:
        value = bytes_or_str
    return value    # Instance of str

# to_bytes
def to_bytes(bytes_or_str):
    if isinstance(bytes_to_str, str):
        value = bytes_to_str.encode(''utf-8'')
    else:
        value = bytes_to_str
    return value    # Instance of bytes

In Python 2, there are two types that represent sequences of characters: str andunicode. In contrast to Python 3, instances of str contain raw 8-bit values. Instances ofunicode contain Unicode characters. 

# to_unicode
def to_unicode(unicode_or_str):
    if isinstance(unicode_or_str, str):
        value = unicode_or_str.encode(''utf-8'')
    else:
        value = unicode_or_str
    return value    # Instance of unicode

# to_str
def to_str(unicode_or_str):
    if isinstance(unicode_or_str, unicode):
        value = unicode_or_str.decode(''utf-8'')
    else:
        value = unicode_or_str
    return value    # Instance of str

    如果你要读取/写入二进制数据至文件中,请使用”rb“或者”wb“:    

import os
with open(''/tmp/random.bin'', ''wb'') as f:
    f.write(os.urandom(10))


  • Use List Comprehensions Instead of map and filter (用列表解析代替map和filter)

a = [1, 2, 3, 4]
squares = [x ** 2 for x in a]
squares = map(lambda x: x ** 2, a)

even_squares = [x ** 2 for x in a if x % 2 == 0]
alt = map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, a))

# 对调字典的key与value
chile_ranks = {''ghost'': 1, ''habanero'': 2, ''cayenne'': 3}
rank_dict = {rank: name for name, rank in chile_ranks.items()}
chile_len_set = {len(name) for name in rank_dict.values()}


  • Consider Generator Expressions for Large Comprehensions(用生成器表达式代替大的列表解析)
value = [len(x) for x in open(''/tmp/my_file.txt'')]
print(value)

it = (len(x) for x in open(''/tmp/my_file.txt''))
print(next(it))

# 生成器表达式可以由另外一个生成器表达式构成
roots = ((x, x**0.5) for x in it)
print(next(roots))


  • Prefer enumerate Over range 
# 当迭代一个列表,同时想知道当前元素的索引(计数)时;使用enumerate而不是range
flavor_list = [''vanilla'', ''chocolate'', ''pecan'', ''strawberry'']

# use range
for i in range(len(flavor_list)):
    print(''%d: %s'' % (i, flavor_list[i]))
# use enumerate
for i, flavor in enumerate(flavor_list):    # enumerate(flavor_list, 1)可为enumerate指定开始计数值
    print(''%d: %s'' % (i, flavor))


  • Use zip to Process Iterators in Parallel 
# 使用zip并行处理迭代器
names = [''Cecilia'', ''Lise'', ''Marie'']
letters = [len(n) for n in names]

max_letters = 0
for name, count in zip(names, letters):
    if count > max_letters:
        longest_name = name
        max_letters = count

# 注意:在Python3中zip是一个元组生成器;在Python2中zip是一个由元组组成的列表。


  • Avoid else Blocks After for and while Loops 
# 避免在for与while循环之后使用else
# 1,在没有break的for/while循环结束后,会马上执行else中的语句
# 2,避免在循环之后使用else,因为else不确定是否执行
for i in in range(5):
    print i
else:
    print ''else run''
    
for i in range(5):
    break
else:
    print ''else not run''


  • Take Advantage of Each Block in try/except/else/finally
# 使用finally 去可靠的关机文件句柄、socket等
handle = open(''/tmp/random_data.txt'')    # May raise IOError
try:
    data = handle.read()    # May raise UnicodeDecodeError
finally:
    try:
        handle.close()    # Always runs after try
    except Exception:
        pass

# 使用else 减少try block里面的代码量、提高可读性
# 如:从字符串中加载一个json dict并返回某个key的value
def load_json_key(data, key):
    try:
        result_dict = json.loads(data)    # May raise ValueError
    except ValueError as e:
        raise KeyError from e
    else: 
        return result_dict[key]    # May raise KeyError

# 
UNDEFINED = object()

def divide_json(path):
    handle = open(path, ''r+'')    # May raise IOError
    try:
        data = handle.read()    # May raise UnicodeDecodeError
        op = json.loads(data)    # May raise ValueError
        value = (op[''numerator''] / op[''denominator''])    # May raise ZeroDivisonError
    except ZeroDivisionError as e:
        return UNDEFINED
    else:
        op[''result''] = value
        result = json.dumps(op)
        handle.seek(0)
        handle.write(result)    # May raise IOError
        return value
    finally:
        try:
            handle.close()    # Always runs
        except Exception:
            pass








iOS Swift 应用程序随机 EXC_BAD_ACCESS 崩溃:swift_bridgeObjectRetain swift_retain swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1>

iOS Swift 应用程序随机 EXC_BAD_ACCESS 崩溃:swift_bridgeObjectRetain swift_retain swift::RefCounts

如何解决iOS Swift 应用程序随机 EXC_BAD_ACCESS 崩溃:swift_bridgeObjectRetain swift_retain swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1>

我不断收到来自随机用户的随机崩溃报告。不幸的是,我无法定期重现这一点。用户说崩溃是在 discussionViewController 中随机发生的。所有崩溃报告都有类似的内容:

0   libswiftCore.dylib              0x00000001a53face4 swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::incrementSlow(swift::RefCountBitsT<(swift::RefCountInlinedness)1>,unsigned int) + 60 (atomic:1003)
1   libswiftCore.dylib              0x00000001a53c59e0 swift_retain + 124 (RefCount.h:813)
2   libswiftCore.dylib              0x00000001a5401d60 swift_bridgeObjectRetain + 56 (SwiftObject.mm:585)
3   APPNAME                             0x0000000102b59734 closure #1 in discussionViewController.fetchPostData() + 7916

这是完整的崩溃日志和崩溃的线程:

Hardware Model:      iphone11,6
Process:             APPNAME [11770]
Path:                /private/var/containers/Bundle/Application/.../APPNAME.app/APPNAME
Identifier:          ----
Version:             62 (62)
AppStoretools:       12E262
AppVariant:          1:iphone11,6:13
Code Type:           ARM-64 (Native)
Role:                Foreground
Parent Process:      launchd [1]
Coalition:           ---- [1824]


Date/Time:           2021-06-17 12:07:01.4346 +1000
Launch Time:         2021-06-17 12:06:56.4993 +1000
OS Version:          iPhone OS 14.6 (18F72)
Release Type:        User
Baseband Version:    3.04.01
Report Version:      104

Exception Type:  EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x8000000000000010 -> 0x0000000000000010 (possible pointer authentication failure)
VM Region Info: 0x10 is not in any region.  Bytes before following region: 4339515376
      REGION TYPE                 START - END      [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->  
      __TEXT                   102a7c000-102a94000 [   96K] r-x/r-x SM=COW  ...APPNAME.app/APPNAME

Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL,Code 0xb
Terminating Process: exc handler [11770]
Triggered by Thread:  3


Thread 3 name:
Thread 3 Crashed:
0   libswiftCore.dylib              0x00000001a53face4 swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::incrementSlow(swift::RefCountBitsT<(swift::RefCountInlinedness)1>,unsigned int) + 60 (atomic:1003)
1   libswiftCore.dylib              0x00000001a53c59e0 swift_retain + 124 (RefCount.h:813)
2   libswiftCore.dylib              0x00000001a5401d60 swift_bridgeObjectRetain + 56 (SwiftObject.mm:585)
3   APPNAME                             0x0000000102b59734 closure #1 in discussionViewController.fetchPostData() + 7916
4   APPNAME                             0x0000000102ad09d4 thunk for @escaping @callee_guaranteed (@guaranteed Data?,@guaranteed NSURLResponse?,@guaranteed Error?) -> () + 132 (<compiler-generated>:0)
5   CFNetwork                       0x00000001a1b0a3dc __40-[__NSURLSessionLocal taskForClassInfo:]_block_invoke + 540 (LocalSession.mm:687)
6   CFNetwork                       0x00000001a1b1c768 __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 244 (LocalSessionTask.mm:584)
7   libdispatch.dylib               0x00000001a10d1a84 _dispatch_call_block_and_release + 32 (init.c:1466)
8   libdispatch.dylib               0x00000001a10d381c _dispatch_client_callout + 20 (object.m:559)
9   libdispatch.dylib               0x00000001a10db004 _dispatch_lane_serial_drain + 620 (inline_internal.h:2557)
10  libdispatch.dylib               0x00000001a10dbc34 _dispatch_lane_invoke + 456 (queue.c:3862)
11  libdispatch.dylib               0x00000001a10e64bc _dispatch_workloop_worker_thread + 764 (queue.c:6589)
12  libsystem_pthread.dylib         0x00000001ed04a7a4 0x1ed047000 + 14244
13  libsystem_pthread.dylib         0x00000001ed05174c 0x1ed047000 + 42828

我已验证 discussionViewController.fetchPostData() 不会强制解开任何可选选项,没有 try! 并且在任何地方都使用 [weak self]self?。该函数非常大,所以我很难缩小崩溃发生的范围。

java 线程 原子类相关操作示例 thinking in java4 目录21.3.4

java 线程 原子类相关操作示例 thinking in java4 目录21.3.4

java 线程  原子类相关操作示例

package org.rui.thread.volatiles;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * 原子类,
 * java SE5引入了诸如AtomicInteger AtomicLong AtomicReference
 * 等特殊的原子性变量类,它们提供下面形式的原子性条件更新操作:
 * 
 * boolean compareAndSet(expectedValue,updateValue);
 * 
 * 这些类被调整为可以使用在某些现代处理器上的可获得的,并且是在机器级别上的原子性,
 * 因此在使用它们时,通常不需要担心。对于常规编程来说,它们很少会派上用场,但是在涉级性能调优时,
 * 它们就大有用武之地了,例如,我们可以使用AtomicInteger来重写AtomictyTest.java
 * @author lenovo
 *
 */
public class AtomicIntegerTest implements Runnable {
/**
 * 这里我们通过使用AtomicInteger而消除了synchronized关键字。
 * 因为这个程序不会失败,所以添加了一个timer,以便在5秒钟之后自动地终止
 */
	private AtomicInteger i=new AtomicInteger(0);
	public int getValue(){return i.get();}
	private void evenIncrement(){i.addAndGet(2);}
	@Override
	public void run() 
	{
		while(true)
		{
			evenIncrement();
		}
	}

	public static void main(String[] args) 
	{
		//订时器
		new Timer().schedule(new TimerTask() 
		{
			@Override
			public void run() 
			{
				System.err.println("Aborting");
				System.exit(0);
			}
		}, 5000);
		//线程池
		ExecutorService exec=Executors.newCachedThreadPool();
		AtomicIntegerTest at=new AtomicIntegerTest();
		exec.execute(at);
		while(true)
		{
			int val=at.getValue();
			if(val%2!=0)
			{
				System.out.println(val);
				System.exit(0);
			}
		}

	}
}
/**
 * output:
 * Aborting
 */

package org.rui.thread.volatiles;

import java.util.concurrent.atomic.AtomicInteger;

import org.rui.thread.res.EvenChecker;
import org.rui.thread.res.IntGenerator;
/**
 * 下面是用AtomicInteger重写MutexEvenGenerator.java:
 * 所有其他形式的同步再次通过使用AtomicInteger得到了根除
 * 
 * 
 * 
 * 应该强调的是,atomic类被设计用来构建java.util.concureent中的类,
 * 因此只有在特殊情况下才在自己的代码中使用它们,即便使用了也需要确保不存在其他可能出现的问题。
 * 通常依赖于锁要更安全一些(要么是synchronized关键字,要么是显式的lock对象)
 * @author lenovo
 *
 */
public class AtomicEvenGenerator extends IntGenerator{

	private AtomicInteger currentEvenValue=new AtomicInteger(0);
	
	@Override
	public int next() {
		return currentEvenValue.addAndGet(2);
	}
	public static void main(String[] args) {
		EvenChecker.test(new AtomicEvenGenerator());
	}

}


关于thinking in Swift:重新审视装饰器模式重试装饰器的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于d3.js学习笔记--Mike Bostock: Thinking with Joins、Effective Python (Pythonic Thinking)、iOS Swift 应用程序随机 EXC_BAD_ACCESS 崩溃:swift_bridgeObjectRetain swift_retain swift::RefCounts、java 线程 原子类相关操作示例 thinking in java4 目录21.3.4的相关知识,请在本站寻找。

本文标签: